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.
This commit is contained in:
@@ -22,6 +22,7 @@ from homeassistant.core import (
|
|||||||
)
|
)
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
|
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
|
from homeassistant.helpers import device_registry as dr
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
@@ -62,6 +63,7 @@ from .const import (
|
|||||||
STORAGE_SUBDIR,
|
STORAGE_SUBDIR,
|
||||||
SUBENTRY_TYPE_IDENTITY,
|
SUBENTRY_TYPE_IDENTITY,
|
||||||
)
|
)
|
||||||
|
from .entity import hub_device_info
|
||||||
from .reticulum_client import (
|
from .reticulum_client import (
|
||||||
IdentityManager,
|
IdentityManager,
|
||||||
ReticulumError,
|
ReticulumError,
|
||||||
@@ -130,6 +132,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
)
|
)
|
||||||
runtime.identities[subentry.subentry_id] = manager
|
runtime.identities[subentry.subentry_id] = manager
|
||||||
|
|
||||||
|
# Register the hub device before the platforms, so the per-identity devices can
|
||||||
|
# link to it with `via_device_id`.
|
||||||
|
dr.async_get(hass).async_get_or_create(
|
||||||
|
config_entry_id=entry.entry_id, **hub_device_info(entry)
|
||||||
|
)
|
||||||
|
|
||||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
|
|
||||||
# Per-identity announce + periodic schedules.
|
# Per-identity announce + periodic schedules.
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry, ConfigSubentry
|
from homeassistant.config_entries import ConfigEntry, ConfigSubentry
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
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.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
@@ -12,6 +16,22 @@ from .const import DOMAIN, identity_signal, stack_signal
|
|||||||
from .reticulum_client import IdentityManager, ReticulumStack
|
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):
|
class ReticulumStackEntity(Entity):
|
||||||
"""Base for hub (stack-level) entities."""
|
"""Base for hub (stack-level) entities."""
|
||||||
|
|
||||||
@@ -21,14 +41,7 @@ class ReticulumStackEntity(Entity):
|
|||||||
def __init__(self, stack: ReticulumStack, entry: ConfigEntry) -> None:
|
def __init__(self, stack: ReticulumStack, entry: ConfigEntry) -> None:
|
||||||
self._stack = stack
|
self._stack = stack
|
||||||
self._entry = entry
|
self._entry = entry
|
||||||
self._attr_device_info = DeviceInfo(
|
self._attr_device_info = hub_device_info(entry)
|
||||||
identifiers={(DOMAIN, entry.entry_id)},
|
|
||||||
name="Reticulum",
|
|
||||||
manufacturer="Reticulum Network Stack",
|
|
||||||
model="RNS stack",
|
|
||||||
entry_type=DeviceEntryType.SERVICE,
|
|
||||||
configuration_url="https://reticulum.network/",
|
|
||||||
)
|
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
@@ -57,14 +70,21 @@ class ReticulumIdentityEntity(Entity):
|
|||||||
self._manager = manager
|
self._manager = manager
|
||||||
self._entry = entry
|
self._entry = entry
|
||||||
self._subentry = subentry
|
self._subentry = subentry
|
||||||
self._attr_device_info = DeviceInfo(
|
device_info = DeviceInfo(
|
||||||
identifiers={(DOMAIN, subentry.subentry_id)},
|
identifiers={(DOMAIN, subentry.subentry_id)},
|
||||||
name=subentry.title,
|
name=subentry.title,
|
||||||
manufacturer="Reticulum Network Stack",
|
manufacturer="Reticulum Network Stack",
|
||||||
model="LXMF identity",
|
model="LXMF identity",
|
||||||
entry_type=DeviceEntryType.SERVICE,
|
entry_type=DeviceEntryType.SERVICE,
|
||||||
via_device=(DOMAIN, entry.entry_id),
|
|
||||||
)
|
)
|
||||||
|
# `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:
|
async def async_added_to_hass(self) -> None:
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
|
|||||||
Reference in New Issue
Block a user