Fix zwave_js.update entity restore logic (#94043)
parent
b5b9a06c2c
commit
5461d0e28f
|
@ -42,6 +42,7 @@ PARALLEL_UPDATES = 1
|
||||||
|
|
||||||
UPDATE_DELAY_STRING = "delay"
|
UPDATE_DELAY_STRING = "delay"
|
||||||
UPDATE_DELAY_INTERVAL = 5 # In minutes
|
UPDATE_DELAY_INTERVAL = 5 # In minutes
|
||||||
|
ATTR_LATEST_VERSION_FIRMWARE = "latest_version_firmware"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -53,7 +54,7 @@ class ZWaveNodeFirmwareUpdateExtraStoredData(ExtraStoredData):
|
||||||
def as_dict(self) -> dict[str, Any]:
|
def as_dict(self) -> dict[str, Any]:
|
||||||
"""Return a dict representation of the extra data."""
|
"""Return a dict representation of the extra data."""
|
||||||
return {
|
return {
|
||||||
"latest_version_firmware": asdict(self.latest_version_firmware)
|
ATTR_LATEST_VERSION_FIRMWARE: asdict(self.latest_version_firmware)
|
||||||
if self.latest_version_firmware
|
if self.latest_version_firmware
|
||||||
else None
|
else None
|
||||||
}
|
}
|
||||||
|
@ -61,7 +62,7 @@ class ZWaveNodeFirmwareUpdateExtraStoredData(ExtraStoredData):
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, data: dict[str, Any]) -> ZWaveNodeFirmwareUpdateExtraStoredData:
|
def from_dict(cls, data: dict[str, Any]) -> ZWaveNodeFirmwareUpdateExtraStoredData:
|
||||||
"""Initialize the extra data from a dict."""
|
"""Initialize the extra data from a dict."""
|
||||||
if not (firmware_dict := data["latest_version_firmware"]):
|
if not (firmware_dict := data[ATTR_LATEST_VERSION_FIRMWARE]):
|
||||||
return cls(None)
|
return cls(None)
|
||||||
|
|
||||||
return cls(NodeFirmwareUpdateInfo.from_dict(firmware_dict))
|
return cls(NodeFirmwareUpdateInfo.from_dict(firmware_dict))
|
||||||
|
@ -326,20 +327,24 @@ class ZWaveNodeFirmwareUpdate(UpdateEntity):
|
||||||
)
|
)
|
||||||
|
|
||||||
# If we have a complete previous state, use that to set the latest version
|
# If we have a complete previous state, use that to set the latest version
|
||||||
if (state := await self.async_get_last_state()) and (
|
if (
|
||||||
extra_data := await self.async_get_last_extra_data()
|
(state := await self.async_get_last_state())
|
||||||
|
and (latest_version := state.attributes.get(ATTR_LATEST_VERSION))
|
||||||
|
is not None
|
||||||
|
and (extra_data := await self.async_get_last_extra_data())
|
||||||
):
|
):
|
||||||
self._attr_latest_version = state.attributes[ATTR_LATEST_VERSION]
|
self._attr_latest_version = latest_version
|
||||||
self._latest_version_firmware = (
|
self._latest_version_firmware = (
|
||||||
ZWaveNodeFirmwareUpdateExtraStoredData.from_dict(
|
ZWaveNodeFirmwareUpdateExtraStoredData.from_dict(
|
||||||
extra_data.as_dict()
|
extra_data.as_dict()
|
||||||
).latest_version_firmware
|
).latest_version_firmware
|
||||||
)
|
)
|
||||||
# If we have no state to restore, we can set the latest version to installed
|
# If we have no state or latest version to restore, we can set the latest
|
||||||
# so that the entity starts as off. If we have partial restore data due to an
|
# version to installed so that the entity starts as off. If we have partial
|
||||||
# upgrade to an HA version where this feature is released from one that is not
|
# restore data due to an upgrade to an HA version where this feature is released
|
||||||
# the entity will start in an unknown state until we can correct on next update
|
# from one that is not the entity will start in an unknown state until we can
|
||||||
elif not state:
|
# correct on next update
|
||||||
|
elif not state or not latest_version:
|
||||||
self._attr_latest_version = self._attr_installed_version
|
self._attr_latest_version = self._attr_installed_version
|
||||||
|
|
||||||
# Spread updates out in 5 minute increments to avoid flooding the network
|
# Spread updates out in 5 minute increments to avoid flooding the network
|
||||||
|
|
|
@ -778,6 +778,42 @@ async def test_update_entity_full_restore_data_no_update_available(
|
||||||
assert state.attributes[ATTR_LATEST_VERSION] == "10.7"
|
assert state.attributes[ATTR_LATEST_VERSION] == "10.7"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_update_entity_no_latest_version(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
client,
|
||||||
|
climate_radio_thermostat_ct100_plus_different_endpoints,
|
||||||
|
hass_ws_client: WebSocketGenerator,
|
||||||
|
) -> None:
|
||||||
|
"""Test entity with no `latest_version` attr restores state."""
|
||||||
|
mock_restore_cache_with_extra_data(
|
||||||
|
hass,
|
||||||
|
[
|
||||||
|
(
|
||||||
|
State(
|
||||||
|
UPDATE_ENTITY,
|
||||||
|
STATE_OFF,
|
||||||
|
{
|
||||||
|
ATTR_INSTALLED_VERSION: "10.7",
|
||||||
|
ATTR_LATEST_VERSION: None,
|
||||||
|
ATTR_SKIPPED_VERSION: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
{"latest_version_firmware": None},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
entry = MockConfigEntry(domain="zwave_js", data={"url": "ws://test.org"})
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get(UPDATE_ENTITY)
|
||||||
|
assert state
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
assert state.attributes[ATTR_SKIPPED_VERSION] is None
|
||||||
|
assert state.attributes[ATTR_LATEST_VERSION] == "10.7"
|
||||||
|
|
||||||
|
|
||||||
async def test_update_entity_unload_asleep_node(
|
async def test_update_entity_unload_asleep_node(
|
||||||
hass: HomeAssistant, client, wallmote_central_scene, integration
|
hass: HomeAssistant, client, wallmote_central_scene, integration
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
Loading…
Reference in New Issue