diff --git a/homeassistant/components/smartthings/__init__.py b/homeassistant/components/smartthings/__init__.py index a5e138639de..b3f3e93eeb1 100644 --- a/homeassistant/components/smartthings/__init__.py +++ b/homeassistant/components/smartthings/__init__.py @@ -20,6 +20,7 @@ from pysmartthings import ( SmartThingsSinkError, Status, ) +from pysmartthings.models import Lifecycle from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( @@ -188,6 +189,22 @@ async def async_setup_entry(hass: HomeAssistant, entry: SmartThingsConfigEntry) for scene in await client.get_scenes(location_id=entry.data[CONF_LOCATION_ID]) } + def handle_deleted_device(device_id: str) -> None: + """Handle a deleted device.""" + dev_entry = device_registry.async_get_device( + identifiers={(DOMAIN, device_id)}, + ) + if dev_entry is not None: + device_registry.async_update_device( + dev_entry.id, remove_config_entry_id=entry.entry_id + ) + + entry.async_on_unload( + client.add_device_lifecycle_event_listener( + Lifecycle.DELETE, handle_deleted_device + ) + ) + entry.runtime_data = SmartThingsData( devices={ device_id: device diff --git a/homeassistant/components/smartthings/quality_scale.yaml b/homeassistant/components/smartthings/quality_scale.yaml index 8a902094687..be8a9039617 100644 --- a/homeassistant/components/smartthings/quality_scale.yaml +++ b/homeassistant/components/smartthings/quality_scale.yaml @@ -73,7 +73,7 @@ rules: status: exempt comment: | This integration doesn't have any cases where raising an issue is needed. - stale-devices: todo + stale-devices: done # Platinum async-dependency: done inject-websession: done diff --git a/tests/components/smartthings/test_init.py b/tests/components/smartthings/test_init.py index 3eaa038027d..c0d0b8b5840 100644 --- a/tests/components/smartthings/test_init.py +++ b/tests/components/smartthings/test_init.py @@ -10,10 +10,11 @@ from pysmartthings import ( DeviceStatus, SmartThingsSinkError, ) -from pysmartthings.models import Subscription +from pysmartthings.models import Lifecycle, Subscription import pytest from syrupy import SnapshotAssertion +from homeassistant.components.climate import HVACMode from homeassistant.components.smartthings import EVENT_BUTTON from homeassistant.components.smartthings.const import CONF_SUBSCRIPTION_ID, DOMAIN from homeassistant.config_entries import ConfigEntryState @@ -345,3 +346,23 @@ async def test_hub_via_device( ).via_device_id == hub_device.id ) + + +@pytest.mark.parametrize("device_fixture", ["da_ac_rac_000001"]) +async def test_deleted_device_runtime( + hass: HomeAssistant, + devices: AsyncMock, + mock_config_entry: MockConfigEntry, + snapshot: SnapshotAssertion, +) -> None: + """Test devices that are deleted in runtime.""" + await setup_integration(hass, mock_config_entry) + + assert hass.states.get("climate.ac_office_granit").state == HVACMode.OFF + + for call in devices.add_device_lifecycle_event_listener.call_args_list: + if call[0][0] == Lifecycle.DELETE: + call[0][1]("96a5ef74-5832-a84b-f1f7-ca799957065d") + await hass.async_block_till_done() + + assert hass.states.get("climate.ac_office_granit") is None