Fix search throwing on templated services (#79637)

pull/79659/head
Erik Montnemery 2022-10-05 09:59:18 +02:00 committed by Franck Nijhof
parent 20c61af5b7
commit 146520b437
No known key found for this signature in database
GPG Key ID: D62583BA8AB11CA3
5 changed files with 43 additions and 10 deletions

View File

@ -227,6 +227,7 @@ CONF_SENSOR_TYPE: Final = "sensor_type"
CONF_SEQUENCE: Final = "sequence"
CONF_SERVICE: Final = "service"
CONF_SERVICE_DATA: Final = "data"
CONF_SERVICE_DATA_TEMPLATE: Final = "data_template"
CONF_SERVICE_TEMPLATE: Final = "service_template"
CONF_SHOW_ON_MAP: Final = "show_on_map"
CONF_SLAVE: Final = "slave"

View File

@ -63,6 +63,8 @@ from homeassistant.const import (
CONF_SCENE,
CONF_SEQUENCE,
CONF_SERVICE,
CONF_SERVICE_DATA,
CONF_SERVICE_DATA_TEMPLATE,
CONF_SERVICE_TEMPLATE,
CONF_STATE,
CONF_STOP,
@ -1119,8 +1121,10 @@ SERVICE_SCHEMA = vol.All(
vol.Exclusive(CONF_SERVICE_TEMPLATE, "service name"): vol.Any(
service, dynamic_template
),
vol.Optional("data"): vol.Any(template, vol.All(dict, template_complex)),
vol.Optional("data_template"): vol.Any(
vol.Optional(CONF_SERVICE_DATA): vol.Any(
template, vol.All(dict, template_complex)
),
vol.Optional(CONF_SERVICE_DATA_TEMPLATE): vol.Any(
template, vol.All(dict, template_complex)
),
vol.Optional(CONF_ENTITY_ID): comp_entity_ids,

View File

@ -50,6 +50,7 @@ from homeassistant.const import (
CONF_SEQUENCE,
CONF_SERVICE,
CONF_SERVICE_DATA,
CONF_SERVICE_DATA_TEMPLATE,
CONF_STOP,
CONF_TARGET,
CONF_THEN,
@ -1112,11 +1113,10 @@ async def _async_stop_scripts_at_shutdown(hass, event):
_VarsType = Union[dict[str, Any], MappingProxyType]
def _referenced_extract_ids(
data: dict[str, Any] | None, key: str, found: set[str]
) -> None:
def _referenced_extract_ids(data: Any, key: str, found: set[str]) -> None:
"""Extract referenced IDs."""
if not data:
# Data may not exist, or be a template
if not isinstance(data, dict):
return
item_ids = data.get(key)
@ -1300,7 +1300,7 @@ class Script:
for data in (
step.get(CONF_TARGET),
step.get(CONF_SERVICE_DATA),
step.get(service.CONF_SERVICE_DATA_TEMPLATE),
step.get(CONF_SERVICE_DATA_TEMPLATE),
):
_referenced_extract_ids(data, ATTR_AREA_ID, referenced)
@ -1340,7 +1340,7 @@ class Script:
for data in (
step.get(CONF_TARGET),
step.get(CONF_SERVICE_DATA),
step.get(service.CONF_SERVICE_DATA_TEMPLATE),
step.get(CONF_SERVICE_DATA_TEMPLATE),
):
_referenced_extract_ids(data, ATTR_DEVICE_ID, referenced)
@ -1391,7 +1391,7 @@ class Script:
step,
step.get(CONF_TARGET),
step.get(CONF_SERVICE_DATA),
step.get(service.CONF_SERVICE_DATA_TEMPLATE),
step.get(CONF_SERVICE_DATA_TEMPLATE),
):
_referenced_extract_ids(data, ATTR_ENTITY_ID, referenced)

View File

@ -19,6 +19,7 @@ from homeassistant.const import (
CONF_ENTITY_ID,
CONF_SERVICE,
CONF_SERVICE_DATA,
CONF_SERVICE_DATA_TEMPLATE,
CONF_SERVICE_TEMPLATE,
CONF_TARGET,
ENTITY_MATCH_ALL,
@ -52,7 +53,6 @@ if TYPE_CHECKING:
CONF_SERVICE_ENTITY_ID = "entity_id"
CONF_SERVICE_DATA_TEMPLATE = "data_template"
_LOGGER = logging.getLogger(__name__)

View File

@ -183,6 +183,22 @@ async def test_search(hass):
},
]
},
"script_with_templated_services": {
"sequence": [
{
"service": "test.script",
"target": "{{ {'entity_id':'test.test1'} }}",
},
{
"service": "test.script",
"data": "{{ {'entity_id':'test.test2'} }}",
},
{
"service": "test.script",
"data_template": "{{ {'entity_id':'test.test3'} }}",
},
]
},
}
},
)
@ -304,6 +320,18 @@ async def test_search(hass):
searcher = search.Searcher(hass, device_reg, entity_reg, entity_sources)
assert searcher.async_search(search_type, search_id) == {}
# Test search of templated script. We can't find referenced areas, devices or
# entities within templated services, but searching them should not raise or
# otherwise fail.
assert hass.states.get("script.script_with_templated_services")
for search_type, search_id in (
("area", "script.script_with_templated_services"),
("device", "script.script_with_templated_services"),
("entity", "script.script_with_templated_services"),
):
searcher = search.Searcher(hass, device_reg, entity_reg, entity_sources)
assert searcher.async_search(search_type, search_id) == {}
searcher = search.Searcher(hass, device_reg, entity_reg, entity_sources)
assert searcher.async_search("entity", "light.wled_config_entry_source") == {
"config_entry": {wled_config_entry.entry_id},