core/homeassistant/components/ruckus_unleashed/device_tracker.py

133 lines
4.0 KiB
Python

"""Support for Ruckus Unleashed devices."""
from __future__ import annotations
from homeassistant.components.device_tracker import SOURCE_TYPE_ROUTER
from homeassistant.components.device_tracker.config_entry import ScannerEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import (
API_ACCESS_POINT,
API_CLIENTS,
API_NAME,
COORDINATOR,
DOMAIN,
MANUFACTURER,
UNDO_UPDATE_LISTENERS,
)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities
) -> None:
"""Set up device tracker for Ruckus Unleashed component."""
coordinator = hass.data[DOMAIN][entry.entry_id][COORDINATOR]
tracked = set()
@callback
def router_update():
"""Update the values of the router."""
add_new_entities(coordinator, async_add_entities, tracked)
router_update()
hass.data[DOMAIN][entry.entry_id][UNDO_UPDATE_LISTENERS].append(
coordinator.async_add_listener(router_update)
)
registry = await entity_registry.async_get_registry(hass)
restore_entities(registry, coordinator, entry, async_add_entities, tracked)
@callback
def add_new_entities(coordinator, async_add_entities, tracked):
"""Add new tracker entities from the router."""
new_tracked = []
for mac in coordinator.data[API_CLIENTS]:
if mac in tracked:
continue
device = coordinator.data[API_CLIENTS][mac]
new_tracked.append(RuckusUnleashedDevice(coordinator, mac, device[API_NAME]))
tracked.add(mac)
if new_tracked:
async_add_entities(new_tracked)
@callback
def restore_entities(registry, coordinator, entry, async_add_entities, tracked):
"""Restore clients that are not a part of active clients list."""
missing = []
for entity in registry.entities.values():
if (
entity.config_entry_id == entry.entry_id
and entity.platform == DOMAIN
and entity.unique_id not in coordinator.data[API_CLIENTS]
):
missing.append(
RuckusUnleashedDevice(
coordinator, entity.unique_id, entity.original_name
)
)
tracked.add(entity.unique_id)
if missing:
async_add_entities(missing)
class RuckusUnleashedDevice(CoordinatorEntity, ScannerEntity):
"""Representation of a Ruckus Unleashed client."""
def __init__(self, coordinator, mac, name) -> None:
"""Initialize a Ruckus Unleashed client."""
super().__init__(coordinator)
self._mac = mac
self._name = name
@property
def unique_id(self) -> str:
"""Return a unique ID."""
return self._mac
@property
def name(self) -> str:
"""Return the name."""
if self.is_connected:
return (
self.coordinator.data[API_CLIENTS][self._mac][API_NAME]
or f"{MANUFACTURER} {self._mac}"
)
return self._name
@property
def is_connected(self) -> bool:
"""Return true if the device is connected to the network."""
return self._mac in self.coordinator.data[API_CLIENTS]
@property
def source_type(self) -> str:
"""Return the source type."""
return SOURCE_TYPE_ROUTER
@property
def device_info(self) -> DeviceInfo | None:
"""Return the device information."""
if self.is_connected:
return {
"name": self.name,
"connections": {(CONNECTION_NETWORK_MAC, self._mac)},
"via_device": (
CONNECTION_NETWORK_MAC,
self.coordinator.data[API_CLIENTS][self._mac][API_ACCESS_POINT],
),
}
return None