Fix via_device race in guardian (#177717)

This commit is contained in:
Erik Montnemery
2026-08-03 17:50:33 +02:00
committed by GitHub
parent ab7553aef8
commit 406d37b0b7
4 changed files with 73 additions and 3 deletions
@@ -115,6 +115,19 @@ async def async_setup_entry(hass: HomeAssistant, entry: GuardianConfigEntry) ->
paired_sensor_manager=paired_sensor_manager,
)
# Register the valve controller device up front so paired sensors can resolve
# it as their via device when they are added:
device_registry = dr.async_get(hass)
device_registry.async_get_or_create(
config_entry_id=entry.entry_id,
identifiers={(DOMAIN, entry.data[CONF_UID])},
manufacturer="Elexa",
name=f"Guardian valve controller {entry.data[CONF_UID]}",
sw_version=valve_controller_coordinators[API_SYSTEM_DIAGNOSTICS].data[
"firmware"
],
)
# Set up all of the Guardian entity platforms:
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
+6 -1
View File
@@ -2,6 +2,7 @@
from dataclasses import dataclass
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.update_coordinator import CoordinatorEntity
@@ -43,7 +44,11 @@ class PairedSensorEntity(GuardianEntity):
manufacturer="Elexa",
model=coordinator.data["codename"],
name=f"Guardian paired sensor {paired_sensor_uid}",
via_device=(DOMAIN, entry.data[CONF_UID]),
via_device_id=dr.async_get_device_id_by_identifier(
coordinator.hass,
(DOMAIN, entry.data[CONF_UID]),
config_entry_id=entry.entry_id,
),
)
self._attr_unique_id = f"{paired_sensor_uid}_{description.key}"
+9 -2
View File
@@ -7,7 +7,7 @@ from unittest.mock import AsyncMock, patch
import pytest
from homeassistant.components.guardian import CONF_UID, DOMAIN
from homeassistant.const import CONF_IP_ADDRESS, CONF_PORT
from homeassistant.const import CONF_IP_ADDRESS, CONF_PORT, Platform
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from homeassistant.util.json import JsonObjectType
@@ -97,10 +97,17 @@ def data_wifi_status_fixture() -> JsonObjectType:
return load_json_object_fixture("wifi_status_data.json", "guardian")
@pytest.fixture(name="platforms")
def platforms_fixture() -> list[Platform]:
"""Define a platforms fixture."""
return []
@pytest.fixture(name="setup_guardian")
async def setup_guardian_fixture(
hass: HomeAssistant,
config: dict[str, Any],
platforms: list[Platform],
data_sensor_pair_dump: JsonObjectType,
data_sensor_pair_sensor: JsonObjectType,
data_sensor_paired_sensor_status: JsonObjectType,
@@ -150,7 +157,7 @@ async def setup_guardian_fixture(
),
patch(
"homeassistant.components.guardian.PLATFORMS",
[],
platforms,
),
):
assert await async_setup_component(hass, DOMAIN, config)
+45
View File
@@ -0,0 +1,45 @@
"""Test the Elexa Guardian init module."""
from datetime import timedelta
from freezegun.api import FrozenDateTimeFactory
import pytest
from homeassistant.components.guardian import CONF_UID, DOMAIN
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from tests.common import MockConfigEntry, async_fire_time_changed
@pytest.fixture(name="platforms")
def platforms_fixture() -> list[Platform]:
"""Override to exercise the paired sensor entity setup."""
return [Platform.SENSOR]
async def test_paired_sensor_via_device_id(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
device_registry: dr.DeviceRegistry,
config_entry: MockConfigEntry,
setup_guardian: None, # relies on config_entry fixture
) -> None:
"""Test that a paired sensor is linked to the valve controller via via_device_id."""
# Advance time so the sensor pair dump coordinator refreshes and discovers the
# paired sensor from the fixture data:
freezer.tick(timedelta(seconds=30))
async_fire_time_changed(hass)
await hass.async_block_till_done()
valve_controller_device = device_registry.async_get_device_by_identifier(
(DOMAIN, config_entry.data[CONF_UID]), config_entry.entry_id
)
paired_sensor_device = device_registry.async_get_device_by_identifier(
(DOMAIN, "AABBCCDDEEFF"), config_entry.entry_id
)
assert valve_controller_device is not None
assert paired_sensor_device is not None
assert paired_sensor_device.via_device_id == valve_controller_device.id