From 2329db5a05085ef6d7b8e6b00eb380a9a4ad4091 Mon Sep 17 00:00:00 2001 From: Guido Schmitz Date: Sat, 19 Sep 2026 11:25:53 +0200 Subject: [PATCH] Track devolo Home Network Wi-Fi clients via the entity registry (#182327) --- .../devolo_home_network/device_tracker.py | 49 ++++++------------- .../test_device_tracker.py | 25 ++++++++++ 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/homeassistant/components/devolo_home_network/device_tracker.py b/homeassistant/components/devolo_home_network/device_tracker.py index 185e01a09432..4595ad83ee24 100644 --- a/homeassistant/components/devolo_home_network/device_tracker.py +++ b/homeassistant/components/devolo_home_network/device_tracker.py @@ -32,47 +32,30 @@ async def async_setup_entry( str, DevoloDataUpdateCoordinator[dict[str, ConnectedStationInfo]] ] = entry.runtime_data.coordinators registry = er.async_get(hass) - tracked = set() @callback def new_device_callback() -> None: - """Add new devices if needed.""" - new_entities = [] - for mac_address in coordinators[CONNECTED_WIFI_CLIENTS].data: - if mac_address in tracked: - continue - - new_entities.append( - DevoloScannerEntity( - coordinators[CONNECTED_WIFI_CLIENTS], device, mac_address - ) + """Add clients that don't have an entity yet.""" + async_add_entities( + DevoloScannerEntity(coordinators[CONNECTED_WIFI_CLIENTS], device, mac) + for mac in coordinators[CONNECTED_WIFI_CLIENTS].data + if not registry.async_get_entity_id( + DEVICE_TRACKER_DOMAIN, DOMAIN, f"{device.serial_number}_{mac}" ) - tracked.add(mac_address) - async_add_entities(new_entities) + ) @callback def restore_entities() -> None: """Restore clients that are not a part of active clients list.""" - missing = [] - for entity in er.async_entries_for_config_entry(registry, entry.entry_id): - if ( - entity.platform == DOMAIN - and entity.domain == DEVICE_TRACKER_DOMAIN - and ( - mac_address := entity.unique_id.replace( - f"{device.serial_number}_", "" - ) - ) - not in tracked - ): - missing.append( - DevoloScannerEntity( - coordinators[CONNECTED_WIFI_CLIENTS], device, mac_address - ) - ) - tracked.add(mac_address) - - async_add_entities(missing) + async_add_entities( + DevoloScannerEntity( + coordinators[CONNECTED_WIFI_CLIENTS], + device, + entity.unique_id.removeprefix(f"{device.serial_number}_"), + ) + for entity in er.async_entries_for_config_entry(registry, entry.entry_id) + if entity.platform == DOMAIN and entity.domain == DEVICE_TRACKER_DOMAIN + ) restore_entities() new_device_callback() diff --git a/tests/components/devolo_home_network/test_device_tracker.py b/tests/components/devolo_home_network/test_device_tracker.py index 86ce0122c2e6..d278c4714838 100644 --- a/tests/components/devolo_home_network/test_device_tracker.py +++ b/tests/components/devolo_home_network/test_device_tracker.py @@ -95,3 +95,28 @@ async def test_restoring_clients( state = hass.states.get(entity_id) assert state is not None assert state.state == STATE_NOT_HOME + + +@pytest.mark.usefixtures("mock_device", "entity_registry_enabled_by_default") +async def test_recreating_removed_entity( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + freezer: FrozenDateTimeFactory, +) -> None: + """Test that the entity registry is the source of truth for tracked clients.""" + entity_id = ( + f"{DEVICE_TRACKER_DOMAIN}.{STATION.mac_address.lower().replace(':', '_')}" + ) + entry = configure_integration(hass) + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + assert entity_registry.async_get(entity_id) is not None + + entity_registry.async_remove(entity_id) + await hass.async_block_till_done() + assert entity_registry.async_get(entity_id) is None + + freezer.tick(SHORT_UPDATE_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + assert entity_registry.async_get(entity_id) is not None