diff --git a/homeassistant/components/onewire/model.py b/homeassistant/components/onewire/model.py index 2b8734cdcf33..a4285539ec75 100644 --- a/homeassistant/components/onewire/model.py +++ b/homeassistant/components/onewire/model.py @@ -15,3 +15,4 @@ class OWDeviceDescription: id: str path: str type: str | None + parent_id: str | None = None diff --git a/homeassistant/components/onewire/onewirehub.py b/homeassistant/components/onewire/onewirehub.py index 96cc26b82dea..67ce60476b4c 100644 --- a/homeassistant/components/onewire/onewirehub.py +++ b/homeassistant/components/onewire/onewirehub.py @@ -10,7 +10,7 @@ from aio_ownet.exceptions import OWServerProtocolError, OWServerReturnError from aio_ownet.proxy import OWServerStatelessProxy from homeassistant.config_entries import ConfigEntry -from homeassistant.const import ATTR_VIA_DEVICE, CONF_HOST, CONF_PORT +from homeassistant.const import CONF_HOST, CONF_PORT from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import device_registry as dr from homeassistant.helpers.device_registry import DeviceInfo @@ -93,6 +93,16 @@ class OneWireHub: device_registry = dr.async_get(self._hass) for device in devices: device.device_info["sw_version"] = self._version + if device.parent_id is not None: + # Devices are ordered parents-first, so a device's parent is + # already registered by the time we reach the device. + device.device_info["via_device_id"] = ( + dr.async_get_device_id_by_identifier( + self._hass, + (DOMAIN, device.parent_id), + config_entry_id=self._config_entry.entry_id, + ) + ) device_registry.async_get_or_create( config_entry_id=self._config_entry.entry_id, **device.device_info, @@ -147,14 +157,13 @@ async def _discover_devices( name=device_id, serial_number=device_id[3:], ) - if parent_id: - device_info[ATTR_VIA_DEVICE] = (DOMAIN, parent_id) device = OWDeviceDescription( device_info=device_info, id=device_id, family=device_family, path=device_path, type=device_type, + parent_id=parent_id, ) devices.append(device) if device_branches := DEVICE_COUPLERS.get(device_family): diff --git a/tests/components/onewire/snapshots/test_diagnostics.ambr b/tests/components/onewire/snapshots/test_diagnostics.ambr index 1b1d4a0b30bc..65dfda99bac7 100644 --- a/tests/components/onewire/snapshots/test_diagnostics.ambr +++ b/tests/components/onewire/snapshots/test_diagnostics.ambr @@ -18,6 +18,7 @@ }), 'family': 'EF', 'id': 'EF.111111111113', + 'parent_id': None, 'path': '/EF.111111111113/', 'type': 'HB_HUB', }), @@ -60,6 +61,7 @@ }), 'family': 'EF', 'id': 'EF.111111111113', + 'parent_id': None, 'path': '/EF.111111111113/', 'type': 'HB_HUB', }), diff --git a/tests/components/onewire/test_init.py b/tests/components/onewire/test_init.py index 2716c579036d..d1f8be42ed56 100644 --- a/tests/components/onewire/test_init.py +++ b/tests/components/onewire/test_init.py @@ -110,6 +110,30 @@ async def test_registry_delayed( ) +async def test_device_via_device_links( + hass: HomeAssistant, + config_entry: MockConfigEntry, + owproxy: MagicMock, + device_registry: dr.DeviceRegistry, +) -> None: + """Test a coupler branch device links to its parent via via_device_id.""" + # The 1F coupler exposes a 1D device on its "main" branch. + setup_owproxy_mock_devices(owproxy, ["1F.111111111111"]) + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + parent_device = device_registry.async_get_device_by_identifier( + (DOMAIN, "1F.111111111111"), config_entry.entry_id + ) + assert parent_device is not None + + child_device = device_registry.async_get_device_by_identifier( + (DOMAIN, "1D.111111111111"), config_entry.entry_id + ) + assert child_device is not None + assert child_device.via_device_id == parent_device.id + + @patch("homeassistant.components.onewire._PLATFORMS", [Platform.SENSOR]) async def test_registry_cleanup( hass: HomeAssistant,