From 01acc3d1e5771048a13727213b58509a885b04de Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Sat, 17 Sep 2022 13:43:35 -0400 Subject: [PATCH] Fix zwave_js update entity startup state (#78563) * Fix update entity startup state * Only write state if there is a change * Add test to show that when an existing entity gets recreated, skipped version does not reset * Remove unused blocks * Update homeassistant/components/zwave_js/update.py Co-authored-by: Franck Nijhof Co-authored-by: Franck Nijhof --- homeassistant/components/zwave_js/update.py | 34 ++++++----- tests/components/zwave_js/test_update.py | 63 ++++++++++++++++++++- 2 files changed, 82 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/zwave_js/update.py b/homeassistant/components/zwave_js/update.py index 022c4dc3f3c..08a5b90b42d 100644 --- a/homeassistant/components/zwave_js/update.py +++ b/homeassistant/components/zwave_js/update.py @@ -99,7 +99,7 @@ class ZWaveNodeFirmwareUpdate(UpdateEntity): self._attr_name = "Firmware" self._base_unique_id = get_valueless_base_unique_id(driver, node) self._attr_unique_id = f"{self._base_unique_id}.firmware_update" - self._attr_installed_version = self._attr_latest_version = node.firmware_version + self._attr_installed_version = node.firmware_version # device may not be precreated in main handler yet self._attr_device_info = get_device_info(driver, node) @@ -187,20 +187,26 @@ class ZWaveNodeFirmwareUpdate(UpdateEntity): err, ) else: - if available_firmware_updates: - self._latest_version_firmware = latest_firmware = max( - available_firmware_updates, - key=lambda x: AwesomeVersion(x.version), + # If we have an available firmware update that is a higher version than + # what's on the node, we should advertise it, otherwise the installed + # version is the latest. + if ( + available_firmware_updates + and ( + latest_firmware := max( + available_firmware_updates, + key=lambda x: AwesomeVersion(x.version), + ) ) - - # If we have an available firmware update that is a higher version than - # what's on the node, we should advertise it, otherwise there is - # nothing to do. - new_version = latest_firmware.version - current_version = self.node.firmware_version - if AwesomeVersion(new_version) > AwesomeVersion(current_version): - self._attr_latest_version = new_version - self.async_write_ha_state() + and AwesomeVersion(latest_firmware.version) + > AwesomeVersion(self.node.firmware_version) + ): + self._latest_version_firmware = latest_firmware + self._attr_latest_version = latest_firmware.version + self.async_write_ha_state() + elif self._attr_latest_version != self._attr_installed_version: + self._attr_latest_version = self._attr_installed_version + self.async_write_ha_state() finally: self._poll_unsub = async_call_later( self.hass, timedelta(days=1), self._async_update diff --git a/tests/components/zwave_js/test_update.py b/tests/components/zwave_js/test_update.py index 0b567d93106..a5b3059e705 100644 --- a/tests/components/zwave_js/test_update.py +++ b/tests/components/zwave_js/test_update.py @@ -13,8 +13,10 @@ from homeassistant.components.update.const import ( ATTR_INSTALLED_VERSION, ATTR_LATEST_VERSION, ATTR_RELEASE_URL, + ATTR_SKIPPED_VERSION, DOMAIN as UPDATE_DOMAIN, SERVICE_INSTALL, + SERVICE_SKIP, ) from homeassistant.components.zwave_js.const import DOMAIN, SERVICE_REFRESH_VALUE from homeassistant.components.zwave_js.helpers import get_valueless_base_unique_id @@ -64,7 +66,6 @@ async def test_update_entity_states( ): """Test update entity states.""" ws_client = await hass_ws_client(hass) - await hass.async_block_till_done() assert hass.states.get(UPDATE_ENTITY).state == STATE_OFF @@ -453,3 +454,63 @@ async def test_update_entity_install_failed( # validate that the install task failed with pytest.raises(HomeAssistantError): await install_task + + +async def test_update_entity_reload( + hass, + client, + climate_radio_thermostat_ct100_plus_different_endpoints, + integration, +): + """Test update entity maintains state after reload.""" + assert hass.states.get(UPDATE_ENTITY).state == STATE_OFF + + client.async_send_command.return_value = {"updates": []} + + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(days=1)) + await hass.async_block_till_done() + + state = hass.states.get(UPDATE_ENTITY) + assert state + assert state.state == STATE_OFF + + 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() + + state = hass.states.get(UPDATE_ENTITY) + assert state + assert state.state == STATE_ON + 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_LATEST_VERSION] == "11.2.4" + assert attrs[ATTR_RELEASE_URL] is None + + await hass.services.async_call( + UPDATE_DOMAIN, + SERVICE_SKIP, + { + ATTR_ENTITY_ID: UPDATE_ENTITY, + }, + blocking=True, + ) + + state = hass.states.get(UPDATE_ENTITY) + assert state + assert state.state == STATE_OFF + assert state.attributes[ATTR_SKIPPED_VERSION] == "11.2.4" + + await hass.config_entries.async_reload(integration.entry_id) + await hass.async_block_till_done() + + # Trigger another update and make sure the skipped version is still skipped + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(days=4)) + 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] == "11.2.4"