Allow update entities to report progress as a float (#128930)

* Allow update entities to report progress as a float

* Add test

* Update snapshots

* Update recorder test

* Use _attr_* in MockUpdateEntity
This commit is contained in:
Erik Montnemery 2024-10-24 21:20:18 +02:00 committed by GitHub
parent 87a2465a25
commit bd55fe868d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 76 additions and 51 deletions

View File

@ -27,6 +27,7 @@ from homeassistant.util.hass_dict import HassKey
from .const import ( from .const import (
ATTR_AUTO_UPDATE, ATTR_AUTO_UPDATE,
ATTR_BACKUP, ATTR_BACKUP,
ATTR_DISPLAY_PRECISION,
ATTR_IN_PROGRESS, ATTR_IN_PROGRESS,
ATTR_INSTALLED_VERSION, ATTR_INSTALLED_VERSION,
ATTR_LATEST_VERSION, ATTR_LATEST_VERSION,
@ -178,6 +179,7 @@ class UpdateEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes update entities.""" """A class that describes update entities."""
device_class: UpdateDeviceClass | None = None device_class: UpdateDeviceClass | None = None
display_precision: int = 0
entity_category: EntityCategory | None = EntityCategory.CONFIG entity_category: EntityCategory | None = EntityCategory.CONFIG
@ -191,6 +193,7 @@ CACHED_PROPERTIES_WITH_ATTR_ = {
"auto_update", "auto_update",
"installed_version", "installed_version",
"device_class", "device_class",
"display_precision",
"in_progress", "in_progress",
"latest_version", "latest_version",
"release_summary", "release_summary",
@ -210,6 +213,7 @@ class UpdateEntity(
_entity_component_unrecorded_attributes = frozenset( _entity_component_unrecorded_attributes = frozenset(
{ {
ATTR_DISPLAY_PRECISION,
ATTR_ENTITY_PICTURE, ATTR_ENTITY_PICTURE,
ATTR_IN_PROGRESS, ATTR_IN_PROGRESS,
ATTR_RELEASE_SUMMARY, ATTR_RELEASE_SUMMARY,
@ -221,6 +225,7 @@ class UpdateEntity(
_attr_auto_update: bool = False _attr_auto_update: bool = False
_attr_installed_version: str | None = None _attr_installed_version: str | None = None
_attr_device_class: UpdateDeviceClass | None _attr_device_class: UpdateDeviceClass | None
_attr_display_precision: int
_attr_in_progress: bool | int = False _attr_in_progress: bool | int = False
_attr_latest_version: str | None = None _attr_latest_version: str | None = None
_attr_release_summary: str | None = None _attr_release_summary: str | None = None
@ -228,7 +233,7 @@ class UpdateEntity(
_attr_state: None = None _attr_state: None = None
_attr_supported_features: UpdateEntityFeature = UpdateEntityFeature(0) _attr_supported_features: UpdateEntityFeature = UpdateEntityFeature(0)
_attr_title: str | None = None _attr_title: str | None = None
_attr_update_percentage: int | None = None _attr_update_percentage: int | float | None = None
__skipped_version: str | None = None __skipped_version: str | None = None
__in_progress: bool = False __in_progress: bool = False
@ -258,6 +263,15 @@ class UpdateEntity(
return self.entity_description.device_class return self.entity_description.device_class
return None return None
@cached_property
def display_precision(self) -> int:
"""Return number of decimal digits for display of update progress."""
if hasattr(self, "_attr_display_precision"):
return self._attr_display_precision
if hasattr(self, "entity_description"):
return self.entity_description.display_precision
return 0
@property @property
def entity_category(self) -> EntityCategory | None: def entity_category(self) -> EntityCategory | None:
"""Return the category of the entity, if any.""" """Return the category of the entity, if any."""
@ -337,12 +351,12 @@ class UpdateEntity(
return features return features
@cached_property @cached_property
def update_percentage(self) -> int | None: def update_percentage(self) -> int | float | None:
"""Update installation progress. """Update installation progress.
Needs UpdateEntityFeature.PROGRESS flag to be set for it to be used. Needs UpdateEntityFeature.PROGRESS flag to be set for it to be used.
Can either return an integer to indicate the progress from 0 to 100% or None. Can either return a number to indicate the progress from 0 to 100% or None.
""" """
return self._attr_update_percentage return self._attr_update_percentage
@ -460,6 +474,7 @@ class UpdateEntity(
return { return {
ATTR_AUTO_UPDATE: self.auto_update, ATTR_AUTO_UPDATE: self.auto_update,
ATTR_DISPLAY_PRECISION: self.display_precision,
ATTR_INSTALLED_VERSION: installed_version, ATTR_INSTALLED_VERSION: installed_version,
ATTR_IN_PROGRESS: in_progress, ATTR_IN_PROGRESS: in_progress,
ATTR_LATEST_VERSION: latest_version, ATTR_LATEST_VERSION: latest_version,

View File

@ -23,6 +23,7 @@ SERVICE_SKIP: Final = "skip"
ATTR_AUTO_UPDATE: Final = "auto_update" ATTR_AUTO_UPDATE: Final = "auto_update"
ATTR_BACKUP: Final = "backup" ATTR_BACKUP: Final = "backup"
ATTR_DISPLAY_PRECISION: Final = "display_precision"
ATTR_INSTALLED_VERSION: Final = "installed_version" ATTR_INSTALLED_VERSION: Final = "installed_version"
ATTR_IN_PROGRESS: Final = "in_progress" ATTR_IN_PROGRESS: Final = "in_progress"
ATTR_LATEST_VERSION: Final = "latest_version" ATTR_LATEST_VERSION: Final = "latest_version"

View File

@ -37,6 +37,7 @@
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'device_class': 'firmware', 'device_class': 'firmware',
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/airgradient/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/airgradient/icon.png',
'friendly_name': 'Airgradient Firmware', 'friendly_name': 'Airgradient Firmware',
'in_progress': False, 'in_progress': False,

View File

@ -4,6 +4,7 @@
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'device_class': 'firmware', 'device_class': 'firmware',
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/devolo_home_network/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/devolo_home_network/icon.png',
'friendly_name': 'Mock Title Firmware', 'friendly_name': 'Mock Title Firmware',
'in_progress': False, 'in_progress': False,

View File

@ -36,6 +36,7 @@
StateSnapshot({ StateSnapshot({
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/fritz/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/fritz/icon.png',
'friendly_name': 'Mock Title FRITZ!OS', 'friendly_name': 'Mock Title FRITZ!OS',
'in_progress': False, 'in_progress': False,
@ -93,6 +94,7 @@
StateSnapshot({ StateSnapshot({
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/fritz/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/fritz/icon.png',
'friendly_name': 'Mock Title FRITZ!OS', 'friendly_name': 'Mock Title FRITZ!OS',
'in_progress': False, 'in_progress': False,
@ -150,6 +152,7 @@
StateSnapshot({ StateSnapshot({
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/fritz/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/fritz/icon.png',
'friendly_name': 'Mock Title FRITZ!OS', 'friendly_name': 'Mock Title FRITZ!OS',
'in_progress': False, 'in_progress': False,

View File

@ -40,6 +40,7 @@
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'device_class': 'firmware', 'device_class': 'firmware',
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/iron_os/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/iron_os/icon.png',
'friendly_name': 'Pinecil Firmware', 'friendly_name': 'Pinecil Firmware',
'in_progress': False, 'in_progress': False,

View File

@ -4,6 +4,7 @@
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'device_class': 'firmware', 'device_class': 'firmware',
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/lamarzocco/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/lamarzocco/icon.png',
'friendly_name': 'GS01234 Gateway firmware', 'friendly_name': 'GS01234 Gateway firmware',
'in_progress': False, 'in_progress': False,
@ -62,6 +63,7 @@
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'device_class': 'firmware', 'device_class': 'firmware',
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/lamarzocco/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/lamarzocco/icon.png',
'friendly_name': 'GS01234 Machine firmware', 'friendly_name': 'GS01234 Machine firmware',
'in_progress': False, 'in_progress': False,

View File

@ -36,6 +36,7 @@
StateSnapshot({ StateSnapshot({
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/nextcloud/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/nextcloud/icon.png',
'friendly_name': 'my.nc_url.local None', 'friendly_name': 'my.nc_url.local None',
'in_progress': False, 'in_progress': False,

View File

@ -37,6 +37,7 @@
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'device_class': 'firmware', 'device_class': 'firmware',
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/smlight/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/smlight/icon.png',
'friendly_name': 'Mock Title Core firmware', 'friendly_name': 'Mock Title Core firmware',
'in_progress': False, 'in_progress': False,
@ -95,6 +96,7 @@
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'device_class': 'firmware', 'device_class': 'firmware',
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/smlight/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/smlight/icon.png',
'friendly_name': 'Mock Title Zigbee firmware', 'friendly_name': 'Mock Title Zigbee firmware',
'in_progress': False, 'in_progress': False,

View File

@ -36,6 +36,7 @@
StateSnapshot({ StateSnapshot({
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/teslemetry/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/teslemetry/icon.png',
'friendly_name': 'Test Update', 'friendly_name': 'Test Update',
'in_progress': False, 'in_progress': False,
@ -93,6 +94,7 @@
StateSnapshot({ StateSnapshot({
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/teslemetry/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/teslemetry/icon.png',
'friendly_name': 'Test Update', 'friendly_name': 'Test Update',
'in_progress': False, 'in_progress': False,

View File

@ -36,6 +36,7 @@
StateSnapshot({ StateSnapshot({
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/tessie/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/tessie/icon.png',
'friendly_name': 'Test Update', 'friendly_name': 'Test Update',
'in_progress': False, 'in_progress': False,

View File

@ -37,6 +37,7 @@
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'device_class': 'firmware', 'device_class': 'firmware',
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/unifi/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/unifi/icon.png',
'friendly_name': 'Device 1', 'friendly_name': 'Device 1',
'in_progress': False, 'in_progress': False,
@ -95,6 +96,7 @@
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'device_class': 'firmware', 'device_class': 'firmware',
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/unifi/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/unifi/icon.png',
'friendly_name': 'Device 2', 'friendly_name': 'Device 2',
'in_progress': False, 'in_progress': False,
@ -153,6 +155,7 @@
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'device_class': 'firmware', 'device_class': 'firmware',
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/unifi/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/unifi/icon.png',
'friendly_name': 'Device 1', 'friendly_name': 'Device 1',
'in_progress': False, 'in_progress': False,
@ -211,6 +214,7 @@
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'auto_update': False, 'auto_update': False,
'device_class': 'firmware', 'device_class': 'firmware',
'display_precision': 0,
'entity_picture': 'https://brands.home-assistant.io/_/unifi/icon.png', 'entity_picture': 'https://brands.home-assistant.io/_/unifi/icon.png',
'friendly_name': 'Device 2', 'friendly_name': 'Device 2',
'in_progress': False, 'in_progress': False,

View File

@ -5,53 +5,16 @@ from typing import Any
from homeassistant.components.update import UpdateEntity from homeassistant.components.update import UpdateEntity
from tests.common import MockEntity
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
class MockUpdateEntity(MockEntity, UpdateEntity): class MockUpdateEntity(UpdateEntity):
"""Mock UpdateEntity class.""" """Mock UpdateEntity class."""
@property def __init__(self, **values: Any) -> None:
def auto_update(self) -> bool: """Initialize an entity."""
"""Indicate if the device or service has auto update enabled.""" for key, val in values.items():
return self._handle("auto_update") setattr(self, f"_attr_{key}", val)
@property
def installed_version(self) -> str | None:
"""Version currently installed and in use."""
return self._handle("installed_version")
@property
def in_progress(self) -> bool | int | None:
"""Update installation progress."""
return self._handle("in_progress")
@property
def latest_version(self) -> str | None:
"""Latest version available for install."""
return self._handle("latest_version")
@property
def release_summary(self) -> str | None:
"""Summary of the release notes or changelog."""
return self._handle("release_summary")
@property
def release_url(self) -> str | None:
"""URL to the full release notes of the latest version available."""
return self._handle("release_url")
@property
def title(self) -> str | None:
"""Title of the software."""
return self._handle("title")
@property
def update_percentage(self) -> int | None:
"""Update installation progress."""
return self._handle("update_percentage")
def install(self, version: str | None, backup: bool, **kwargs: Any) -> None: def install(self, version: str | None, backup: bool, **kwargs: Any) -> None:
"""Install an update.""" """Install an update."""
@ -59,10 +22,10 @@ class MockUpdateEntity(MockEntity, UpdateEntity):
_LOGGER.info("Creating backup before installing update") _LOGGER.info("Creating backup before installing update")
if version is not None: if version is not None:
self._values["installed_version"] = version self._attr_installed_version = version
_LOGGER.info("Installed update with version: %s", version) _LOGGER.info("Installed update with version: %s", version)
else: else:
self._values["installed_version"] = self.latest_version self._attr_installed_version = self.latest_version
_LOGGER.info("Installed latest update") _LOGGER.info("Installed latest update")
def release_notes(self) -> str | None: def release_notes(self) -> str | None:

View File

@ -51,7 +51,7 @@ def mock_update_entities() -> list[MockUpdateEntity]:
), ),
MockUpdateEntity( MockUpdateEntity(
name="Update Already in Progress", name="Update Already in Progress",
unique_id="update_already_in_progres", unique_id="update_already_in_progress",
installed_version="1.0.0", installed_version="1.0.0",
latest_version="1.0.1", latest_version="1.0.1",
in_progress=True, in_progress=True,
@ -59,6 +59,17 @@ def mock_update_entities() -> list[MockUpdateEntity]:
| UpdateEntityFeature.PROGRESS, | UpdateEntityFeature.PROGRESS,
update_percentage=50, update_percentage=50,
), ),
MockUpdateEntity(
name="Update Already in Progress Float",
unique_id="update_already_in_progress_float",
installed_version="1.0.0",
latest_version="1.0.1",
in_progress=True,
supported_features=UpdateEntityFeature.INSTALL
| UpdateEntityFeature.PROGRESS,
update_percentage=0.25,
display_precision=2,
),
MockUpdateEntity( MockUpdateEntity(
name="Update No Install", name="Update No Install",
unique_id="no_install", unique_id="no_install",

View File

@ -18,6 +18,7 @@ from homeassistant.components.update import (
) )
from homeassistant.components.update.const import ( from homeassistant.components.update.const import (
ATTR_AUTO_UPDATE, ATTR_AUTO_UPDATE,
ATTR_DISPLAY_PRECISION,
ATTR_IN_PROGRESS, ATTR_IN_PROGRESS,
ATTR_INSTALLED_VERSION, ATTR_INSTALLED_VERSION,
ATTR_LATEST_VERSION, ATTR_LATEST_VERSION,
@ -92,6 +93,7 @@ async def test_update(hass: HomeAssistant) -> None:
assert update.state == STATE_ON assert update.state == STATE_ON
assert update.state_attributes == { assert update.state_attributes == {
ATTR_AUTO_UPDATE: False, ATTR_AUTO_UPDATE: False,
ATTR_DISPLAY_PRECISION: 0,
ATTR_INSTALLED_VERSION: "1.0.0", ATTR_INSTALLED_VERSION: "1.0.0",
ATTR_IN_PROGRESS: False, ATTR_IN_PROGRESS: False,
ATTR_LATEST_VERSION: "1.0.1", ATTR_LATEST_VERSION: "1.0.1",
@ -546,10 +548,20 @@ async def test_entity_with_backup_support(
assert "Installed update with version: 0.9.8" in caplog.text assert "Installed update with version: 0.9.8" in caplog.text
@pytest.mark.parametrize(
("entity_id", "expected_display_precision", "expected_update_percentage"),
[
("update.update_already_in_progress", 0, 50),
("update.update_already_in_progress_float", 2, 0.25),
],
)
async def test_entity_already_in_progress( async def test_entity_already_in_progress(
hass: HomeAssistant, hass: HomeAssistant,
mock_update_entities: list[MockUpdateEntity], mock_update_entities: list[MockUpdateEntity],
caplog: pytest.LogCaptureFixture, caplog: pytest.LogCaptureFixture,
entity_id: str,
expected_display_precision: int,
expected_update_percentage: float,
) -> None: ) -> None:
"""Test update install already in progress.""" """Test update install already in progress."""
setup_test_component_platform(hass, DOMAIN, mock_update_entities) setup_test_component_platform(hass, DOMAIN, mock_update_entities)
@ -557,13 +569,14 @@ async def test_entity_already_in_progress(
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get("update.update_already_in_progress") state = hass.states.get(entity_id)
assert state assert state
assert state.state == STATE_ON assert state.state == STATE_ON
assert state.attributes[ATTR_DISPLAY_PRECISION] == expected_display_precision
assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0" assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0"
assert state.attributes[ATTR_LATEST_VERSION] == "1.0.1" assert state.attributes[ATTR_LATEST_VERSION] == "1.0.1"
assert state.attributes[ATTR_IN_PROGRESS] is True assert state.attributes[ATTR_IN_PROGRESS] is True
assert state.attributes[ATTR_UPDATE_PERCENTAGE] == 50 assert state.attributes[ATTR_UPDATE_PERCENTAGE] == expected_update_percentage
with pytest.raises( with pytest.raises(
HomeAssistantError, HomeAssistantError,
@ -572,7 +585,7 @@ async def test_entity_already_in_progress(
await hass.services.async_call( await hass.services.async_call(
DOMAIN, DOMAIN,
SERVICE_INSTALL, SERVICE_INSTALL,
{ATTR_ENTITY_ID: "update.update_already_in_progress"}, {ATTR_ENTITY_ID: entity_id},
blocking=True, blocking=True,
) )
@ -1056,6 +1069,7 @@ async def test_update_percentage_backwards_compatibility(
expected_attributes = { expected_attributes = {
ATTR_AUTO_UPDATE: False, ATTR_AUTO_UPDATE: False,
ATTR_DISPLAY_PRECISION: 0,
ATTR_ENTITY_PICTURE: "https://brands.home-assistant.io/_/test/icon.png", ATTR_ENTITY_PICTURE: "https://brands.home-assistant.io/_/test/icon.png",
ATTR_FRIENDLY_NAME: "legacy", ATTR_FRIENDLY_NAME: "legacy",
ATTR_INSTALLED_VERSION: "1.0.0", ATTR_INSTALLED_VERSION: "1.0.0",

View File

@ -7,6 +7,7 @@ from datetime import timedelta
from homeassistant.components.recorder import Recorder from homeassistant.components.recorder import Recorder
from homeassistant.components.recorder.history import get_significant_states from homeassistant.components.recorder.history import get_significant_states
from homeassistant.components.update.const import ( from homeassistant.components.update.const import (
ATTR_DISPLAY_PRECISION,
ATTR_IN_PROGRESS, ATTR_IN_PROGRESS,
ATTR_INSTALLED_VERSION, ATTR_INSTALLED_VERSION,
ATTR_RELEASE_SUMMARY, ATTR_RELEASE_SUMMARY,
@ -35,6 +36,7 @@ async def test_exclude_attributes(
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get("update.update_already_in_progress") state = hass.states.get("update.update_already_in_progress")
assert state.attributes[ATTR_DISPLAY_PRECISION] == 0
assert state.attributes[ATTR_IN_PROGRESS] is True assert state.attributes[ATTR_IN_PROGRESS] is True
assert state.attributes[ATTR_UPDATE_PERCENTAGE] == 50 assert state.attributes[ATTR_UPDATE_PERCENTAGE] == 50
assert ( assert (
@ -54,6 +56,7 @@ async def test_exclude_attributes(
assert len(states) >= 1 assert len(states) >= 1
for entity_states in states.values(): for entity_states in states.values():
for state in entity_states: for state in entity_states:
assert ATTR_DISPLAY_PRECISION not in state.attributes
assert ATTR_ENTITY_PICTURE not in state.attributes assert ATTR_ENTITY_PICTURE not in state.attributes
assert ATTR_IN_PROGRESS not in state.attributes assert ATTR_IN_PROGRESS not in state.attributes
assert ATTR_RELEASE_SUMMARY not in state.attributes assert ATTR_RELEASE_SUMMARY not in state.attributes