"""Platform for Device tracker integration.""" from fing_agent_api.models import Device from homeassistant.components.device_tracker import ScannerEntity from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import entity_registry as er from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity from . import FingConfigEntry from .coordinator import FingDataUpdateCoordinator from .utils import get_icon_from_type async def async_setup_entry( hass: HomeAssistant, config_entry: FingConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Add sensors for passed config_entry in HA.""" coordinator = config_entry.runtime_data entity_registry = er.async_get(hass) tracked_devices: set[str] = set() @callback def add_entities() -> None: latest_devices = set(coordinator.data.devices.keys()) devices_to_remove = tracked_devices - set(latest_devices) devices_to_add = set(latest_devices) - tracked_devices entities_to_remove = [] for entity_entry in entity_registry.entities.values(): if entity_entry.config_entry_id != config_entry.entry_id: continue try: _, mac = entity_entry.unique_id.rsplit("-", 1) if mac in devices_to_remove: entities_to_remove.append(entity_entry.entity_id) except ValueError: continue for entity_id in entities_to_remove: entity_registry.async_remove(entity_id) entities_to_add = [] for mac_addr in devices_to_add: device = coordinator.data.devices[mac_addr] entities_to_add.append(FingTrackedDevice(coordinator, device)) tracked_devices.clear() tracked_devices.update(latest_devices) async_add_entities(entities_to_add) add_entities() config_entry.async_on_unload(coordinator.async_add_listener(add_entities)) class FingTrackedDevice(CoordinatorEntity[FingDataUpdateCoordinator], ScannerEntity): """Represent a tracked device.""" _attr_has_entity_name = True def __init__(self, coordinator: FingDataUpdateCoordinator, device: Device) -> None: """Set up FingDevice entity.""" super().__init__(coordinator) self._device = device agent_id = coordinator.data.network_id if coordinator.data.agent_info is not None: agent_id = coordinator.data.agent_info.agent_id self._attr_mac_address = self._device.mac self._attr_unique_id = f"{agent_id}-{self._attr_mac_address}" self._attr_name = self._device.name self._attr_icon = get_icon_from_type(self._device.type) @property def is_connected(self) -> bool: """Return true if the device is connected to the network.""" return self._device.active @property def ip_address(self) -> str | None: """Return the primary ip address of the device.""" return self._device.ip[0] if self._device.ip else None @property def entity_registry_enabled_default(self) -> bool: """Enable entity by default.""" return True @property def unique_id(self) -> str | None: """Return the unique ID of the entity.""" return self._attr_unique_id def check_for_updates(self, new_device: Device) -> bool: """Return true if the device has updates.""" new_device_ip = new_device.ip[0] if new_device.ip else None current_device_ip = self._device.ip[0] if self._device.ip else None return ( current_device_ip != new_device_ip or self._device.active != new_device.active or self._device.type != new_device.type or self._attr_name != new_device.name or self._attr_icon != get_icon_from_type(new_device.type) ) @callback def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" updated_device_data = self.coordinator.data.devices.get(self._device.mac) if updated_device_data is not None and self.check_for_updates( updated_device_data ): self._device = updated_device_data self._attr_name = updated_device_data.name self._attr_icon = get_icon_from_type(updated_device_data.type) er.async_get(self.hass).async_update_entity( entity_id=self.entity_id, original_name=self._attr_name, original_icon=self._attr_icon, ) self.async_write_ha_state()