Add update_percentage state attribute to update entity (#128877)

* Add update_percentage state attribute to update entity

* Update tests

* Update tests
This commit is contained in:
Erik Montnemery 2024-10-21 15:31:48 +02:00 committed by GitHub
parent f8f87ec091
commit e861cab727
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 232 additions and 41 deletions

View File

@ -34,6 +34,7 @@ from .const import (
ATTR_RELEASE_URL,
ATTR_SKIPPED_VERSION,
ATTR_TITLE,
ATTR_UPDATE_PERCENTAGE,
ATTR_VERSION,
DOMAIN,
SERVICE_INSTALL,
@ -207,7 +208,12 @@ class UpdateEntity(
"""Representation of an update entity."""
_entity_component_unrecorded_attributes = frozenset(
{ATTR_ENTITY_PICTURE, ATTR_IN_PROGRESS, ATTR_RELEASE_SUMMARY}
{
ATTR_ENTITY_PICTURE,
ATTR_IN_PROGRESS,
ATTR_RELEASE_SUMMARY,
ATTR_UPDATE_PERCENTAGE,
}
)
entity_description: UpdateEntityDescription
@ -418,12 +424,17 @@ class UpdateEntity(
if (release_summary := self.release_summary) is not None:
release_summary = release_summary[:255]
update_percentage = None
# If entity supports progress, return the in_progress value.
# Otherwise, we use the internal progress value.
if UpdateEntityFeature.PROGRESS in self.supported_features_compat:
in_progress = self.in_progress
else:
in_progress = self.__in_progress
if type(in_progress) is not bool and isinstance(in_progress, int):
update_percentage = in_progress
in_progress = True
installed_version = self.installed_version
latest_version = self.latest_version
@ -445,6 +456,7 @@ class UpdateEntity(
ATTR_RELEASE_URL: self.release_url,
ATTR_SKIPPED_VERSION: skipped_version,
ATTR_TITLE: self.title,
ATTR_UPDATE_PERCENTAGE: update_percentage,
}
@final

View File

@ -30,4 +30,5 @@ ATTR_RELEASE_SUMMARY: Final = "release_summary"
ATTR_RELEASE_URL: Final = "release_url"
ATTR_SKIPPED_VERSION: Final = "skipped_version"
ATTR_TITLE: Final = "title"
ATTR_UPDATE_PERCENTAGE: Final = "update_percentage"
ATTR_VERSION: Final = "version"

View File

@ -47,6 +47,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 0>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.airgradient_firmware',

View File

@ -11,6 +11,7 @@ from homeassistant.components.update import (
ATTR_RELEASE_SUMMARY,
ATTR_RELEASE_URL,
ATTR_TITLE,
ATTR_UPDATE_PERCENTAGE,
DOMAIN as UPDATE_DOMAIN,
SERVICE_INSTALL,
UpdateDeviceClass,
@ -131,6 +132,7 @@ async def test_update_with_progress(hass: HomeAssistant) -> None:
assert state
assert state.state == STATE_ON
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
events = []
async_track_state_change_event(
@ -148,19 +150,31 @@ async def test_update_with_progress(hass: HomeAssistant) -> None:
blocking=True,
)
assert len(events) == 10
assert len(events) == 11
assert events[0].data["new_state"].state == STATE_ON
assert events[0].data["new_state"].attributes[ATTR_IN_PROGRESS] == 10
assert events[1].data["new_state"].attributes[ATTR_IN_PROGRESS] == 20
assert events[2].data["new_state"].attributes[ATTR_IN_PROGRESS] == 30
assert events[3].data["new_state"].attributes[ATTR_IN_PROGRESS] == 40
assert events[4].data["new_state"].attributes[ATTR_IN_PROGRESS] == 50
assert events[5].data["new_state"].attributes[ATTR_IN_PROGRESS] == 60
assert events[6].data["new_state"].attributes[ATTR_IN_PROGRESS] == 70
assert events[7].data["new_state"].attributes[ATTR_IN_PROGRESS] == 80
assert events[8].data["new_state"].attributes[ATTR_IN_PROGRESS] == 90
assert events[9].data["new_state"].attributes[ATTR_IN_PROGRESS] is False
assert events[9].data["new_state"].state == STATE_OFF
assert events[0].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[0].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 0
assert events[1].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[1].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 10
assert events[2].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[2].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 20
assert events[3].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[3].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 30
assert events[4].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[4].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 40
assert events[5].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[5].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 50
assert events[6].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[6].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 60
assert events[7].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[7].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 70
assert events[8].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[8].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 80
assert events[9].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[9].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 90
assert events[10].data["new_state"].attributes[ATTR_IN_PROGRESS] is False
assert events[10].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] is None
assert events[10].data["new_state"].state == STATE_OFF
async def test_update_with_progress_raising(hass: HomeAssistant) -> None:
@ -169,6 +183,7 @@ async def test_update_with_progress_raising(hass: HomeAssistant) -> None:
assert state
assert state.state == STATE_ON
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
events = []
async_track_state_change_event(
@ -194,11 +209,18 @@ async def test_update_with_progress_raising(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
assert fake_sleep.call_count == 5
assert len(events) == 5
assert len(events) == 6
assert events[0].data["new_state"].state == STATE_ON
assert events[0].data["new_state"].attributes[ATTR_IN_PROGRESS] == 10
assert events[1].data["new_state"].attributes[ATTR_IN_PROGRESS] == 20
assert events[2].data["new_state"].attributes[ATTR_IN_PROGRESS] == 30
assert events[3].data["new_state"].attributes[ATTR_IN_PROGRESS] == 40
assert events[4].data["new_state"].attributes[ATTR_IN_PROGRESS] is False
assert events[4].data["new_state"].state == STATE_ON
assert events[0].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[0].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 0
assert events[1].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[1].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 10
assert events[2].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[2].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 20
assert events[3].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[3].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 30
assert events[4].data["new_state"].attributes[ATTR_IN_PROGRESS] is True
assert events[4].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] == 40
assert events[5].data["new_state"].attributes[ATTR_IN_PROGRESS] is False
assert events[5].data["new_state"].attributes[ATTR_UPDATE_PERCENTAGE] is None
assert events[5].data["new_state"].state == STATE_ON

View File

@ -14,6 +14,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 5>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.mock_title_firmware',

View File

@ -531,7 +531,8 @@ async def test_generic_device_update_entity_has_update(
state = hass.states.get("update.test_myupdate")
assert state is not None
assert state.state == STATE_ON
assert state.attributes["in_progress"] == 50
assert state.attributes["in_progress"] is True
assert state.attributes["update_percentage"] == 50
await hass.services.async_call(
HOMEASSISTANT_DOMAIN,

View File

@ -46,6 +46,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 1>,
'title': 'FRITZ!OS',
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.mock_title_fritz_os',
@ -102,6 +103,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 1>,
'title': 'FRITZ!OS',
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.mock_title_fritz_os',
@ -158,6 +160,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 1>,
'title': 'FRITZ!OS',
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.mock_title_fritz_os',

View File

@ -14,6 +14,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 1>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.gs01234_gateway_firmware',
@ -71,6 +72,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 1>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.gs01234_machine_firmware',

View File

@ -202,7 +202,8 @@ async def test_update_install(
state = hass.states.get("update.mock_dimmable_light")
assert state
assert state.state == STATE_ON
assert state.attributes.get("in_progress")
assert state.attributes["in_progress"] is True
assert state.attributes["update_percentage"] is None
set_node_attribute_typed(
matter_node,
@ -215,7 +216,8 @@ async def test_update_install(
state = hass.states.get("update.mock_dimmable_light")
assert state
assert state.state == STATE_ON
assert state.attributes.get("in_progress") == 50
assert state.attributes["in_progress"] is True
assert state.attributes["update_percentage"] == 50
set_node_attribute_typed(
matter_node,

View File

@ -46,6 +46,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 0>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.my_nc_url_local_none',

View File

@ -16,6 +16,7 @@ from homeassistant.components.update import (
ATTR_INSTALLED_VERSION,
ATTR_LATEST_VERSION,
ATTR_RELEASE_URL,
ATTR_UPDATE_PERCENTAGE,
DOMAIN as UPDATE_DOMAIN,
SERVICE_INSTALL,
UpdateEntityFeature,
@ -64,6 +65,7 @@ async def test_block_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0"
assert state.attributes[ATTR_LATEST_VERSION] == "2.0.0"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
supported_feat = state.attributes[ATTR_SUPPORTED_FEATURES]
assert supported_feat == UpdateEntityFeature.INSTALL | UpdateEntityFeature.PROGRESS
@ -80,6 +82,7 @@ async def test_block_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0"
assert state.attributes[ATTR_LATEST_VERSION] == "2.0.0"
assert state.attributes[ATTR_IN_PROGRESS] is True
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
assert state.attributes[ATTR_RELEASE_URL] == GEN1_RELEASE_URL
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "2.0.0")
@ -90,6 +93,7 @@ async def test_block_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "2.0.0"
assert state.attributes[ATTR_LATEST_VERSION] == "2.0.0"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
entry = entity_registry.async_get(entity_id)
assert entry
@ -117,6 +121,7 @@ async def test_block_beta_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0"
assert state.attributes[ATTR_LATEST_VERSION] == "1.0.0"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
monkeypatch.setitem(
mock_block_device.status["update"], "beta_version", "2.0.0-beta"
@ -128,6 +133,7 @@ async def test_block_beta_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0"
assert state.attributes[ATTR_LATEST_VERSION] == "2.0.0-beta"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
assert state.attributes[ATTR_RELEASE_URL] is None
await hass.services.async_call(
@ -143,6 +149,7 @@ async def test_block_beta_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0"
assert state.attributes[ATTR_LATEST_VERSION] == "2.0.0-beta"
assert state.attributes[ATTR_IN_PROGRESS] is True
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "2.0.0-beta")
await mock_rest_update(hass, freezer)
@ -152,6 +159,7 @@ async def test_block_beta_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "2.0.0-beta"
assert state.attributes[ATTR_LATEST_VERSION] == "2.0.0-beta"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
entry = entity_registry.async_get(entity_id)
assert entry
@ -292,6 +300,7 @@ async def test_rpc_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "1"
assert state.attributes[ATTR_LATEST_VERSION] == "2"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
supported_feat = state.attributes[ATTR_SUPPORTED_FEATURES]
assert supported_feat == UpdateEntityFeature.INSTALL | UpdateEntityFeature.PROGRESS
@ -309,6 +318,7 @@ async def test_rpc_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "1"
assert state.attributes[ATTR_LATEST_VERSION] == "2"
assert state.attributes[ATTR_IN_PROGRESS] is True
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
assert state.attributes[ATTR_RELEASE_URL] == GEN2_RELEASE_URL
inject_rpc_device_event(
@ -326,7 +336,9 @@ async def test_rpc_update(
},
)
assert hass.states.get(entity_id).attributes[ATTR_IN_PROGRESS] == 0
state = hass.states.get(entity_id)
assert state.attributes[ATTR_IN_PROGRESS] is True
assert state.attributes[ATTR_UPDATE_PERCENTAGE] == 0
inject_rpc_device_event(
monkeypatch,
@ -344,7 +356,9 @@ async def test_rpc_update(
},
)
assert hass.states.get(entity_id).attributes[ATTR_IN_PROGRESS] == 50
state = hass.states.get(entity_id)
assert state.attributes[ATTR_IN_PROGRESS] is True
assert state.attributes[ATTR_UPDATE_PERCENTAGE] == 50
inject_rpc_device_event(
monkeypatch,
@ -368,6 +382,7 @@ async def test_rpc_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "2"
assert state.attributes[ATTR_LATEST_VERSION] == "2"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
entry = entity_registry.async_get(entity_id)
assert entry
@ -406,6 +421,7 @@ async def test_rpc_sleeping_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "1"
assert state.attributes[ATTR_LATEST_VERSION] == "2"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
assert state.attributes[ATTR_SUPPORTED_FEATURES] == UpdateEntityFeature(0)
assert state.attributes[ATTR_RELEASE_URL] == GEN2_RELEASE_URL
@ -417,6 +433,7 @@ async def test_rpc_sleeping_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "2"
assert state.attributes[ATTR_LATEST_VERSION] == "2"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
assert state.attributes[ATTR_SUPPORTED_FEATURES] == UpdateEntityFeature(0)
entry = entity_registry.async_get(entity_id)
@ -456,6 +473,7 @@ async def test_rpc_restored_sleeping_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "1"
assert state.attributes[ATTR_LATEST_VERSION] == "2"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
assert state.attributes[ATTR_SUPPORTED_FEATURES] == UpdateEntityFeature(0)
# Make device online
@ -472,6 +490,7 @@ async def test_rpc_restored_sleeping_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "2"
assert state.attributes[ATTR_LATEST_VERSION] == "2"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
assert state.attributes[ATTR_SUPPORTED_FEATURES] == UpdateEntityFeature(0)
@ -522,6 +541,7 @@ async def test_rpc_restored_sleeping_update_no_last_state(
assert state.attributes[ATTR_INSTALLED_VERSION] == "1"
assert state.attributes[ATTR_LATEST_VERSION] == "2"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
assert state.attributes[ATTR_SUPPORTED_FEATURES] == UpdateEntityFeature(0)
@ -551,6 +571,7 @@ async def test_rpc_beta_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "1"
assert state.attributes[ATTR_LATEST_VERSION] == "1"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
assert state.attributes[ATTR_RELEASE_URL] is None
monkeypatch.setitem(
@ -568,6 +589,7 @@ async def test_rpc_beta_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "1"
assert state.attributes[ATTR_LATEST_VERSION] == "2b"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
await hass.services.async_call(
UPDATE_DOMAIN,
@ -596,7 +618,8 @@ async def test_rpc_beta_update(
assert state.state == STATE_ON
assert state.attributes[ATTR_INSTALLED_VERSION] == "1"
assert state.attributes[ATTR_LATEST_VERSION] == "2b"
assert state.attributes[ATTR_IN_PROGRESS] == 0
assert state.attributes[ATTR_IN_PROGRESS] is True
assert state.attributes[ATTR_UPDATE_PERCENTAGE] == 0
inject_rpc_device_event(
monkeypatch,
@ -614,7 +637,9 @@ async def test_rpc_beta_update(
},
)
assert hass.states.get(entity_id).attributes[ATTR_IN_PROGRESS] == 40
state = hass.states.get(entity_id)
assert state.attributes[ATTR_IN_PROGRESS] is True
assert state.attributes[ATTR_UPDATE_PERCENTAGE] == 40
inject_rpc_device_event(
monkeypatch,
@ -638,6 +663,7 @@ async def test_rpc_beta_update(
assert state.attributes[ATTR_INSTALLED_VERSION] == "2b"
assert state.attributes[ATTR_LATEST_VERSION] == "2b"
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
entry = entity_registry.async_get(entity_id)
assert entry

View File

@ -47,6 +47,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 21>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.mock_title_core_firmware',
@ -104,6 +105,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 21>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.mock_title_zigbee_firmware',

View File

@ -14,6 +14,7 @@ from homeassistant.components.update import (
ATTR_IN_PROGRESS,
ATTR_INSTALLED_VERSION,
ATTR_LATEST_VERSION,
ATTR_UPDATE_PERCENTAGE,
DOMAIN as PLATFORM,
SERVICE_INSTALL,
)
@ -114,7 +115,8 @@ async def test_update_firmware(
event_function(MOCK_FIRMWARE_PROGRESS)
state = hass.states.get(entity_id)
assert state.attributes[ATTR_IN_PROGRESS] == 50
assert state.attributes[ATTR_IN_PROGRESS] is True
assert state.attributes[ATTR_UPDATE_PERCENTAGE] == 50
event_function = get_mock_event_function(mock_smlight_client, SmEvents.FW_UPD_done)
@ -211,6 +213,7 @@ async def test_update_firmware_failed(
await _call_event_function(MOCK_FIRMWARE_FAIL)
state = hass.states.get(entity_id)
assert state.attributes[ATTR_IN_PROGRESS] is False
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
async def test_update_release_notes(

View File

@ -46,6 +46,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 5>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.test_update',
@ -102,6 +103,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 4>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.test_update',

View File

@ -46,6 +46,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 5>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.test_update',

View File

@ -47,6 +47,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 5>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.device_1',
@ -104,6 +105,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 5>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.device_2',
@ -161,6 +163,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 4>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.device_1',
@ -218,6 +221,7 @@
'skipped_version': None,
'supported_features': <UpdateEntityFeature: 4>,
'title': None,
'update_percentage': None,
}),
'context': <ANY>,
'entity_id': 'update.device_2',

View File

@ -25,11 +25,15 @@ from homeassistant.components.update.const import (
ATTR_RELEASE_URL,
ATTR_SKIPPED_VERSION,
ATTR_TITLE,
ATTR_UPDATE_PERCENTAGE,
UpdateEntityFeature,
)
from homeassistant.config_entries import ConfigEntry, ConfigFlow
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_ENTITY_PICTURE,
ATTR_FRIENDLY_NAME,
ATTR_SUPPORTED_FEATURES,
CONF_PLATFORM,
STATE_OFF,
STATE_ON,
@ -95,6 +99,7 @@ async def test_update(hass: HomeAssistant) -> None:
ATTR_RELEASE_URL: "https://example.com",
ATTR_SKIPPED_VERSION: None,
ATTR_TITLE: "Title",
ATTR_UPDATE_PERCENTAGE: None,
}
# Test no update available
@ -557,7 +562,8 @@ async def test_entity_already_in_progress(
assert state.state == STATE_ON
assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0"
assert state.attributes[ATTR_LATEST_VERSION] == "1.0.1"
assert state.attributes[ATTR_IN_PROGRESS] == 50
assert state.attributes[ATTR_IN_PROGRESS] is True
assert state.attributes[ATTR_UPDATE_PERCENTAGE] == 50
with pytest.raises(
HomeAssistantError,
@ -997,3 +1003,84 @@ async def test_custom_version_is_newer(hass: HomeAssistant) -> None:
assert update.installed_version == BETA
assert update.latest_version == STABLE
assert update.state == STATE_OFF
@pytest.mark.parametrize(
("supported_features", "extra_expected_attributes"),
[
(
0,
[
{},
{},
{},
{},
{},
{},
{},
],
),
(
UpdateEntityFeature.PROGRESS,
[
{ATTR_IN_PROGRESS: False},
{ATTR_IN_PROGRESS: False},
{ATTR_IN_PROGRESS: True, ATTR_UPDATE_PERCENTAGE: 0},
{ATTR_IN_PROGRESS: True},
{ATTR_IN_PROGRESS: True, ATTR_UPDATE_PERCENTAGE: 1},
{ATTR_IN_PROGRESS: True, ATTR_UPDATE_PERCENTAGE: 10},
{ATTR_IN_PROGRESS: True, ATTR_UPDATE_PERCENTAGE: 100},
],
),
],
)
async def test_update_percentage_backwards_compatibility(
hass: HomeAssistant,
supported_features: UpdateEntityFeature,
extra_expected_attributes: list[dict],
) -> None:
"""Test deriving update percentage from deprecated in_progress."""
update = MockUpdateEntity()
update._attr_installed_version = "1.0.0"
update._attr_latest_version = "1.0.1"
update._attr_name = "legacy"
update._attr_release_summary = "Summary"
update._attr_release_url = "https://example.com"
update._attr_supported_features = supported_features
update._attr_title = "Title"
setup_test_component_platform(hass, DOMAIN, [update])
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
await hass.async_block_till_done()
expected_attributes = {
ATTR_AUTO_UPDATE: False,
ATTR_ENTITY_PICTURE: "https://brands.home-assistant.io/_/test/icon.png",
ATTR_FRIENDLY_NAME: "legacy",
ATTR_INSTALLED_VERSION: "1.0.0",
ATTR_IN_PROGRESS: False,
ATTR_LATEST_VERSION: "1.0.1",
ATTR_RELEASE_SUMMARY: "Summary",
ATTR_RELEASE_URL: "https://example.com",
ATTR_SKIPPED_VERSION: None,
ATTR_SUPPORTED_FEATURES: supported_features,
ATTR_TITLE: "Title",
ATTR_UPDATE_PERCENTAGE: None,
}
state = hass.states.get("update.legacy")
assert state is not None
assert state.state == STATE_ON
assert state.attributes == expected_attributes | extra_expected_attributes[0]
in_progress_list = [False, 0, True, 1, 10, 100]
for i, in_progress in enumerate(in_progress_list):
update._attr_in_progress = in_progress
update.async_write_ha_state()
state = hass.states.get("update.legacy")
assert state.state == STATE_ON
assert (
state.attributes == expected_attributes | extra_expected_attributes[i + 1]
)

View File

@ -10,6 +10,7 @@ from homeassistant.components.update.const import (
ATTR_IN_PROGRESS,
ATTR_INSTALLED_VERSION,
ATTR_RELEASE_SUMMARY,
ATTR_UPDATE_PERCENTAGE,
DOMAIN,
)
from homeassistant.const import ATTR_ENTITY_PICTURE, CONF_PLATFORM
@ -34,7 +35,8 @@ async def test_exclude_attributes(
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
await hass.async_block_till_done()
state = hass.states.get("update.update_already_in_progress")
assert state.attributes[ATTR_IN_PROGRESS] == 50
assert state.attributes[ATTR_IN_PROGRESS] is True
assert state.attributes[ATTR_UPDATE_PERCENTAGE] == 50
assert (
state.attributes[ATTR_ENTITY_PICTURE]
== "https://brands.home-assistant.io/_/test/icon.png"
@ -56,3 +58,4 @@ async def test_exclude_attributes(
assert ATTR_IN_PROGRESS not in state.attributes
assert ATTR_RELEASE_SUMMARY not in state.attributes
assert ATTR_INSTALLED_VERSION in state.attributes
assert ATTR_UPDATE_PERCENTAGE not in state.attributes

View File

@ -23,6 +23,7 @@ from homeassistant.components.update import (
ATTR_IN_PROGRESS,
ATTR_INSTALLED_VERSION,
ATTR_LATEST_VERSION,
ATTR_UPDATE_PERCENTAGE,
DOMAIN as UPDATE_DOMAIN,
SERVICE_INSTALL,
)
@ -172,7 +173,8 @@ async def test_firmware_update_notification_from_zigpy(
assert state.state == STATE_ON
attrs = state.attributes
assert attrs[ATTR_INSTALLED_VERSION] == f"0x{installed_fw_version:08x}"
assert not attrs[ATTR_IN_PROGRESS]
assert attrs[ATTR_IN_PROGRESS] is False
assert attrs[ATTR_UPDATE_PERCENTAGE] is None
assert (
attrs[ATTR_LATEST_VERSION] == f"0x{fw_image.firmware.header.file_version:08x}"
)
@ -231,7 +233,8 @@ async def test_firmware_update_notification_from_service_call(
assert state.state == STATE_ON
attrs = state.attributes
assert attrs[ATTR_INSTALLED_VERSION] == f"0x{installed_fw_version:08x}"
assert not attrs[ATTR_IN_PROGRESS]
assert attrs[ATTR_IN_PROGRESS] is False
assert attrs[ATTR_UPDATE_PERCENTAGE] is None
assert (
attrs[ATTR_LATEST_VERSION]
== f"0x{fw_image.firmware.header.file_version:08x}"
@ -301,7 +304,8 @@ async def test_firmware_update_success(
assert state.state == STATE_ON
attrs = state.attributes
assert attrs[ATTR_INSTALLED_VERSION] == f"0x{installed_fw_version:08x}"
assert not attrs[ATTR_IN_PROGRESS]
assert attrs[ATTR_IN_PROGRESS] is False
assert attrs[ATTR_UPDATE_PERCENTAGE] is None
assert (
attrs[ATTR_LATEST_VERSION] == f"0x{fw_image.firmware.header.file_version:08x}"
)
@ -389,7 +393,8 @@ async def test_firmware_update_success(
assert (
attrs[ATTR_INSTALLED_VERSION] == f"0x{installed_fw_version:08x}"
)
assert attrs[ATTR_IN_PROGRESS] == 58
assert attrs[ATTR_IN_PROGRESS] is True
assert attrs[ATTR_UPDATE_PERCENTAGE] == 58
assert (
attrs[ATTR_LATEST_VERSION]
== f"0x{fw_image.firmware.header.file_version:08x}"
@ -446,7 +451,8 @@ async def test_firmware_update_success(
attrs[ATTR_INSTALLED_VERSION]
== f"0x{fw_image.firmware.header.file_version:08x}"
)
assert not attrs[ATTR_IN_PROGRESS]
assert attrs[ATTR_IN_PROGRESS] is False
assert attrs[ATTR_UPDATE_PERCENTAGE] is None
assert attrs[ATTR_LATEST_VERSION] == attrs[ATTR_INSTALLED_VERSION]
# If we send a progress notification incorrectly, it won't be handled
@ -454,7 +460,8 @@ async def test_firmware_update_success(
entity.entity_data.entity._update_progress(50, 100, 0.50)
state = hass.states.get(entity_id)
assert not attrs[ATTR_IN_PROGRESS]
assert attrs[ATTR_IN_PROGRESS] is False
assert attrs[ATTR_UPDATE_PERCENTAGE] is None
assert state.state == STATE_OFF
@ -493,7 +500,8 @@ async def test_firmware_update_raises(
assert state.state == STATE_ON
attrs = state.attributes
assert attrs[ATTR_INSTALLED_VERSION] == f"0x{installed_fw_version:08x}"
assert not attrs[ATTR_IN_PROGRESS]
assert attrs[ATTR_IN_PROGRESS] is False
assert attrs[ATTR_UPDATE_PERCENTAGE] is None
assert (
attrs[ATTR_LATEST_VERSION] == f"0x{fw_image.firmware.header.file_version:08x}"
)

View File

@ -16,6 +16,7 @@ from homeassistant.components.update import (
ATTR_LATEST_VERSION,
ATTR_RELEASE_URL,
ATTR_SKIPPED_VERSION,
ATTR_UPDATE_PERCENTAGE,
DOMAIN as UPDATE_DOMAIN,
SERVICE_INSTALL,
SERVICE_SKIP,
@ -155,9 +156,10 @@ async def test_update_entity_states(
attrs = state.attributes
assert not attrs[ATTR_AUTO_UPDATE]
assert attrs[ATTR_INSTALLED_VERSION] == "10.7"
assert not attrs[ATTR_IN_PROGRESS]
assert attrs[ATTR_IN_PROGRESS] is False
assert attrs[ATTR_LATEST_VERSION] == "11.2.4"
assert attrs[ATTR_RELEASE_URL] is None
assert attrs[ATTR_UPDATE_PERCENTAGE] is None
await ws_client.send_json(
{
@ -417,6 +419,7 @@ async def test_update_entity_progress(
assert state
attrs = state.attributes
assert attrs[ATTR_IN_PROGRESS] is True
assert attrs[ATTR_UPDATE_PERCENTAGE] is None
event = Event(
type="firmware update progress",
@ -439,7 +442,8 @@ async def test_update_entity_progress(
state = hass.states.get(UPDATE_ENTITY)
assert state
attrs = state.attributes
assert attrs[ATTR_IN_PROGRESS] == 5
assert attrs[ATTR_IN_PROGRESS] is True
assert attrs[ATTR_UPDATE_PERCENTAGE] == 5
event = Event(
type="firmware update finished",
@ -463,6 +467,7 @@ async def test_update_entity_progress(
assert state
attrs = state.attributes
assert attrs[ATTR_IN_PROGRESS] is False
assert attrs[ATTR_UPDATE_PERCENTAGE] is None
assert attrs[ATTR_INSTALLED_VERSION] == "11.2.4"
assert attrs[ATTR_LATEST_VERSION] == "11.2.4"
assert state.state == STATE_OFF
@ -532,7 +537,8 @@ async def test_update_entity_install_failed(
state = hass.states.get(UPDATE_ENTITY)
assert state
attrs = state.attributes
assert attrs[ATTR_IN_PROGRESS] == 5
assert attrs[ATTR_IN_PROGRESS] is True
assert attrs[ATTR_UPDATE_PERCENTAGE] == 5
event = Event(
type="firmware update finished",
@ -556,6 +562,7 @@ async def test_update_entity_install_failed(
assert state
attrs = state.attributes
assert attrs[ATTR_IN_PROGRESS] is False
assert attrs[ATTR_UPDATE_PERCENTAGE] is None
assert attrs[ATTR_INSTALLED_VERSION] == "10.7"
assert attrs[ATTR_LATEST_VERSION] == "11.2.4"
assert state.state == STATE_ON
@ -594,7 +601,8 @@ async def test_update_entity_reload(
attrs = state.attributes
assert not attrs[ATTR_AUTO_UPDATE]
assert attrs[ATTR_INSTALLED_VERSION] == "10.7"
assert not attrs[ATTR_IN_PROGRESS]
assert attrs[ATTR_IN_PROGRESS] is False
assert attrs[ATTR_UPDATE_PERCENTAGE] is None
assert attrs[ATTR_LATEST_VERSION] == "11.2.4"
assert attrs[ATTR_RELEASE_URL] is None
@ -833,6 +841,7 @@ async def test_update_entity_full_restore_data_update_available(
assert state
attrs = state.attributes
assert attrs[ATTR_IN_PROGRESS] is True
assert attrs[ATTR_UPDATE_PERCENTAGE] is None
assert len(client.async_send_command.call_args_list) == 2
assert client.async_send_command.call_args_list[1][0][0] == {