mirror of
https://github.com/home-assistant/core.git
synced 2025-11-06 01:19:29 +00:00
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Norbert Rittel <norbert@rittel.de> Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
128 lines
4.6 KiB
Python
128 lines
4.6 KiB
Python
"""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()
|