"""Support for Unifi AP direct access.""" from __future__ import annotations import logging from typing import Any from unifi_ap import UniFiAP, UniFiAPConnectionException, UniFiAPDataException import voluptuous as vol from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA, DeviceScanner, ) from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME from homeassistant.core import HomeAssistant import homeassistant.helpers.config_validation as cv from homeassistant.helpers.typing import ConfigType _LOGGER = logging.getLogger(__name__) DEFAULT_SSH_PORT = 22 PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend( { vol.Required(CONF_HOST): cv.string, vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_USERNAME): cv.string, vol.Optional(CONF_PORT, default=DEFAULT_SSH_PORT): cv.port, } ) def get_scanner(hass: HomeAssistant, config: ConfigType) -> UnifiDeviceScanner | None: """Validate the configuration and return a Unifi direct scanner.""" scanner = UnifiDeviceScanner(config[DOMAIN]) return scanner if scanner.update_clients() else None class UnifiDeviceScanner(DeviceScanner): """Class which queries Unifi wireless access point.""" def __init__(self, config: ConfigType) -> None: """Initialize the scanner.""" self.clients: dict[str, dict[str, Any]] = {} self.ap = UniFiAP( target=config[CONF_HOST], username=config[CONF_USERNAME], password=config[CONF_PASSWORD], port=config[CONF_PORT], ) def scan_devices(self) -> list[str]: """Scan for new devices and return a list with found device IDs.""" self.update_clients() return list(self.clients) def get_device_name(self, device: str) -> str | None: """Return the name of the given device or None if we don't know.""" client_info = self.clients.get(device) if client_info: return client_info.get("hostname") return None def update_clients(self) -> bool: """Update the client info from AP.""" try: self.clients = self.ap.get_clients() except UniFiAPConnectionException: _LOGGER.error("Failed to connect to accesspoint") return False except UniFiAPDataException: _LOGGER.error("Failed to get proper response from accesspoint") return False return True