From d135d088139096cfff60be0fb9d4bf277f93f92d Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Mon, 11 Aug 2025 14:09:04 +0200 Subject: [PATCH] Lower Z-Wave firmware check delay (#150411) --- homeassistant/components/zwave_js/update.py | 13 ++++----- tests/components/zwave_js/test_discovery.py | 12 ++++++++- tests/components/zwave_js/test_update.py | 30 ++++++++++----------- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/zwave_js/update.py b/homeassistant/components/zwave_js/update.py index 88e1a22c00f..9e9d6ee2ef3 100644 --- a/homeassistant/components/zwave_js/update.py +++ b/homeassistant/components/zwave_js/update.py @@ -42,7 +42,7 @@ from .models import ZwaveJSConfigEntry PARALLEL_UPDATES = 1 UPDATE_DELAY_STRING = "delay" -UPDATE_DELAY_INTERVAL = 5 # In minutes +UPDATE_DELAY_INTERVAL = 15 # In seconds ATTR_LATEST_VERSION_FIRMWARE = "latest_version_firmware" @@ -129,11 +129,11 @@ async def async_setup_entry( @callback def async_add_firmware_update_entity(node: ZwaveNode) -> None: """Add firmware update entity.""" - # We need to delay the first update of each entity to avoid flooding the network - # so we maintain a counter to schedule first update in UPDATE_DELAY_INTERVAL - # minute increments. + # Delay the first update of each entity to avoid spamming the firmware server. + # Maintain a counter to schedule first update in UPDATE_DELAY_INTERVAL + # second increments. cnt[UPDATE_DELAY_STRING] += 1 - delay = timedelta(minutes=(cnt[UPDATE_DELAY_STRING] * UPDATE_DELAY_INTERVAL)) + delay = timedelta(seconds=(cnt[UPDATE_DELAY_STRING] * UPDATE_DELAY_INTERVAL)) driver = client.driver assert driver is not None # Driver is ready before platforms are loaded. if node.is_controller_node: @@ -413,7 +413,8 @@ class ZWaveFirmwareUpdateEntity(UpdateEntity): ): self._attr_latest_version = self._attr_installed_version - # Spread updates out in 5 minute increments to avoid flooding the network + # Spread updates out in 15 second increments + # to avoid spamming the firmware server self.async_on_remove( async_call_later(self.hass, self._delay, self._async_update) ) diff --git a/tests/components/zwave_js/test_discovery.py b/tests/components/zwave_js/test_discovery.py index 9109d6a4048..6a4752d536b 100644 --- a/tests/components/zwave_js/test_discovery.py +++ b/tests/components/zwave_js/test_discovery.py @@ -28,7 +28,13 @@ from homeassistant.components.zwave_js.discovery_data_template import ( DynamicCurrentTempClimateDataTemplate, ) from homeassistant.config_entries import RELOAD_AFTER_UPDATE_DELAY -from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_UNKNOWN, EntityCategory +from homeassistant.const import ( + ATTR_ENTITY_ID, + STATE_OFF, + STATE_UNKNOWN, + EntityCategory, + Platform, +) from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.util import dt as dt_util @@ -253,6 +259,7 @@ async def test_merten_507801_disabled_enitites( assert updated_entry.disabled is False +@pytest.mark.parametrize("platforms", [[Platform.BUTTON, Platform.NUMBER]]) async def test_zooz_zen72( hass: HomeAssistant, entity_registry: er.EntityRegistry, @@ -324,6 +331,9 @@ async def test_zooz_zen72( assert args["value"] is True +@pytest.mark.parametrize( + "platforms", [[Platform.BINARY_SENSOR, Platform.SENSOR, Platform.SWITCH]] +) async def test_indicator_test( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/zwave_js/test_update.py b/tests/components/zwave_js/test_update.py index d7243268b9e..b78d202935d 100644 --- a/tests/components/zwave_js/test_update.py +++ b/tests/components/zwave_js/test_update.py @@ -167,7 +167,7 @@ async def test_update_entity_states( client.async_send_command.return_value = {"updates": []} - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5, days=1)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15, days=1)) await hass.async_block_till_done() state = hass.states.get(entity_id) @@ -186,7 +186,7 @@ async def test_update_entity_states( client.async_send_command.return_value = FIRMWARE_UPDATES - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5, days=2)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15, days=2)) await hass.async_block_till_done() state = hass.states.get(entity_id) @@ -224,7 +224,7 @@ async def test_update_entity_states( client.async_send_command.return_value = {"updates": []} - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5, days=3)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15, days=3)) await hass.async_block_till_done() state = hass.states.get(entity_id) @@ -246,7 +246,7 @@ async def test_update_entity_install_raises( """Test update entity install raises exception.""" client.async_send_command.return_value = FIRMWARE_UPDATES - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5, days=1)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15, days=1)) await hass.async_block_till_done() # Test failed installation by driver @@ -279,7 +279,7 @@ async def test_update_entity_sleep( client.async_send_command.return_value = FIRMWARE_UPDATES - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5, days=1)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15, days=1)) await hass.async_block_till_done() # Two nodes in total, the controller node and the zen_31 node. @@ -308,7 +308,7 @@ async def test_update_entity_dead( client.async_send_command.return_value = FIRMWARE_UPDATES - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5, days=1)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15, days=1)) await hass.async_block_till_done() # Two nodes in total, the controller node and the zen_31 node. @@ -352,14 +352,14 @@ async def test_update_entity_ha_not_running( # Update should be delayed by a day because Home Assistant is not running hass.set_state(CoreState.starting) - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15)) await hass.async_block_till_done() assert client.async_send_command.call_count == 0 hass.set_state(CoreState.running) - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5, days=1)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15, days=1)) await hass.async_block_till_done() # Two nodes in total, the controller node and the zen_31 node. @@ -385,7 +385,7 @@ async def test_update_entity_update_failure( assert client.async_send_command.call_count == 0 client.async_send_command.side_effect = FailedZWaveCommand("test", 260, "test") - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5, days=1)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15, days=1)) await hass.async_block_till_done() entity_ids = (CONTROLLER_UPDATE_ENTITY, NODE_UPDATE_ENTITY) @@ -493,7 +493,7 @@ async def test_update_entity_progress( client.async_send_command.return_value = FIRMWARE_UPDATES driver = client.driver - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5, days=1)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15, days=1)) await hass.async_block_till_done() state = hass.states.get(entity_id) @@ -641,7 +641,7 @@ async def test_update_entity_install_failed( driver = client.driver client.async_send_command.return_value = FIRMWARE_UPDATES - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5, days=1)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15, days=1)) await hass.async_block_till_done() state = hass.states.get(entity_id) @@ -717,7 +717,7 @@ async def test_update_entity_reload( client.async_send_command.return_value = {"updates": []} - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5, days=1)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15, days=1)) await hass.async_block_till_done() state = hass.states.get(entity_id) @@ -726,7 +726,7 @@ async def test_update_entity_reload( client.async_send_command.return_value = FIRMWARE_UPDATES - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5, days=2)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15, days=2)) await hass.async_block_till_done() state = hass.states.get(entity_id) @@ -758,7 +758,7 @@ async def test_update_entity_reload( 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(minutes=5, days=4)) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=15, days=4)) await hass.async_block_till_done() state = hass.states.get(entity_id) @@ -793,7 +793,7 @@ async def test_update_entity_delay( assert client.async_send_command.call_count == 0 - update_interval = timedelta(minutes=5) + update_interval = timedelta(seconds=15) freezer.tick(update_interval) async_fire_time_changed(hass) await hass.async_block_till_done()