1
mirror of https://github.com/home-assistant/core synced 2024-10-07 10:13:38 +02:00

Teach call service script action about entity registry ids (#61172)

This commit is contained in:
Erik Montnemery 2022-01-07 17:42:47 +01:00 committed by GitHub
parent d5d8eefded
commit fc2025509e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 2 deletions

View File

@ -311,6 +311,12 @@ comp_entity_ids = vol.Any(
)
comp_entity_ids_or_uuids = vol.Any(
vol.All(vol.Lower, vol.Any(ENTITY_MATCH_ALL, ENTITY_MATCH_NONE)),
entity_ids_or_uuids,
)
def entity_domain(domain: str | list[str]) -> Callable[[Any], str]:
"""Validate that entity belong to domain."""
ent_domain = entities_domain(domain)
@ -972,6 +978,23 @@ ENTITY_SERVICE_FIELDS = {
),
}
TARGET_SERVICE_FIELDS = {
# Same as ENTITY_SERVICE_FIELDS but supports specifying entity by entity registry
# ID.
# Either accept static entity IDs, a single dynamic template or a mixed list
# of static and dynamic templates. While this could be solved with a single
# complex template, handling it like this, keeps config validation useful.
vol.Optional(ATTR_ENTITY_ID): vol.Any(
comp_entity_ids_or_uuids, dynamic_template, vol.All(list, template_complex)
),
vol.Optional(ATTR_DEVICE_ID): vol.Any(
ENTITY_MATCH_NONE, vol.All(ensure_list, [vol.Any(dynamic_template, str)])
),
vol.Optional(ATTR_AREA_ID): vol.Any(
ENTITY_MATCH_NONE, vol.All(ensure_list, [vol.Any(dynamic_template, str)])
),
}
def make_entity_service_schema(
schema: dict, *, extra: int = vol.PREVENT_EXTRA
@ -1034,7 +1057,7 @@ SERVICE_SCHEMA = vol.All(
template, vol.All(dict, template_complex)
),
vol.Optional(CONF_ENTITY_ID): comp_entity_ids,
vol.Optional(CONF_TARGET): vol.Any(ENTITY_SERVICE_FIELDS, dynamic_template),
vol.Optional(CONF_TARGET): vol.Any(TARGET_SERVICE_FIELDS, dynamic_template),
}
),
has_at_least_one_key(CONF_SERVICE, CONF_SERVICE_TEMPLATE),

View File

@ -218,7 +218,10 @@ def async_prepare_call_from_config(
target.update(template.render_complex(conf, variables))
if CONF_ENTITY_ID in target:
target[CONF_ENTITY_ID] = cv.comp_entity_ids(target[CONF_ENTITY_ID])
registry = entity_registry.async_get(hass)
target[CONF_ENTITY_ID] = entity_registry.async_resolve_entity_ids(
registry, cv.comp_entity_ids_or_uuids(target[CONF_ENTITY_ID])
)
except TemplateError as ex:
raise HomeAssistantError(
f"Error rendering service target template: {ex}"

View File

@ -29,6 +29,7 @@ from homeassistant.setup import async_setup_component
from tests.common import (
MockEntity,
async_mock_service,
get_test_home_assistant,
mock_device_registry,
mock_registry,
@ -375,6 +376,27 @@ class TestServiceHelpers(unittest.TestCase):
assert mock_log.call_count == 3
async def test_service_call_entry_id(hass):
"""Test service call with entity specified by entity registry ID."""
registry = ent_reg.async_get(hass)
calls = async_mock_service(hass, "test_domain", "test_service")
entry = registry.async_get_or_create(
"hello", "hue", "1234", suggested_object_id="world"
)
assert entry.entity_id == "hello.world"
config = {
"service": "test_domain.test_service",
"target": {"entity_id": entry.id},
}
await service.async_call_from_config(hass, config)
await hass.async_block_till_done()
assert dict(calls[0].data) == {"entity_id": ["hello.world"]}
async def test_extract_entity_ids(hass):
"""Test extract_entity_ids method."""
hass.states.async_set("light.Bowl", STATE_ON)