"""Support for Notion.""" from __future__ import annotations from dataclasses import dataclass from aionotion.bridge.models import Bridge from aionotion.listener.models import Listener, ListenerKind from homeassistant.core import callback from homeassistant.helpers import device_registry as dr from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.entity import EntityDescription from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN, LOGGER from .coordinator import NotionDataUpdateCoordinator @dataclass(frozen=True, kw_only=True) class NotionEntityDescription: """Define an description for Notion entities.""" listener_kind: ListenerKind class NotionEntity(CoordinatorEntity[NotionDataUpdateCoordinator]): """Define a base Notion entity.""" _attr_has_entity_name = True def __init__( self, coordinator: NotionDataUpdateCoordinator, listener_id: str, sensor_id: str, bridge_id: int, description: EntityDescription, ) -> None: """Initialize the entity.""" super().__init__(coordinator) sensor = self.coordinator.data.sensors[sensor_id] self._attr_device_info = DeviceInfo( identifiers={(DOMAIN, sensor.hardware_id)}, manufacturer="Silicon Labs", model=str(sensor.hardware_revision), name=str(sensor.name).capitalize(), sw_version=sensor.firmware_version, ) if bridge := self._async_get_bridge(bridge_id): self._attr_device_info["via_device"] = (DOMAIN, bridge.hardware_id) self._attr_extra_state_attributes = {} self._attr_unique_id = listener_id self._bridge_id = bridge_id self._listener_id = listener_id self._sensor_id = sensor_id self.entity_description = description @property def available(self) -> bool: """Return True if entity is available.""" return ( self.coordinator.last_update_success and self._listener_id in self.coordinator.data.listeners ) @property def listener(self) -> Listener: """Return the listener related to this entity.""" return self.coordinator.data.listeners[self._listener_id] @callback def _async_get_bridge(self, bridge_id: int) -> Bridge | None: """Get a bridge by ID (if it exists).""" if (bridge := self.coordinator.data.bridges.get(bridge_id)) is None: LOGGER.debug("Entity references a non-existent bridge ID: %s", bridge_id) return None return bridge @callback def _async_update_bridge_id(self) -> None: """Update the entity's bridge ID if it has changed. Sensors can move to other bridges based on signal strength, etc. """ sensor = self.coordinator.data.sensors[self._sensor_id] # If the bridge ID hasn't changed, return: if self._bridge_id == sensor.bridge.id: return # If the bridge doesn't exist, return: if (bridge := self._async_get_bridge(sensor.bridge.id)) is None: return self._bridge_id = sensor.bridge.id device_registry = dr.async_get(self.hass) this_device = device_registry.async_get_device( identifiers={(DOMAIN, sensor.hardware_id)} ) bridge = self.coordinator.data.bridges[self._bridge_id] bridge_device = device_registry.async_get_device( identifiers={(DOMAIN, bridge.hardware_id)} ) if not bridge_device or not this_device: return device_registry.async_update_device( this_device.id, via_device_id=bridge_device.id ) @callback def _handle_coordinator_update(self) -> None: """Respond to a DataUpdateCoordinator update.""" if self._listener_id in self.coordinator.data.listeners: self._async_update_bridge_id() super()._handle_coordinator_update()