diff --git a/homeassistant/helpers/condition.py b/homeassistant/helpers/condition.py index b8c85902f7f..e76244240d1 100644 --- a/homeassistant/helpers/condition.py +++ b/homeassistant/helpers/condition.py @@ -227,16 +227,25 @@ async def async_from_config( factory = platform.async_condition_from_config # Check if condition is not enabled - if not config.get(CONF_ENABLED, True): + if CONF_ENABLED in config: + enabled = config[CONF_ENABLED] + if isinstance(enabled, Template): + try: + enabled = enabled.async_render(limited=True) + except TemplateError as err: + raise HomeAssistantError( + f"Error rendering condition enabled template: {err}" + ) from err + if not enabled: - @trace_condition_function - def disabled_condition( - hass: HomeAssistant, variables: TemplateVarsType = None - ) -> bool | None: - """Condition not enabled, will act as if it didn't exist.""" - return None + @trace_condition_function + def disabled_condition( + hass: HomeAssistant, variables: TemplateVarsType = None + ) -> bool | None: + """Condition not enabled, will act as if it didn't exist.""" + return None - return disabled_condition + return disabled_condition # Check for partials to properly determine if coroutine function check_factory = factory diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 697810e21aa..ebf13532ee8 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -1356,7 +1356,7 @@ NUMERIC_STATE_THRESHOLD_SCHEMA = vol.Any( CONDITION_BASE_SCHEMA = { vol.Optional(CONF_ALIAS): string, - vol.Optional(CONF_ENABLED): boolean, + vol.Optional(CONF_ENABLED): vol.Any(boolean, template), } NUMERIC_STATE_CONDITION_SCHEMA = vol.All( diff --git a/tests/helpers/test_condition.py b/tests/helpers/test_condition.py index 20dea85c3e4..7b98ccb3749 100644 --- a/tests/helpers/test_condition.py +++ b/tests/helpers/test_condition.py @@ -3382,10 +3382,36 @@ async def test_platform_async_validate_condition_config(hass: HomeAssistant) -> device_automation_validate_condition_mock.assert_awaited() -async def test_disabled_condition(hass: HomeAssistant) -> None: +@pytest.mark.parametrize("enabled_value", [True, "{{ 1 == 1 }}"]) +async def test_enabled_condition( + hass: HomeAssistant, enabled_value: bool | str +) -> None: + """Test an explicitly enabled condition.""" + config = { + "enabled": enabled_value, + "condition": "state", + "entity_id": "binary_sensor.test", + "state": "on", + } + config = cv.CONDITION_SCHEMA(config) + config = await condition.async_validate_condition_config(hass, config) + test = await condition.async_from_config(hass, config) + + hass.states.async_set("binary_sensor.test", "on") + assert test(hass) is True + + # Still passes, condition is not enabled + hass.states.async_set("binary_sensor.test", "off") + assert test(hass) is False + + +@pytest.mark.parametrize("enabled_value", [False, "{{ 1 == 9 }}"]) +async def test_disabled_condition( + hass: HomeAssistant, enabled_value: bool | str +) -> None: """Test a disabled condition returns none.""" config = { - "enabled": False, + "enabled": enabled_value, "condition": "state", "entity_id": "binary_sensor.test", "state": "on", @@ -3402,6 +3428,21 @@ async def test_disabled_condition(hass: HomeAssistant) -> None: assert test(hass) is None +async def test_condition_enabled_template_limited(hass: HomeAssistant) -> None: + """Test conditions enabled template raises for non-limited template uses.""" + config = { + "enabled": "{{ states('sensor.limited') }}", + "condition": "state", + "entity_id": "binary_sensor.test", + "state": "on", + } + config = cv.CONDITION_SCHEMA(config) + config = await condition.async_validate_condition_config(hass, config) + + with pytest.raises(HomeAssistantError): + await condition.async_from_config(hass, config) + + async def test_and_condition_with_disabled_condition(hass: HomeAssistant) -> None: """Test the 'and' condition with one of the conditions disabled.""" config = {