Add a syntax for merging lists of triggers (#117698)
* Add a syntax for merging lists of triggers * Updating to the new syntax * Update homeassistant/helpers/config_validation.py Co-authored-by: Erik Montnemery <erik@montnemery.com> * fix suggestion * update test and add comments * not actually json * move test to new file * update tests --------- Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
parent
06e876aee0
commit
056e6eae82
4 changed files with 159 additions and 1 deletions
|
@ -282,6 +282,7 @@ CONF_THEN: Final = "then"
|
||||||
CONF_TIMEOUT: Final = "timeout"
|
CONF_TIMEOUT: Final = "timeout"
|
||||||
CONF_TIME_ZONE: Final = "time_zone"
|
CONF_TIME_ZONE: Final = "time_zone"
|
||||||
CONF_TOKEN: Final = "token"
|
CONF_TOKEN: Final = "token"
|
||||||
|
CONF_TRIGGERS: Final = "triggers"
|
||||||
CONF_TRIGGER_TIME: Final = "trigger_time"
|
CONF_TRIGGER_TIME: Final = "trigger_time"
|
||||||
CONF_TTL: Final = "ttl"
|
CONF_TTL: Final = "ttl"
|
||||||
CONF_TYPE: Final = "type"
|
CONF_TYPE: Final = "type"
|
||||||
|
|
|
@ -81,6 +81,7 @@ from homeassistant.const import (
|
||||||
CONF_TARGET,
|
CONF_TARGET,
|
||||||
CONF_THEN,
|
CONF_THEN,
|
||||||
CONF_TIMEOUT,
|
CONF_TIMEOUT,
|
||||||
|
CONF_TRIGGERS,
|
||||||
CONF_UNTIL,
|
CONF_UNTIL,
|
||||||
CONF_VALUE_TEMPLATE,
|
CONF_VALUE_TEMPLATE,
|
||||||
CONF_VARIABLES,
|
CONF_VARIABLES,
|
||||||
|
@ -1781,6 +1782,19 @@ TRIGGER_BASE_SCHEMA = vol.Schema(
|
||||||
_base_trigger_validator_schema = TRIGGER_BASE_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA)
|
_base_trigger_validator_schema = TRIGGER_BASE_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
|
|
||||||
|
def _base_trigger_list_flatten(triggers: list[Any]) -> list[Any]:
|
||||||
|
"""Flatten trigger arrays containing 'triggers:' sublists into a single list of triggers."""
|
||||||
|
flatlist = []
|
||||||
|
for t in triggers:
|
||||||
|
if CONF_TRIGGERS in t and len(t.keys()) == 1:
|
||||||
|
triggerlist = ensure_list(t[CONF_TRIGGERS])
|
||||||
|
flatlist.extend(triggerlist)
|
||||||
|
else:
|
||||||
|
flatlist.append(t)
|
||||||
|
|
||||||
|
return flatlist
|
||||||
|
|
||||||
|
|
||||||
# This is first round of validation, we don't want to process the config here already,
|
# This is first round of validation, we don't want to process the config here already,
|
||||||
# just ensure basics as platform and ID are there.
|
# just ensure basics as platform and ID are there.
|
||||||
def _base_trigger_validator(value: Any) -> Any:
|
def _base_trigger_validator(value: Any) -> Any:
|
||||||
|
@ -1788,7 +1802,9 @@ def _base_trigger_validator(value: Any) -> Any:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
TRIGGER_SCHEMA = vol.All(ensure_list, [_base_trigger_validator])
|
TRIGGER_SCHEMA = vol.All(
|
||||||
|
ensure_list, _base_trigger_list_flatten, [_base_trigger_validator]
|
||||||
|
)
|
||||||
|
|
||||||
_SCRIPT_DELAY_SCHEMA = vol.Schema(
|
_SCRIPT_DELAY_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,6 +25,7 @@ from homeassistant.helpers import (
|
||||||
selector,
|
selector,
|
||||||
template,
|
template,
|
||||||
)
|
)
|
||||||
|
from homeassistant.helpers.config_validation import TRIGGER_SCHEMA
|
||||||
|
|
||||||
|
|
||||||
def test_boolean() -> None:
|
def test_boolean() -> None:
|
||||||
|
@ -1817,6 +1818,82 @@ async def test_async_validate(hass: HomeAssistant, tmpdir: py.path.local) -> Non
|
||||||
validator_calls = {}
|
validator_calls = {}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_nested_trigger_list() -> None:
|
||||||
|
"""Test triggers within nested lists are flattened."""
|
||||||
|
|
||||||
|
trigger_config = [
|
||||||
|
{
|
||||||
|
"triggers": {
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_2",
|
||||||
|
},
|
||||||
|
{"triggers": []},
|
||||||
|
{"triggers": None},
|
||||||
|
{
|
||||||
|
"triggers": [
|
||||||
|
{
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_4",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
validated_triggers = TRIGGER_SCHEMA(trigger_config)
|
||||||
|
|
||||||
|
assert validated_triggers == [
|
||||||
|
{
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_4",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_nested_trigger_list_extra() -> None:
|
||||||
|
"""Test triggers key with extra keys is not modified."""
|
||||||
|
|
||||||
|
trigger_config = [
|
||||||
|
{
|
||||||
|
"platform": "other",
|
||||||
|
"triggers": [
|
||||||
|
{
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_2",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
validated_triggers = TRIGGER_SCHEMA(trigger_config)
|
||||||
|
|
||||||
|
assert validated_triggers == trigger_config
|
||||||
|
|
||||||
|
|
||||||
async def test_is_entity_service_schema(
|
async def test_is_entity_service_schema(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
|
@ -159,6 +159,70 @@ async def test_trigger_enabled_templates(
|
||||||
assert len(service_calls) == 2
|
assert len(service_calls) == 2
|
||||||
|
|
||||||
|
|
||||||
|
async def test_nested_trigger_list(
|
||||||
|
hass: HomeAssistant, service_calls: list[ServiceCall]
|
||||||
|
) -> None:
|
||||||
|
"""Test triggers within nested list."""
|
||||||
|
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"automation",
|
||||||
|
{
|
||||||
|
"automation": {
|
||||||
|
"trigger": [
|
||||||
|
{
|
||||||
|
"triggers": {
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_2",
|
||||||
|
},
|
||||||
|
{"triggers": []},
|
||||||
|
{"triggers": None},
|
||||||
|
{
|
||||||
|
"triggers": [
|
||||||
|
{
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "trigger_4",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"action": {
|
||||||
|
"service": "test.automation",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.bus.async_fire("trigger_1")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(service_calls) == 1
|
||||||
|
|
||||||
|
hass.bus.async_fire("trigger_2")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(service_calls) == 2
|
||||||
|
|
||||||
|
hass.bus.async_fire("trigger_none")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(service_calls) == 2
|
||||||
|
|
||||||
|
hass.bus.async_fire("trigger_3")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(service_calls) == 3
|
||||||
|
|
||||||
|
hass.bus.async_fire("trigger_4")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(service_calls) == 4
|
||||||
|
|
||||||
|
|
||||||
async def test_trigger_enabled_template_limited(
|
async def test_trigger_enabled_template_limited(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
service_calls: list[ServiceCall],
|
service_calls: list[ServiceCall],
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue