diff --git a/homeassistant/components/zwave_js/update.py b/homeassistant/components/zwave_js/update.py index 134c6cc6661c32bc407909734cc20c2a7e2ca6f3..1f04c3acc47b5bbc6e6d85a49cb329ecad896760 100644 --- a/homeassistant/components/zwave_js/update.py +++ b/homeassistant/components/zwave_js/update.py @@ -86,17 +86,24 @@ class ZWaveNodeFirmwareUpdate(UpdateEntity): self._attr_installed_version = self._attr_latest_version = node.firmware_version - def _update_on_wake_up(self, _: dict[str, Any]) -> None: + def _update_on_status_change(self, _: dict[str, Any]) -> None: """Update the entity when node is awake.""" self._status_unsub = None self.hass.async_create_task(self.async_update(True)) async def async_update(self, write_state: bool = False) -> None: """Update the entity.""" - if self.node.status == NodeStatus.ASLEEP: - if not self._status_unsub: - self._status_unsub = self.node.once("wake up", self._update_on_wake_up) - return + for status, event_name in ( + (NodeStatus.ASLEEP, "wake up"), + (NodeStatus.DEAD, "alive"), + ): + if self.node.status == status: + if not self._status_unsub: + self._status_unsub = self.node.once( + event_name, self._update_on_status_change + ) + return + if available_firmware_updates := ( await self.driver.controller.async_get_available_firmware_updates( self.node, API_KEY_FIRMWARE_UPDATE_SERVICE diff --git a/tests/components/zwave_js/test_update.py b/tests/components/zwave_js/test_update.py index 852dcba5954bc87c350462cf057b6635dba78334..c9ec8fa68c6f6a3619382e645612f9a474c554a7 100644 --- a/tests/components/zwave_js/test_update.py +++ b/tests/components/zwave_js/test_update.py @@ -24,6 +24,31 @@ from homeassistant.util import datetime as dt_util from tests.common import async_fire_time_changed UPDATE_ENTITY = "update.z_wave_thermostat_firmware" +FIRMWARE_UPDATES = { + "updates": [ + { + "version": "10.11.1", + "changelog": "blah 1", + "files": [ + {"target": 0, "url": "https://example1.com", "integrity": "sha1"} + ], + }, + { + "version": "11.2.4", + "changelog": "blah 2", + "files": [ + {"target": 0, "url": "https://example2.com", "integrity": "sha2"} + ], + }, + { + "version": "11.1.5", + "changelog": "blah 3", + "files": [ + {"target": 0, "url": "https://example3.com", "integrity": "sha3"} + ], + }, + ] +} async def test_update_entity_success( @@ -60,31 +85,7 @@ async def test_update_entity_success( result = await ws_client.receive_json() assert result["result"] is None - client.async_send_command.return_value = { - "updates": [ - { - "version": "10.11.1", - "changelog": "blah 1", - "files": [ - {"target": 0, "url": "https://example1.com", "integrity": "sha1"} - ], - }, - { - "version": "11.2.4", - "changelog": "blah 2", - "files": [ - {"target": 0, "url": "https://example2.com", "integrity": "sha2"} - ], - }, - { - "version": "11.1.5", - "changelog": "blah 3", - "files": [ - {"target": 0, "url": "https://example3.com", "integrity": "sha3"} - ], - }, - ] - } + client.async_send_command.return_value = FIRMWARE_UPDATES async_fire_time_changed(hass, dt_util.utcnow() + timedelta(days=2)) await hass.async_block_till_done() @@ -171,31 +172,7 @@ async def test_update_entity_failure( hass_ws_client, ): """Test update entity failed install.""" - client.async_send_command.return_value = { - "updates": [ - { - "version": "10.11.1", - "changelog": "blah 1", - "files": [ - {"target": 0, "url": "https://example1.com", "integrity": "sha1"} - ], - }, - { - "version": "11.2.4", - "changelog": "blah 2", - "files": [ - {"target": 0, "url": "https://example2.com", "integrity": "sha2"} - ], - }, - { - "version": "11.1.5", - "changelog": "blah 3", - "files": [ - {"target": 0, "url": "https://example3.com", "integrity": "sha3"} - ], - }, - ] - } + client.async_send_command.return_value = FIRMWARE_UPDATES async_fire_time_changed(hass, dt_util.utcnow() + timedelta(days=1)) await hass.async_block_till_done() @@ -228,31 +205,7 @@ async def test_update_entity_sleep( multisensor_6.receive_event(event) client.async_send_command.reset_mock() - client.async_send_command.return_value = { - "updates": [ - { - "version": "10.11.1", - "changelog": "blah 1", - "files": [ - {"target": 0, "url": "https://example1.com", "integrity": "sha1"} - ], - }, - { - "version": "11.2.4", - "changelog": "blah 2", - "files": [ - {"target": 0, "url": "https://example2.com", "integrity": "sha2"} - ], - }, - { - "version": "11.1.5", - "changelog": "blah 3", - "files": [ - {"target": 0, "url": "https://example3.com", "integrity": "sha3"} - ], - }, - ] - } + client.async_send_command.return_value = FIRMWARE_UPDATES async_fire_time_changed(hass, dt_util.utcnow() + timedelta(days=1)) await hass.async_block_till_done() @@ -273,3 +226,40 @@ async def test_update_entity_sleep( args = client.async_send_command.call_args_list[0][0][0] assert args["command"] == "controller.get_available_firmware_updates" assert args["nodeId"] == multisensor_6.node_id + + +async def test_update_entity_dead( + hass, + client, + multisensor_6, + integration, +): + """Test update occurs when device is dead after it becomes alive.""" + event = Event( + "dead", + data={"source": "node", "event": "dead", "nodeId": multisensor_6.node_id}, + ) + multisensor_6.receive_event(event) + client.async_send_command.reset_mock() + + client.async_send_command.return_value = FIRMWARE_UPDATES + + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(days=1)) + await hass.async_block_till_done() + + # Because node is asleep we shouldn't attempt to check for firmware updates + assert len(client.async_send_command.call_args_list) == 0 + + event = Event( + "alive", + data={"source": "node", "event": "alive", "nodeId": multisensor_6.node_id}, + ) + multisensor_6.receive_event(event) + await hass.async_block_till_done() + + # Now that the node is up we can check for updates + assert len(client.async_send_command.call_args_list) > 0 + + args = client.async_send_command.call_args_list[0][0][0] + assert args["command"] == "controller.get_available_firmware_updates" + assert args["nodeId"] == multisensor_6.node_id