1
mirror of https://github.com/home-assistant/core synced 2024-07-30 21:18:57 +02:00

Allow variables in service.call_from_config

This commit is contained in:
Paulus Schoutsen 2016-04-21 12:22:19 -07:00
parent 3318c55c65
commit 4acb121689
3 changed files with 60 additions and 46 deletions

View File

@ -231,8 +231,8 @@ EVENT_SCHEMA = vol.Schema({
SERVICE_SCHEMA = vol.All(vol.Schema({
vol.Exclusive('service', 'service name'): service,
vol.Exclusive('service_template', 'service name'): string,
vol.Exclusive('data', 'service data'): dict,
vol.Exclusive('data_template', 'service data'): {match_all: template},
'entity_id': entity_ids,
vol.Exclusive('service_template', 'service name'): template,
vol.Optional('data'): dict,
vol.Optional('data_template'): {match_all: template},
vol.Optional('entity_id'): entity_ids,
}), has_at_least_one_key('service', 'service_template'))

View File

@ -2,9 +2,13 @@
import functools
import logging
import voluptuous as vol
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.exceptions import TemplateError
from homeassistant.helpers import template
from homeassistant.loader import get_component
import homeassistant.helpers.config_validation as cv
HASS = None
@ -28,47 +32,38 @@ def service(domain, service_name):
return register_service_decorator
def call_from_config(hass, config, blocking=False):
def call_from_config(hass, config, blocking=False, variables=None):
"""Call a service based on a config hash."""
validation_error = validate_service_call(config)
if validation_error:
_LOGGER.error(validation_error)
return
domain_service = (
config[CONF_SERVICE]
if CONF_SERVICE in config
else template.render(hass, config[CONF_SERVICE_TEMPLATE]))
try:
domain, service_name = domain_service.split('.', 1)
except ValueError:
_LOGGER.error('Invalid service specified: %s', domain_service)
config = cv.SERVICE_SCHEMA(config)
except vol.Invalid as ex:
_LOGGER.error("Invalid config for calling service: %s", ex)
return
service_data = config.get(CONF_SERVICE_DATA)
if service_data is None:
service_data = {}
elif isinstance(service_data, dict):
service_data = dict(service_data)
if CONF_SERVICE in config:
domain_service = config[CONF_SERVICE]
else:
_LOGGER.error("%s should be a dictionary", CONF_SERVICE_DATA)
service_data = {}
try:
domain_service = template.render(
hass, config[CONF_SERVICE_TEMPLATE], variables)
domain_service = cv.service(domain_service)
except TemplateError as ex:
_LOGGER.error('Error rendering service name template: %s', ex)
return
except vol.Invalid as ex:
_LOGGER.error('Template rendered invalid service: %s',
domain_service)
return
service_data_template = config.get(CONF_SERVICE_DATA_TEMPLATE)
if service_data_template and isinstance(service_data_template, dict):
for key, value in service_data_template.items():
service_data[key] = template.render(hass, value)
elif service_data_template:
_LOGGER.error("%s should be a dictionary", CONF_SERVICE_DATA)
domain, service_name = domain_service.split('.', 1)
service_data = dict(config.get(CONF_SERVICE_DATA, {}))
entity_id = config.get(CONF_SERVICE_ENTITY_ID)
if isinstance(entity_id, str):
service_data[ATTR_ENTITY_ID] = [ent.strip() for ent in
entity_id.split(",")]
elif entity_id is not None:
service_data[ATTR_ENTITY_ID] = entity_id
if CONF_SERVICE_DATA_TEMPLATE in config:
for key, value in config[CONF_SERVICE_DATA_TEMPLATE].items():
service_data[key] = template.render(hass, value, variables)
if CONF_SERVICE_ENTITY_ID in config:
service_data[ATTR_ENTITY_ID] = config[CONF_SERVICE_ENTITY_ID]
hass.services.call(domain, service_name, service_data, blocking)
@ -98,11 +93,8 @@ def validate_service_call(config):
Helper method to validate that a configuration is a valid service call.
Returns None if validation succeeds, else an error description
"""
if not isinstance(config, dict):
return 'Invalid configuration {}'.format(config)
if CONF_SERVICE not in config and CONF_SERVICE_TEMPLATE not in config:
return 'Missing key {} or {}: {}'.format(
CONF_SERVICE,
CONF_SERVICE_TEMPLATE,
config)
return None
try:
cv.SERVICE_SCHEMA(config)
return None
except vol.Invalid as ex:
return str(ex)

View File

@ -2,6 +2,7 @@
import unittest
from unittest.mock import patch
import homeassistant.components # noqa - to prevent circular import
from homeassistant import core as ha, loader
from homeassistant.const import STATE_ON, STATE_OFF, ATTR_ENTITY_ID
from homeassistant.helpers import service
@ -53,6 +54,27 @@ class TestServiceHelpers(unittest.TestCase):
self.assertEqual('goodbye', runs[0].data['hello'])
def test_passing_variables_to_templates(self):
config = {
'service_template': '{{ var_service }}',
'entity_id': 'hello.world',
'data_template': {
'hello': '{{ var_data }}',
},
}
runs = []
decor = service.service('test_domain', 'test_service')
decor(lambda x, y: runs.append(y))
service.call_from_config(self.hass, config, variables={
'var_service': 'test_domain.test_service',
'var_data': 'goodbye',
})
self.hass.pool.block_till_done()
self.assertEqual('goodbye', runs[0].data['hello'])
def test_split_entity_string(self):
"""Test splitting of entity string."""
service.call_from_config(self.hass, {