"""Support for Mikrotik routers as device tracker.""" from __future__ import annotations from typing import Any from homeassistant.components.device_tracker import ( DOMAIN as DEVICE_TRACKER, ScannerEntity, SourceType, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import entity_registry as er from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity import homeassistant.util.dt as dt_util from .const import DOMAIN from .hub import Device, MikrotikDataUpdateCoordinator async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up device tracker for Mikrotik component.""" coordinator: MikrotikDataUpdateCoordinator = hass.data[DOMAIN][ config_entry.entry_id ] tracked: dict[str, MikrotikDataUpdateCoordinatorTracker] = {} registry = er.async_get(hass) # Restore clients that is not a part of active clients list. for entity in registry.entities.values(): if ( entity.config_entry_id == config_entry.entry_id and entity.domain == DEVICE_TRACKER ): if ( entity.unique_id in coordinator.api.devices or entity.unique_id not in coordinator.api.all_devices ): continue coordinator.api.restore_device(entity.unique_id) @callback def update_hub() -> None: """Update the status of the device.""" update_items(coordinator, async_add_entities, tracked) config_entry.async_on_unload(coordinator.async_add_listener(update_hub)) update_hub() @callback def update_items( coordinator: MikrotikDataUpdateCoordinator, async_add_entities: AddEntitiesCallback, tracked: dict[str, MikrotikDataUpdateCoordinatorTracker], ) -> None: """Update tracked device state from the hub.""" new_tracked: list[MikrotikDataUpdateCoordinatorTracker] = [] for mac, device in coordinator.api.devices.items(): if mac not in tracked: tracked[mac] = MikrotikDataUpdateCoordinatorTracker(device, coordinator) new_tracked.append(tracked[mac]) async_add_entities(new_tracked) class MikrotikDataUpdateCoordinatorTracker( CoordinatorEntity[MikrotikDataUpdateCoordinator], ScannerEntity ): """Representation of network device.""" def __init__( self, device: Device, coordinator: MikrotikDataUpdateCoordinator ) -> None: """Initialize the tracked device.""" super().__init__(coordinator) self.device = device self._attr_name = device.name self._attr_unique_id = device.mac @property def is_connected(self) -> bool: """Return true if the client is connected to the network.""" if ( self.device.last_seen and (dt_util.utcnow() - self.device.last_seen) < self.coordinator.option_detection_time ): return True return False @property def source_type(self) -> SourceType: """Return the source type of the client.""" return SourceType.ROUTER @property def hostname(self) -> str: """Return the hostname of the client.""" return self.device.name @property def mac_address(self) -> str: """Return the mac address of the client.""" return self.device.mac @property def ip_address(self) -> str | None: """Return the mac address of the client.""" return self.device.ip_address @property def extra_state_attributes(self) -> dict[str, Any] | None: """Return the device state attributes.""" return self.device.attrs if self.is_connected else None