Add auto device removal handling to Whisker (#165709)

This commit is contained in:
Nathan Spencer
2026-03-16 12:01:37 -06:00
committed by GitHub
parent bf23fc5887
commit 00b0da7d26
3 changed files with 31 additions and 9 deletions

View File

@@ -13,6 +13,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
@@ -43,6 +44,7 @@ class LitterRobotDataUpdateCoordinator(DataUpdateCoordinator[None]):
)
self.account = Account(websession=async_get_clientsession(hass))
self.previous_members: set[str] = set()
async def _async_update_data(self) -> None:
"""Update all device states from the Litter-Robot API."""
@@ -63,6 +65,22 @@ class LitterRobotDataUpdateCoordinator(DataUpdateCoordinator[None]):
translation_placeholders={"error": str(ex)},
) from ex
current_members = {robot.serial for robot in self.account.robots} | {
pet.id for pet in self.account.pets
}
if stale_members := self.previous_members - current_members:
device_registry = dr.async_get(self.hass)
for device_id in stale_members:
device = device_registry.async_get_device(
identifiers={(DOMAIN, device_id)}
)
if device:
device_registry.async_update_device(
device_id=device.id,
remove_config_entry_id=self.config_entry.entry_id,
)
self.previous_members = current_members
async def _async_setup(self) -> None:
"""Set up the coordinator."""
try:

View File

@@ -64,12 +64,7 @@ rules:
status: done
comment: |
This integration doesn't have any cases where raising an issue is needed
stale-devices:
status: todo
comment: |
Currently handled via async_remove_config_entry_device,
but we should be able to remove devices automatically
stale-devices: done
# Platinum
async-dependency: done
inject-websession: done

View File

@@ -256,12 +256,12 @@ async def test_dynamic_devices(
device_registry: dr.DeviceRegistry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test new device found."""
"""Test dynamic addition of new devices and removal of stale devices."""
delta_time = timedelta(seconds=305) # 5 minutes + 5 delta seconds
entry = await setup_integration(hass, mock_account)
# First check -> there is 1 device in total
# First check -> 1 device created
assert len(dr.async_entries_for_config_entry(device_registry, entry.entry_id)) == 1
mock_account.robots.extend([LitterRobot4(data=ROBOT_4_DATA, account=mock_account)])
@@ -270,5 +270,14 @@ async def test_dynamic_devices(
async_fire_time_changed(hass)
await hass.async_block_till_done()
# Second check -> added one device
# Second check -> added 1 device
assert len(dr.async_entries_for_config_entry(device_registry, entry.entry_id)) == 2
mock_account.robots.pop(0)
freezer.tick(delta_time)
async_fire_time_changed(hass)
await hass.async_block_till_done()
# Third check -> removed 1 device
assert len(dr.async_entries_for_config_entry(device_registry, entry.entry_id)) == 1