From 8be6f441ddc76205dad677b39668b5c5846f65bc Mon Sep 17 00:00:00 2001 From: Artur Pragacz <49985303+arturpragacz@users.noreply.github.com> Date: Tue, 31 Mar 2026 11:53:36 +0200 Subject: [PATCH] Register condition platform upon use (#166939) --- homeassistant/helpers/condition.py | 25 +++++++++----- tests/helpers/test_condition.py | 53 ++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 8 deletions(-) diff --git a/homeassistant/helpers/condition.py b/homeassistant/helpers/condition.py index 5cf8df5d36c7..810b8f40b732 100644 --- a/homeassistant/helpers/condition.py +++ b/homeassistant/helpers/condition.py @@ -230,19 +230,23 @@ async def _register_condition_platform( from homeassistant.components import automation # noqa: PLC0415 new_conditions: set[str] = set() + conditions = hass.data[CONDITIONS] if hasattr(platform, "async_get_conditions"): - for condition_key in await platform.async_get_conditions(hass): + all_conditions = await platform.async_get_conditions(hass) + for condition_key in all_conditions: condition_key = get_absolute_description_key( integration_domain, condition_key ) - hass.data[CONDITIONS][condition_key] = integration_domain - new_conditions.add(condition_key) + if condition_key not in conditions: + conditions[condition_key] = integration_domain + new_conditions.add(condition_key) if not new_conditions: - _LOGGER.debug( - "Integration %s returned no conditions in async_get_conditions", - integration_domain, - ) + if not all_conditions: + _LOGGER.debug( + "Integration %s returned no conditions in async_get_conditions", + integration_domain, + ) return else: _LOGGER.debug( @@ -821,12 +825,17 @@ async def _async_get_condition_platform( f'Invalid condition "{condition_key}" specified' ) from None try: - return platform, await integration.async_get_platform("condition") + platform_module = await integration.async_get_platform("condition") except ImportError: raise HomeAssistantError( f"Integration '{platform}' does not provide condition support" ) from None + # Ensure conditions are registered so descriptions can be loaded + await _register_condition_platform(hass, platform, platform_module) + + return platform, platform_module + async def _async_get_checker(condition: Condition) -> ConditionCheckerType: new_checker = await condition.async_get_checker() diff --git a/tests/helpers/test_condition.py b/tests/helpers/test_condition.py index e21a3d048d00..ab5fe80825c1 100644 --- a/tests/helpers/test_condition.py +++ b/tests/helpers/test_condition.py @@ -48,9 +48,11 @@ from homeassistant.helpers.condition import ( ATTR_BEHAVIOR, BEHAVIOR_ALL, BEHAVIOR_ANY, + CONDITIONS, Condition, ConditionChecker, EntityNumericalConditionWithUnitBase, + _async_get_condition_platform, async_validate_condition_config, make_entity_numerical_condition, make_entity_numerical_condition_with_unit, @@ -2276,6 +2278,57 @@ async def test_platform_backwards_compatibility_for_new_style_configs( assert result == config_old_style +async def test_get_condition_platform_registers_conditions( + hass: HomeAssistant, +) -> None: + """Test _async_get_condition_platform registers conditions and notifies subscribers.""" + + class MockCondition(Condition): + """Mock condition.""" + + @classmethod + async def async_validate_config( + cls, hass: HomeAssistant, config: ConfigType + ) -> ConfigType: + return config + + async def async_get_checker(self) -> ConditionChecker: + return lambda **kwargs: True + + async def async_get_conditions( + hass: HomeAssistant, + ) -> dict[str, type[Condition]]: + return {"cond_a": MockCondition, "cond_b": MockCondition} + + mock_integration(hass, MockModule("test")) + mock_platform( + hass, "test.condition", Mock(async_get_conditions=async_get_conditions) + ) + + subscriber_events: list[set[str]] = [] + + async def subscriber(new_conditions: set[str]) -> None: + subscriber_events.append(new_conditions) + + condition.async_subscribe_platform_events(hass, subscriber) + + assert "test.cond_a" not in hass.data[CONDITIONS] + assert "test.cond_b" not in hass.data[CONDITIONS] + + # First call registers all conditions from the platform and notifies subscribers + await _async_get_condition_platform(hass, "test.cond_a") + + assert hass.data[CONDITIONS]["test.cond_a"] == "test" + assert hass.data[CONDITIONS]["test.cond_b"] == "test" + assert len(subscriber_events) == 1 + assert subscriber_events[0] == {"test.cond_a", "test.cond_b"} + + # Subsequent calls are idempotent — no re-registration or re-notification + await _async_get_condition_platform(hass, "test.cond_a") + await _async_get_condition_platform(hass, "test.cond_b") + assert len(subscriber_events) == 1 + + @pytest.mark.parametrize("enabled_value", [True, "{{ 1 == 1 }}"]) async def test_enabled_condition( hass: HomeAssistant, enabled_value: bool | str