Files
ha-reticulum/custom_components/reticulum/entity.py
Artem Eliseev 6316af863b Replace the deprecated via_device with via_device_id
Home Assistant 2026.9 deprecates the `via_device` (domain, identifier)
tuple in favour of `via_device_id`, which takes the parent device's
registry id; `via_device` stops working in 2027.8.0.

Register the hub device explicitly in async_setup_entry before the
platforms are forwarded, so the per-identity entities can look it up and
pass its `.id`. The hub device info moves into a shared helper so both
call sites describe the same device.
2026-09-07 21:54:51 +03:00

101 lines
3.1 KiB
Python

"""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()