diff --git a/homeassistant/components/nexia/__init__.py b/homeassistant/components/nexia/__init__.py index 873fccf57d02..b129e792361a 100644 --- a/homeassistant/components/nexia/__init__.py +++ b/homeassistant/components/nexia/__init__.py @@ -62,20 +62,33 @@ async def async_setup_entry(hass: HomeAssistant, entry: NexiaConfigEntry) -> boo await coordinator.async_config_entry_first_refresh() entry.runtime_data = coordinator - # Register thermostat devices before forwarding platforms so zone sub-devices - # can resolve their via_device_id regardless of platform setup order. - device_registry = dr.async_get(hass) - for thermostat_id in nexia_home.get_thermostat_ids(): - device_registry.async_get_or_create( - config_entry_id=entry.entry_id, - identifiers={(DOMAIN, thermostat_id)}, # type: ignore[arg-type] # until fix issue #139773 - ) + _preregister_devices(hass, entry, nexia_home) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True +def _preregister_devices( + hass: HomeAssistant, entry: NexiaConfigEntry, nexia_home: NexiaHome +) -> None: + """Register devices before forwarding platforms so sub-devices resolve via_device_id regardless of setup order.""" + device_registry = dr.async_get(hass) + for thermostat_id in nexia_home.get_thermostat_ids(): + thermostat = nexia_home.get_thermostat_by_id(thermostat_id) + device_registry.async_get_or_create( + config_entry_id=entry.entry_id, + identifiers={(DOMAIN, thermostat_id)}, # type: ignore[arg-type] # until fix issue #139773 + ) + for zone_id in thermostat.get_zone_ids(): + zone = thermostat.get_zone_by_id(zone_id) + device_registry.async_get_or_create( + config_entry_id=entry.entry_id, + identifiers={(DOMAIN, zone_id)}, # type: ignore[arg-type] # until fix issue #139773 + suggested_area=zone.get_name(), + ) + + async def async_unload_entry(hass: HomeAssistant, entry: NexiaConfigEntry) -> bool: """Unload a config entry.""" return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) diff --git a/homeassistant/components/nexia/entity.py b/homeassistant/components/nexia/entity.py index 78762b6124a8..bffa33db0142 100644 --- a/homeassistant/components/nexia/entity.py +++ b/homeassistant/components/nexia/entity.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, override from nexia.thermostat import NexiaThermostat from nexia.zone import NexiaThermostatZone -from homeassistant.const import ATTR_IDENTIFIERS, ATTR_NAME, ATTR_SUGGESTED_AREA +from homeassistant.const import ATTR_IDENTIFIERS, ATTR_NAME from homeassistant.helpers import device_registry as dr from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.dispatcher import ( @@ -103,13 +103,11 @@ class NexiaThermostatZoneEntity(NexiaThermostatEntity): """Initialize the entity.""" super().__init__(coordinator, zone.thermostat, unique_id) self._zone = zone - zone_name = self._zone.get_name() if TYPE_CHECKING: assert self._attr_device_info is not None self._attr_device_info |= { ATTR_IDENTIFIERS: {(DOMAIN, zone.zone_id)}, # type: ignore[arg-type] # until fix issue #139773 - ATTR_NAME: zone_name, - ATTR_SUGGESTED_AREA: zone_name, + ATTR_NAME: zone.get_name(), "via_device_id": dr.async_get_device_id_by_identifier( self.coordinator.hass, (DOMAIN, zone.thermostat.thermostat_id), # type: ignore[arg-type] # until fix issue #139773 diff --git a/tests/components/nexia/test_init.py b/tests/components/nexia/test_init.py index 1f869d78ebc1..cdb07c548257 100644 --- a/tests/components/nexia/test_init.py +++ b/tests/components/nexia/test_init.py @@ -5,12 +5,14 @@ from unittest.mock import NonCallableMock, patch import aiohttp from nexia.home import NexiaHome +from homeassistant.components.nexia import _preregister_devices from homeassistant.components.nexia.const import DOMAIN from homeassistant.config_entries import ConfigEntryState from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.setup import async_setup_component +from homeassistant.util import slugify from .conftest import setup_integration @@ -77,6 +79,39 @@ async def test_migrate_entry_minor_version_1_2(hass: HomeAssistant) -> None: assert entry.unique_id == "123456" +async def test_device_preregistration( + hass: HomeAssistant, mock_nexia_home: NexiaHome, device_registry: dr.DeviceRegistry +) -> None: + """Test all thermostat and zone devices are preregistered.""" + entry = MockConfigEntry(domain=DOMAIN) + entry.add_to_hass(hass) + + _preregister_devices(hass, entry, mock_nexia_home) + + thermostat_ids = mock_nexia_home.get_thermostat_ids() + assert len(thermostat_ids) > 0 + + for thermostat_id in thermostat_ids: + thermostat = mock_nexia_home.get_thermostat_by_id(thermostat_id) + device = device_registry.async_get_device_by_identifier( + (DOMAIN, thermostat.thermostat_id), # type: ignore[arg-type] # until fix issue #139773 + entry.entry_id, + ) + assert device is not None + + zone_ids = thermostat.get_zone_ids() + assert len(zone_ids) > 0 + + for zone_id in zone_ids: + zone = thermostat.get_zone_by_id(zone_id) + device = device_registry.async_get_device_by_identifier( + (DOMAIN, zone.zone_id), # type: ignore[arg-type] # until fix issue #139773 + entry.entry_id, + ) + assert device is not None + assert device.area_id == slugify(zone.get_name()) + + async def test_device_via_device_links( hass: HomeAssistant, patch_nexia_home: NexiaHome, @@ -86,14 +121,15 @@ async def test_device_via_device_links( config_entry = await setup_integration(hass, patch_nexia_home) thermostat_device = device_registry.async_get_device_by_identifier( - (DOMAIN, 2000000), # type: ignore[arg-type] # until fix issue #139773 + (DOMAIN, 2000004), # type: ignore[arg-type] # until fix issue #139773 config_entry.entry_id, ) assert thermostat_device is not None zone_device = device_registry.async_get_device_by_identifier( - (DOMAIN, 100), # type: ignore[arg-type] # until fix issue #139773 + (DOMAIN, 500), # type: ignore[arg-type] # until fix issue #139773 config_entry.entry_id, ) assert zone_device is not None assert zone_device.via_device_id == thermostat_device.id + assert zone_device.area_id == "center_nativezone"