"""Base entity and device info for ninlight lamps.""" from __future__ import annotations from typing import Any from homeassistant.helpers import device_registry as dr from homeassistant.helpers.device_registry import DeviceInfo, format_mac from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN from .coordinator import NinlightCoordinator def device_name(info: dict[str, Any]) -> str: """The lamp's own name, else ' '.""" name = str(info.get("name") or "").strip() if name: return name mac4 = format_mac(info["mac"]).replace(":", "")[-4:] product = info.get("product_name") or info["device_type"] return f"{product} {mac4}" class NinlightEntity(CoordinatorEntity[NinlightCoordinator]): """Common base: unique id from the MAC, one device per lamp.""" _attr_has_entity_name = True def __init__(self, coordinator: NinlightCoordinator, key: str) -> None: super().__init__(coordinator) info = coordinator.data.info mac = format_mac(info["mac"]) self._attr_unique_id = f"{mac}_{key}" self._attr_device_info = DeviceInfo( identifiers={(DOMAIN, mac)}, connections={(dr.CONNECTION_NETWORK_MAC, mac)}, manufacturer="ninlight", model=info.get("product_name") or None, model_id=info["device_type"], name=device_name(info), sw_version=info["fw_version"], ) class NinlightSacnEntity(NinlightEntity): """Base for entities backed by the lamp's sACN settings. Firmware older than the sACN feature answers system/settings without a "sacn" block. Those entities are still created - so they come to life on the next poll after such a lamp is updated, without reloading the integration - but they report themselves unavailable until the block shows up. """ @property def available(self) -> bool: return super().available and self.coordinator.data.sacn is not None @property def sacn(self) -> dict[str, Any]: """The lamp's sACN settings; empty while the lamp does not report them.""" return self.coordinator.data.sacn or {}