Allow templates for enabling automation triggers (#114458)

* Allow templates for enabling automation triggers

* Test exception for non-limited template

* Use `cv.template` instead of `cv.template_complex`

* skip trigger with invalid enable template

instead of returning and thus not evaluating other triggers
This commit is contained in:
Matthias Alphart 2024-05-14 14:44:21 +02:00 committed by GitHub
parent 2a6a0e6230
commit ba48da7678
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 97 additions and 4 deletions

View file

@ -1648,7 +1648,7 @@ TRIGGER_BASE_SCHEMA = vol.Schema(
vol.Required(CONF_PLATFORM): str,
vol.Optional(CONF_ID): str,
vol.Optional(CONF_VARIABLES): SCRIPT_VARIABLES_SCHEMA,
vol.Optional(CONF_ENABLED): boolean,
vol.Optional(CONF_ENABLED): vol.Any(boolean, template),
}
)

View file

@ -27,11 +27,12 @@ from homeassistant.core import (
callback,
is_callback,
)
from homeassistant.exceptions import HomeAssistantError
from homeassistant.exceptions import HomeAssistantError, TemplateError
from homeassistant.loader import IntegrationNotFound, async_get_integration
from homeassistant.util.async_ import create_eager_task
from homeassistant.util.hass_dict import HassKey
from .template import Template
from .typing import ConfigType, TemplateVarsType
_PLATFORM_ALIASES = {
@ -312,8 +313,16 @@ async def async_initialize_triggers(
triggers: list[asyncio.Task[CALLBACK_TYPE]] = []
for idx, conf in enumerate(trigger_config):
# Skip triggers that are not enabled
if not conf.get(CONF_ENABLED, True):
continue
if CONF_ENABLED in conf:
enabled = conf[CONF_ENABLED]
if isinstance(enabled, Template):
try:
enabled = enabled.async_render(variables, limited=True)
except TemplateError as err:
log_cb(logging.ERROR, f"Error rendering enabled template: {err}")
continue
if not enabled:
continue
platform = await _async_get_trigger_platform(hass, conf)
trigger_id = conf.get(CONF_ID, f"{idx}")

View file

@ -110,6 +110,90 @@ async def test_if_disabled_trigger_not_firing(
assert len(calls) == 1
async def test_trigger_enabled_templates(
hass: HomeAssistant, calls: list[ServiceCall]
) -> None:
"""Test triggers enabled by template."""
assert await async_setup_component(
hass,
"automation",
{
"automation": {
"trigger": [
{
"enabled": "{{ 'some text' }}",
"platform": "event",
"event_type": "truthy_template_trigger_event",
},
{
"enabled": "{{ 3 == 4 }}",
"platform": "event",
"event_type": "falsy_template_trigger_event",
},
{
"enabled": False, # eg. from a blueprints input defaulting to `false`
"platform": "event",
"event_type": "falsy_trigger_event",
},
{
"enabled": "some text", # eg. from a blueprints input value
"platform": "event",
"event_type": "truthy_trigger_event",
},
],
"action": {
"service": "test.automation",
},
}
},
)
hass.bus.async_fire("falsy_template_trigger_event")
await hass.async_block_till_done()
assert not calls
hass.bus.async_fire("falsy_trigger_event")
await hass.async_block_till_done()
assert not calls
hass.bus.async_fire("truthy_template_trigger_event")
await hass.async_block_till_done()
assert len(calls) == 1
hass.bus.async_fire("truthy_trigger_event")
await hass.async_block_till_done()
assert len(calls) == 2
async def test_trigger_enabled_template_limited(
hass: HomeAssistant, calls: list[ServiceCall], caplog: pytest.LogCaptureFixture
) -> None:
"""Test triggers enabled invalid template."""
assert await async_setup_component(
hass,
"automation",
{
"automation": {
"trigger": [
{
"enabled": "{{ states('sensor.limited') }}", # only limited template supported
"platform": "event",
"event_type": "test_event",
},
],
"action": {
"service": "test.automation",
},
}
},
)
hass.bus.async_fire("test_event")
await hass.async_block_till_done()
assert not calls
assert "Error rendering enabled template" in caplog.text
async def test_trigger_alias(
hass: HomeAssistant, calls: list[ServiceCall], caplog: pytest.LogCaptureFixture
) -> None: