Add a service target (#43725)

This commit is contained in:
Paulus Schoutsen 2020-11-28 23:33:32 +01:00 committed by GitHub
parent a2e1efca33
commit dd513147a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 55 additions and 16 deletions

View File

@ -9,9 +9,10 @@ blueprint:
entity:
domain: binary_sensor
device_class: motion
light_entity:
light_target:
name: Light
selector:
target:
entity:
domain: light
@ -28,7 +29,7 @@ trigger:
action:
- service: homeassistant.turn_on
entity_id: !placeholder light_entity
target: !placeholder light_target
- wait_for_trigger:
platform: state
entity_id: !placeholder motion_entity
@ -36,4 +37,4 @@ action:
to: "off"
- delay: 120
- service: homeassistant.turn_off
entity_id: !placeholder light_entity
target: !placeholder light_target

View File

@ -170,6 +170,7 @@ CONF_STATE = "state"
CONF_STATE_TEMPLATE = "state_template"
CONF_STRUCTURE = "structure"
CONF_SWITCHES = "switches"
CONF_TARGET = "target"
CONF_TEMPERATURE_UNIT = "temperature_unit"
CONF_TIMEOUT = "timeout"
CONF_TIME_ZONE = "time_zone"

View File

@ -62,6 +62,7 @@ from homeassistant.const import (
CONF_SERVICE,
CONF_SERVICE_TEMPLATE,
CONF_STATE,
CONF_TARGET,
CONF_TIMEOUT,
CONF_UNIT_SYSTEM_IMPERIAL,
CONF_UNIT_SYSTEM_METRIC,
@ -881,7 +882,10 @@ PLATFORM_SCHEMA = vol.Schema(
PLATFORM_SCHEMA_BASE = PLATFORM_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA)
ENTITY_SERVICE_FIELDS = (ATTR_ENTITY_ID, ATTR_AREA_ID)
ENTITY_SERVICE_FIELDS = {
vol.Optional(ATTR_ENTITY_ID): comp_entity_ids,
vol.Optional(ATTR_AREA_ID): vol.Any(ENTITY_MATCH_NONE, vol.All(ensure_list, [str])),
}
def make_entity_service_schema(
@ -892,10 +896,7 @@ def make_entity_service_schema(
vol.Schema(
{
**schema,
vol.Optional(ATTR_ENTITY_ID): comp_entity_ids,
vol.Optional(ATTR_AREA_ID): vol.Any(
ENTITY_MATCH_NONE, vol.All(ensure_list, [str])
),
**ENTITY_SERVICE_FIELDS,
},
extra=extra,
),
@ -942,6 +943,7 @@ SERVICE_SCHEMA = vol.All(
vol.Optional("data"): vol.All(dict, template_complex),
vol.Optional("data_template"): vol.All(dict, template_complex),
vol.Optional(CONF_ENTITY_ID): comp_entity_ids,
vol.Optional(CONF_TARGET): ENTITY_SERVICE_FIELDS,
}
),
has_at_least_one_key(CONF_SERVICE, CONF_SERVICE_TEMPLATE),

View File

@ -111,3 +111,13 @@ class TimeSelector(Selector):
"""Selector of a time value."""
CONFIG_SCHEMA = vol.Schema({})
@SELECTORS.register("target")
class TargetSelector(Selector):
"""Selector of a target value (area ID, device ID, entity ID etc).
Value should follow cv.ENTITY_SERVICE_FIELDS format.
"""
CONFIG_SCHEMA = vol.Schema({"entity": {"domain": str}})

View File

@ -24,6 +24,7 @@ from homeassistant.const import (
ATTR_ENTITY_ID,
CONF_SERVICE,
CONF_SERVICE_TEMPLATE,
CONF_TARGET,
ENTITY_MATCH_ALL,
ENTITY_MATCH_NONE,
)
@ -136,6 +137,10 @@ def async_prepare_call_from_config(
domain, service = domain_service.split(".", 1)
service_data = {}
if CONF_TARGET in config:
service_data.update(config[CONF_TARGET])
for conf in [CONF_SERVICE_DATA, CONF_SERVICE_DATA_TEMPLATE]:
if conf not in config:
continue

View File

@ -123,7 +123,7 @@ async def test_motion_light(hass):
"use_blueprint": {
"path": "motion_light.yaml",
"input": {
"light_entity": "light.kitchen",
"light_target": {"entity_id": "light.kitchen"},
"motion_entity": "binary_sensor.kitchen",
},
}

View File

@ -117,3 +117,16 @@ def test_boolean_selector_schema(schema):
def test_time_selector_schema(schema):
"""Test time selector."""
selector.validate_selector({"time": schema})
@pytest.mark.parametrize(
"schema",
(
{},
{"entity": {}},
{"entity": {"domain": "light"}},
),
)
def test_target_selector_schema(schema):
"""Test entity selector."""
selector.validate_selector({"target": schema})

View File

@ -175,18 +175,25 @@ class TestServiceHelpers(unittest.TestCase):
"entity_id": "hello.world",
"data": {
"hello": "{{ 'goodbye' }}",
"data": {"value": "{{ 'complex' }}", "simple": "simple"},
"effect": {"value": "{{ 'complex' }}", "simple": "simple"},
},
"data_template": {"list": ["{{ 'list' }}", "2"]},
"target": {"area_id": "test-area-id", "entity_id": "will.be_overridden"},
}
service.call_from_config(self.hass, config)
self.hass.block_till_done()
assert self.calls[0].data["hello"] == "goodbye"
assert self.calls[0].data["data"]["value"] == "complex"
assert self.calls[0].data["data"]["simple"] == "simple"
assert self.calls[0].data["list"][0] == "list"
assert dict(self.calls[0].data) == {
"hello": "goodbye",
"effect": {
"value": "complex",
"simple": "simple",
},
"list": ["list", "2"],
"entity_id": ["hello.world"],
"area_id": ["test-area-id"],
}
def test_service_template_service_call(self):
"""Test legacy service_template call with templating."""