diff --git a/homeassistant/components/melnor/__init__.py b/homeassistant/components/melnor/__init__.py index 4cc112509d99..312a28b562ae 100644 --- a/homeassistant/components/melnor/__init__.py +++ b/homeassistant/components/melnor/__init__.py @@ -7,7 +7,10 @@ from homeassistant.components.bluetooth.match import BluetoothCallbackMatcher from homeassistant.const import CONF_ADDRESS, Platform from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady +from homeassistant.helpers import device_registry as dr +from homeassistant.helpers.device_registry import CONNECTION_BLUETOOTH +from .const import DOMAIN from .coordinator import MelnorConfigEntry, MelnorDataUpdateCoordinator PLATFORMS: list[Platform] = [ @@ -54,6 +57,18 @@ async def async_setup_entry(hass: HomeAssistant, entry: MelnorConfigEntry) -> bo await coordinator.async_config_entry_first_refresh() entry.runtime_data = coordinator + + # Register the parent device up front so zone entities can deterministically + # resolve its via_device_id, regardless of platform setup order. + dr.async_get(hass).async_get_or_create( + config_entry_id=entry.entry_id, + identifiers={(DOMAIN, device.mac)}, + connections={(CONNECTION_BLUETOOTH, device.mac)}, + manufacturer="Melnor", + model=device.model, + name=device.name, + ) + await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True diff --git a/homeassistant/components/melnor/entity.py b/homeassistant/components/melnor/entity.py index 35e804111f48..ac85df205c85 100644 --- a/homeassistant/components/melnor/entity.py +++ b/homeassistant/components/melnor/entity.py @@ -7,6 +7,7 @@ from melnor_bluetooth.device import Device, Valve from homeassistant.components.number import EntityDescription from homeassistant.core import callback +from homeassistant.helpers import device_registry as dr from homeassistant.helpers.device_registry import CONNECTION_BLUETOOTH, DeviceInfo from homeassistant.helpers.update_coordinator import CoordinatorEntity @@ -76,7 +77,11 @@ class MelnorZoneEntity(MelnorBluetoothEntity): identifiers={(DOMAIN, f"{self._device.mac}-zone{self._valve.id}")}, manufacturer="Melnor", name=f"Zone {valve.id + 1}", - via_device=(DOMAIN, self._device.mac), + via_device_id=dr.async_get_device_id_by_identifier( + coordinator.hass, + (DOMAIN, self._device.mac), + config_entry_id=coordinator.config_entry.entry_id, + ), ) diff --git a/tests/components/melnor/test_init.py b/tests/components/melnor/test_init.py index 229d1b3cc337..6af51b4dbde8 100644 --- a/tests/components/melnor/test_init.py +++ b/tests/components/melnor/test_init.py @@ -35,3 +35,29 @@ async def test_device_registry( identifiers={(DOMAIN, FAKE_ADDRESS_1)} ) assert device_entry == snapshot + + +async def test_zone_device_via_device( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, +) -> None: + """Test that zone devices link to the parent device via via_device_id.""" + entry = mock_config_entry(hass) + + with ( + patch_async_ble_device_from_address(), + patch_melnor_device(), + patch_async_register_callback(), + ): + assert await hass.config_entries.async_setup(entry.entry_id) + + parent_device = device_registry.async_get_device_by_identifier( + (DOMAIN, FAKE_ADDRESS_1), entry.entry_id + ) + zone_device = device_registry.async_get_device_by_identifier( + (DOMAIN, f"{FAKE_ADDRESS_1}-zone0"), entry.entry_id + ) + + assert parent_device is not None + assert zone_device is not None + assert zone_device.via_device_id == parent_device.id