"""Base entities for the Reticulum integration.""" from __future__ import annotations from homeassistant.config_entries import ConfigEntry, ConfigSubentry from homeassistant.core import callback from homeassistant.helpers.device_registry import ( DeviceEntryType, DeviceInfo, async_get as async_get_device_registry, ) from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity import Entity from .const import DOMAIN, identity_signal, stack_signal from .reticulum_client import IdentityManager, ReticulumStack def hub_device_info(entry: ConfigEntry) -> DeviceInfo: """Device info for the stack (hub) device. Shared with ``async_setup_entry``, which registers this device up front so the per-identity devices can reference it by registry id. """ return DeviceInfo( identifiers={(DOMAIN, entry.entry_id)}, name="Reticulum", manufacturer="Reticulum Network Stack", model="RNS stack", entry_type=DeviceEntryType.SERVICE, configuration_url="https://reticulum.network/", ) class ReticulumStackEntity(Entity): """Base for hub (stack-level) entities.""" _attr_should_poll = False _attr_has_entity_name = True def __init__(self, stack: ReticulumStack, entry: ConfigEntry) -> None: self._stack = stack self._entry = entry self._attr_device_info = hub_device_info(entry) async def async_added_to_hass(self) -> None: self.async_on_remove( async_dispatcher_connect( self.hass, stack_signal(self._entry.entry_id), self._handle_update ) ) @callback def _handle_update(self) -> None: self.async_write_ha_state() class ReticulumIdentityEntity(Entity): """Base for per-identity (subentry) entities.""" _attr_should_poll = False _attr_has_entity_name = True def __init__( self, manager: IdentityManager, entry: ConfigEntry, subentry: ConfigSubentry, ) -> None: self._manager = manager self._entry = entry self._subentry = subentry device_info = DeviceInfo( identifiers={(DOMAIN, subentry.subentry_id)}, name=subentry.title, manufacturer="Reticulum Network Stack", model="LXMF identity", entry_type=DeviceEntryType.SERVICE, ) # `via_device_id` takes the parent's registry id, not its identifiers, so # look up the hub device registered by async_setup_entry. hub = async_get_device_registry(manager.hass).async_get_device_by_identifier( (DOMAIN, entry.entry_id), entry.entry_id ) if hub is not None: device_info["via_device_id"] = hub.id self._attr_device_info = device_info async def async_added_to_hass(self) -> None: self.async_on_remove( async_dispatcher_connect( self.hass, identity_signal(self._subentry.subentry_id), self._handle_update, ) ) @callback def _handle_update(self) -> None: self.async_write_ha_state()