From 9ca1d204b6c1316930a4dbcfa39a212dcf26e0f8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 28 Apr 2024 11:19:38 -0500 Subject: [PATCH] Fix shelly delaying shutdown (#116346) --- .../components/shelly/coordinator.py | 36 +++++++++++++++---- tests/components/shelly/test_binary_sensor.py | 10 +++--- tests/components/shelly/test_climate.py | 18 +++++----- tests/components/shelly/test_coordinator.py | 16 ++++----- tests/components/shelly/test_number.py | 10 +++--- tests/components/shelly/test_sensor.py | 18 +++++----- tests/components/shelly/test_update.py | 6 ++-- 7 files changed, 69 insertions(+), 45 deletions(-) diff --git a/homeassistant/components/shelly/coordinator.py b/homeassistant/components/shelly/coordinator.py index bd6686198ed..d3d7b86de11 100644 --- a/homeassistant/components/shelly/coordinator.py +++ b/homeassistant/components/shelly/coordinator.py @@ -361,7 +361,12 @@ class ShellyBlockCoordinator(ShellyCoordinatorBase[BlockDevice]): ) -> None: """Handle device update.""" if update_type is BlockUpdateType.ONLINE: - self.hass.async_create_task(self._async_device_connect(), eager_start=True) + self.entry.async_create_background_task( + self.hass, + self._async_device_connect(), + "block device online", + eager_start=True, + ) elif update_type is BlockUpdateType.COAP_PERIODIC: self._push_update_failures = 0 ir.async_delete_issue( @@ -654,12 +659,24 @@ class ShellyRpcCoordinator(ShellyCoordinatorBase[RpcDevice]): ) -> None: """Handle device update.""" if update_type is RpcUpdateType.ONLINE: - self.hass.async_create_task(self._async_device_connect(), eager_start=True) + self.entry.async_create_background_task( + self.hass, + self._async_device_connect(), + "rpc device online", + eager_start=True, + ) elif update_type is RpcUpdateType.INITIALIZED: - self.hass.async_create_task(self._async_connected(), eager_start=True) + self.entry.async_create_background_task( + self.hass, self._async_connected(), "rpc device init", eager_start=True + ) self.async_set_updated_data(None) elif update_type is RpcUpdateType.DISCONNECTED: - self.hass.async_create_task(self._async_disconnected(), eager_start=True) + self.entry.async_create_background_task( + self.hass, + self._async_disconnected(), + "rpc device disconnected", + eager_start=True, + ) elif update_type is RpcUpdateType.STATUS: self.async_set_updated_data(None) if self.sleep_period: @@ -673,7 +690,9 @@ class ShellyRpcCoordinator(ShellyCoordinatorBase[RpcDevice]): self.device.subscribe_updates(self._async_handle_update) if self.device.initialized: # If we are already initialized, we are connected - self.hass.async_create_task(self._async_connected(), eager_start=True) + self.entry.async_create_task( + self.hass, self._async_connected(), eager_start=True + ) async def shutdown(self) -> None: """Shutdown the coordinator.""" @@ -756,4 +775,9 @@ async def async_reconnect_soon(hass: HomeAssistant, entry: ConfigEntry) -> None: and (entry_data := get_entry_data(hass).get(entry.entry_id)) and (coordinator := entry_data.rpc) ): - hass.async_create_task(coordinator.async_request_refresh(), eager_start=True) + entry.async_create_background_task( + hass, + coordinator.async_request_refresh(), + "reconnect soon", + eager_start=True, + ) diff --git a/tests/components/shelly/test_binary_sensor.py b/tests/components/shelly/test_binary_sensor.py index 624eb82f060..524bc1e8ffc 100644 --- a/tests/components/shelly/test_binary_sensor.py +++ b/tests/components/shelly/test_binary_sensor.py @@ -145,7 +145,7 @@ async def test_block_sleeping_binary_sensor( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == STATE_OFF @@ -181,7 +181,7 @@ async def test_block_restored_sleeping_binary_sensor( # Make device online monkeypatch.setattr(mock_block_device, "initialized", True) mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == STATE_OFF @@ -207,7 +207,7 @@ async def test_block_restored_sleeping_binary_sensor_no_last_state( # Make device online monkeypatch.setattr(mock_block_device, "initialized", True) mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == STATE_OFF @@ -275,7 +275,7 @@ async def test_rpc_sleeping_binary_sensor( # Make device online mock_rpc_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == STATE_OFF @@ -346,7 +346,7 @@ async def test_rpc_restored_sleeping_binary_sensor_no_last_state( # Make device online monkeypatch.setattr(mock_rpc_device, "initialized", True) mock_rpc_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) # Mock update mock_rpc_device.mock_update() diff --git a/tests/components/shelly/test_climate.py b/tests/components/shelly/test_climate.py index 9946dd7640d..a70cdef3fb1 100644 --- a/tests/components/shelly/test_climate.py +++ b/tests/components/shelly/test_climate.py @@ -70,7 +70,7 @@ async def test_climate_hvac_mode( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) # Test initial hvac mode - off state = hass.states.get(ENTITY_ID) @@ -131,7 +131,7 @@ async def test_climate_set_temperature( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) state = hass.states.get(ENTITY_ID) assert state.state == HVACMode.OFF @@ -198,7 +198,7 @@ async def test_climate_set_preset_mode( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) state = hass.states.get(ENTITY_ID) assert state.attributes[ATTR_PRESET_MODE] == PRESET_NONE @@ -284,7 +284,7 @@ async def test_block_restored_climate( # Make device online monkeypatch.setattr(mock_block_device, "initialized", True) mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == HVACMode.OFF assert hass.states.get(entity_id).attributes.get("temperature") == 4.0 @@ -355,7 +355,7 @@ async def test_block_restored_climate_us_customery( monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "targetTemp", 4.0) monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "temp", 18.2) mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == HVACMode.OFF assert hass.states.get(entity_id).attributes.get("temperature") == 39 @@ -457,7 +457,7 @@ async def test_block_set_mode_connection_error( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) with pytest.raises(HomeAssistantError): await hass.services.async_call( @@ -482,7 +482,7 @@ async def test_block_set_mode_auth_error( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert entry.state is ConfigEntryState.LOADED @@ -540,7 +540,7 @@ async def test_block_restored_climate_auth_error( return_value={}, side_effect=InvalidAuthError ) mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert entry.state is ConfigEntryState.LOADED @@ -567,7 +567,7 @@ async def test_device_not_calibrated( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) mock_status = MOCK_STATUS_COAP.copy() mock_status["calibrated"] = False diff --git a/tests/components/shelly/test_coordinator.py b/tests/components/shelly/test_coordinator.py index 9f251d1e008..1e581e156c5 100644 --- a/tests/components/shelly/test_coordinator.py +++ b/tests/components/shelly/test_coordinator.py @@ -224,7 +224,7 @@ async def test_block_sleeping_device_firmware_unsupported( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert entry.state is ConfigEntryState.LOADED assert ( @@ -299,7 +299,7 @@ async def test_block_sleeping_device_no_periodic_updates( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert get_entity_state(hass, entity_id) == "22.1" @@ -542,7 +542,7 @@ async def test_rpc_update_entry_sleep_period( # Make device online mock_rpc_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert entry.data["sleep_period"] == 600 @@ -550,7 +550,7 @@ async def test_rpc_update_entry_sleep_period( monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 3600) freezer.tick(timedelta(seconds=600 * SLEEP_PERIOD_MULTIPLIER)) async_fire_time_changed(hass) - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert entry.data["sleep_period"] == 3600 @@ -575,14 +575,14 @@ async def test_rpc_sleeping_device_no_periodic_updates( # Make device online mock_rpc_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert get_entity_state(hass, entity_id) == "22.9" # Move time to generate polling freezer.tick(timedelta(seconds=SLEEP_PERIOD_MULTIPLIER * 1000)) async_fire_time_changed(hass) - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert get_entity_state(hass, entity_id) is STATE_UNAVAILABLE @@ -599,7 +599,7 @@ async def test_rpc_sleeping_device_firmware_unsupported( # Make device online mock_rpc_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert entry.state is ConfigEntryState.LOADED assert ( @@ -765,7 +765,7 @@ async def test_rpc_update_entry_fw_ver( # Make device online mock_rpc_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert entry.unique_id device = dev_reg.async_get_device( diff --git a/tests/components/shelly/test_number.py b/tests/components/shelly/test_number.py index 99ad5709d29..0b9fee9e47f 100644 --- a/tests/components/shelly/test_number.py +++ b/tests/components/shelly/test_number.py @@ -44,7 +44,7 @@ async def test_block_number_update( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == "50" @@ -99,7 +99,7 @@ async def test_block_restored_number( # Make device online monkeypatch.setattr(mock_block_device, "initialized", True) mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == "50" @@ -136,7 +136,7 @@ async def test_block_restored_number_no_last_state( # Make device online monkeypatch.setattr(mock_block_device, "initialized", True) mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == "50" @@ -156,7 +156,7 @@ async def test_block_number_set_value( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) mock_block_device.reset_mock() await hass.services.async_call( @@ -217,7 +217,7 @@ async def test_block_set_value_auth_error( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert entry.state is ConfigEntryState.LOADED diff --git a/tests/components/shelly/test_sensor.py b/tests/components/shelly/test_sensor.py index 6151cac10ab..ceaa9b66b8d 100644 --- a/tests/components/shelly/test_sensor.py +++ b/tests/components/shelly/test_sensor.py @@ -165,7 +165,7 @@ async def test_block_sleeping_sensor( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == "22.1" @@ -207,7 +207,7 @@ async def test_block_restored_sleeping_sensor( # Make device online monkeypatch.setattr(mock_block_device, "initialized", True) mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == "22.1" @@ -233,7 +233,7 @@ async def test_block_restored_sleeping_sensor_no_last_state( # Make device online monkeypatch.setattr(mock_block_device, "initialized", True) mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == "22.1" @@ -306,7 +306,7 @@ async def test_block_not_matched_restored_sleeping_sensor( ) monkeypatch.setattr(mock_block_device, "initialized", True) mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == "20.4" @@ -464,7 +464,7 @@ async def test_rpc_sleeping_sensor( # Make device online mock_rpc_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == "22.9" @@ -503,7 +503,7 @@ async def test_rpc_restored_sleeping_sensor( # Make device online monkeypatch.setattr(mock_rpc_device, "initialized", True) mock_rpc_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) # Mock update mock_rpc_device.mock_update() @@ -539,7 +539,7 @@ async def test_rpc_restored_sleeping_sensor_no_last_state( # Make device online monkeypatch.setattr(mock_rpc_device, "initialized", True) mock_rpc_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) # Mock update mock_rpc_device.mock_update() @@ -607,7 +607,7 @@ async def test_rpc_sleeping_update_entity_service( # Make device online mock_rpc_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) state = hass.states.get(entity_id) assert state.state == "22.9" @@ -657,7 +657,7 @@ async def test_block_sleeping_update_entity_service( # Make device online mock_block_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) assert hass.states.get(entity_id).state == "22.1" diff --git a/tests/components/shelly/test_update.py b/tests/components/shelly/test_update.py index 93b0f55c415..0f26fd14d12 100644 --- a/tests/components/shelly/test_update.py +++ b/tests/components/shelly/test_update.py @@ -352,7 +352,7 @@ async def test_rpc_sleeping_update( # Make device online mock_rpc_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) state = hass.states.get(entity_id) assert state.state == STATE_ON @@ -413,7 +413,7 @@ async def test_rpc_restored_sleeping_update( # Make device online monkeypatch.setattr(mock_rpc_device, "initialized", True) mock_rpc_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) # Mock update mock_rpc_device.mock_update() @@ -462,7 +462,7 @@ async def test_rpc_restored_sleeping_update_no_last_state( # Make device online monkeypatch.setattr(mock_rpc_device, "initialized", True) mock_rpc_device.mock_online() - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) # Mock update mock_rpc_device.mock_update()