mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Rework and simplify the cleanup of orphan AVM Fritz!Tools entities (#117706)
This commit is contained in:
parent
3d15e15e59
commit
916c6a2f46
@ -28,11 +28,11 @@ from homeassistant.components.device_tracker import (
|
|||||||
DEFAULT_CONSIDER_HOME,
|
DEFAULT_CONSIDER_HOME,
|
||||||
DOMAIN as DEVICE_TRACKER_DOMAIN,
|
DOMAIN as DEVICE_TRACKER_DOMAIN,
|
||||||
)
|
)
|
||||||
from homeassistant.components.switch import DOMAIN as DEVICE_SWITCH_DOMAIN
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
from homeassistant.core import HomeAssistant, ServiceCall
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
|
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
from homeassistant.helpers.typing import StateType
|
from homeassistant.helpers.typing import StateType
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
@ -77,13 +77,6 @@ def device_filter_out_from_trackers(
|
|||||||
return bool(reason)
|
return bool(reason)
|
||||||
|
|
||||||
|
|
||||||
def _cleanup_entity_filter(device: er.RegistryEntry) -> bool:
|
|
||||||
"""Filter only relevant entities."""
|
|
||||||
return device.domain == DEVICE_TRACKER_DOMAIN or (
|
|
||||||
device.domain == DEVICE_SWITCH_DOMAIN and "_internet_access" in device.entity_id
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _ha_is_stopping(activity: str) -> None:
|
def _ha_is_stopping(activity: str) -> None:
|
||||||
"""Inform that HA is stopping."""
|
"""Inform that HA is stopping."""
|
||||||
_LOGGER.info("Cannot execute %s: HomeAssistant is shutting down", activity)
|
_LOGGER.info("Cannot execute %s: HomeAssistant is shutting down", activity)
|
||||||
@ -169,6 +162,8 @@ class UpdateCoordinatorDataType(TypedDict):
|
|||||||
class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
|
class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
|
||||||
"""FritzBoxTools class."""
|
"""FritzBoxTools class."""
|
||||||
|
|
||||||
|
config_entry: ConfigEntry
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -649,71 +644,37 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
|
|||||||
self.fritz_guest_wifi.set_password, password, length
|
self.fritz_guest_wifi.set_password, password, length
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_trigger_cleanup(
|
async def async_trigger_cleanup(self) -> None:
|
||||||
self, config_entry: ConfigEntry | None = None
|
|
||||||
) -> None:
|
|
||||||
"""Trigger device trackers cleanup."""
|
"""Trigger device trackers cleanup."""
|
||||||
device_hosts = await self._async_update_hosts_info()
|
device_hosts = await self._async_update_hosts_info()
|
||||||
entity_reg: er.EntityRegistry = er.async_get(self.hass)
|
entity_reg: er.EntityRegistry = er.async_get(self.hass)
|
||||||
|
config_entry = self.config_entry
|
||||||
|
|
||||||
if config_entry is None:
|
entities: list[er.RegistryEntry] = er.async_entries_for_config_entry(
|
||||||
if self.config_entry is None:
|
|
||||||
return
|
|
||||||
config_entry = self.config_entry
|
|
||||||
|
|
||||||
ha_entity_reg_list: list[er.RegistryEntry] = er.async_entries_for_config_entry(
|
|
||||||
entity_reg, config_entry.entry_id
|
entity_reg, config_entry.entry_id
|
||||||
)
|
)
|
||||||
entities_removed: bool = False
|
|
||||||
|
|
||||||
device_hosts_macs = set()
|
orphan_macs: set[str] = set()
|
||||||
device_hosts_names = set()
|
for entity in entities:
|
||||||
for mac, device in device_hosts.items():
|
entry_mac = entity.unique_id.split("_")[0]
|
||||||
device_hosts_macs.add(mac)
|
if (
|
||||||
device_hosts_names.add(device.name)
|
entity.domain == DEVICE_TRACKER_DOMAIN
|
||||||
|
or "_internet_access" in entity.unique_id
|
||||||
for entry in ha_entity_reg_list:
|
) and entry_mac not in device_hosts:
|
||||||
if entry.original_name is None:
|
_LOGGER.info("Removing orphan entity entry %s", entity.entity_id)
|
||||||
continue
|
orphan_macs.add(entry_mac)
|
||||||
entry_name = entry.name or entry.original_name
|
entity_reg.async_remove(entity.entity_id)
|
||||||
entry_host = entry_name.split(" ")[0]
|
|
||||||
entry_mac = entry.unique_id.split("_")[0]
|
|
||||||
|
|
||||||
if not _cleanup_entity_filter(entry) or (
|
|
||||||
entry_mac in device_hosts_macs and entry_host in device_hosts_names
|
|
||||||
):
|
|
||||||
_LOGGER.debug(
|
|
||||||
"Skipping entity %s [mac=%s, host=%s]",
|
|
||||||
entry_name,
|
|
||||||
entry_mac,
|
|
||||||
entry_host,
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
_LOGGER.info("Removing entity: %s", entry_name)
|
|
||||||
entity_reg.async_remove(entry.entity_id)
|
|
||||||
entities_removed = True
|
|
||||||
|
|
||||||
if entities_removed:
|
|
||||||
self._async_remove_empty_devices(entity_reg, config_entry)
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def _async_remove_empty_devices(
|
|
||||||
self, entity_reg: er.EntityRegistry, config_entry: ConfigEntry
|
|
||||||
) -> None:
|
|
||||||
"""Remove devices with no entities."""
|
|
||||||
|
|
||||||
device_reg = dr.async_get(self.hass)
|
device_reg = dr.async_get(self.hass)
|
||||||
device_list = dr.async_entries_for_config_entry(
|
orphan_connections = {(CONNECTION_NETWORK_MAC, mac) for mac in orphan_macs}
|
||||||
|
for device in dr.async_entries_for_config_entry(
|
||||||
device_reg, config_entry.entry_id
|
device_reg, config_entry.entry_id
|
||||||
)
|
):
|
||||||
for device_entry in device_list:
|
if any(con in device.connections for con in orphan_connections):
|
||||||
if not er.async_entries_for_device(
|
_LOGGER.debug("Removing obsolete device entry %s", device.name)
|
||||||
entity_reg,
|
device_reg.async_update_device(
|
||||||
device_entry.id,
|
device.id, remove_config_entry_id=config_entry.entry_id
|
||||||
include_disabled_entities=True,
|
)
|
||||||
):
|
|
||||||
_LOGGER.info("Removing device: %s", device_entry.name)
|
|
||||||
device_reg.async_remove_device(device_entry.id)
|
|
||||||
|
|
||||||
async def service_fritzbox(
|
async def service_fritzbox(
|
||||||
self, service_call: ServiceCall, config_entry: ConfigEntry
|
self, service_call: ServiceCall, config_entry: ConfigEntry
|
||||||
|
Loading…
x
Reference in New Issue
Block a user