From 91c36fcdf68ecc1f8900b4fa111183c9cca967ac Mon Sep 17 00:00:00 2001 From: Sid <27780930+autinerd@users.noreply.github.com> Date: Tue, 17 Feb 2026 15:47:56 +0100 Subject: [PATCH] Fix dynamic entity creation in eheimdigital (#161155) --- .../components/eheimdigital/coordinator.py | 18 ++++++- tests/components/eheimdigital/test_init.py | 52 ++++++++++++++++++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/eheimdigital/coordinator.py b/homeassistant/components/eheimdigital/coordinator.py index df5475b6567..61c3be363c8 100644 --- a/homeassistant/components/eheimdigital/coordinator.py +++ b/homeassistant/components/eheimdigital/coordinator.py @@ -53,6 +53,7 @@ class EheimDigitalUpdateCoordinator( main_device_added_event=self.main_device_added_event, ) self.known_devices: set[str] = set() + self.incomplete_devices: set[str] = set() self.platform_callbacks: set[AsyncSetupDeviceEntitiesCallback] = set() def add_platform_callback( @@ -70,11 +71,26 @@ class EheimDigitalUpdateCoordinator( This function is called from the library whenever a new device is added. """ - if device_address not in self.known_devices: + if self.hub.devices[device_address].is_missing_data: + self.incomplete_devices.add(device_address) + return + + if ( + device_address not in self.known_devices + or device_address in self.incomplete_devices + ): for platform_callback in self.platform_callbacks: platform_callback({device_address: self.hub.devices[device_address]}) + if device_address in self.incomplete_devices: + self.incomplete_devices.remove(device_address) async def _async_receive_callback(self) -> None: + if any(self.incomplete_devices): + for device_address in self.incomplete_devices.copy(): + if not self.hub.devices[device_address].is_missing_data: + await self._async_device_found( + device_address, EheimDeviceType.VERSION_UNDEFINED + ) self.async_set_updated_data(self.hub.devices) async def _async_setup(self) -> None: diff --git a/tests/components/eheimdigital/test_init.py b/tests/components/eheimdigital/test_init.py index 4b282338954..8087c0a927e 100644 --- a/tests/components/eheimdigital/test_init.py +++ b/tests/components/eheimdigital/test_init.py @@ -1,12 +1,14 @@ """Tests for the init module.""" -from unittest.mock import MagicMock +from unittest.mock import AsyncMock, MagicMock, patch from eheimdigital.types import EheimDeviceType, EheimDigitalClientError +from homeassistant.components.eheimdigital.const import DOMAIN from homeassistant.config_entries import ConfigEntryState +from homeassistant.const import Platform from homeassistant.core import HomeAssistant -from homeassistant.helpers import device_registry as dr +from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.setup import async_setup_component from .conftest import init_integration @@ -15,6 +17,52 @@ from tests.common import MockConfigEntry from tests.typing import WebSocketGenerator +async def test_dynamic_entities( + hass: HomeAssistant, + eheimdigital_hub_mock: MagicMock, + mock_config_entry: MockConfigEntry, + entity_registry: er.EntityRegistry, +) -> None: + """Test dynamic adding of entities.""" + mock_config_entry.add_to_hass(hass) + heater_data = eheimdigital_hub_mock.return_value.devices[ + "00:00:00:00:00:02" + ].heater_data + eheimdigital_hub_mock.return_value.devices["00:00:00:00:00:02"].heater_data = None + with ( + patch( + "homeassistant.components.eheimdigital.coordinator.asyncio.Event", + new=AsyncMock, + ), + ): + await hass.config_entries.async_setup(mock_config_entry.entry_id) + + for device in eheimdigital_hub_mock.return_value.devices: + await eheimdigital_hub_mock.call_args.kwargs["device_found_callback"]( + device, eheimdigital_hub_mock.return_value.devices[device].device_type + ) + await hass.async_block_till_done() + + assert ( + entity_registry.async_get_entity_id( + DOMAIN, Platform.NUMBER, "mock_heater_night_temperature_offset" + ) + is None + ) + + eheimdigital_hub_mock.return_value.devices[ + "00:00:00:00:00:02" + ].heater_data = heater_data + + await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]() + + assert hass.states.get("number.mock_heater_night_temperature_offset").state == str( + eheimdigital_hub_mock.return_value.devices[ + "00:00:00:00:00:02" + ].night_temperature_offset + ) + + async def test_remove_device( hass: HomeAssistant, eheimdigital_hub_mock: MagicMock,