core/homeassistant/components/automation/__init__.py

208 lines
6.2 KiB
Python
Raw Normal View History

2015-01-16 07:32:27 +00:00
"""
2016-03-07 19:20:07 +00:00
Allow to setup simple automation rules via the config file.
2015-11-09 12:12:18 +00:00
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/automation/
2015-01-16 07:32:27 +00:00
"""
import logging
import voluptuous as vol
2015-08-10 00:12:22 +00:00
from homeassistant.bootstrap import prepare_setup_platform
from homeassistant.const import CONF_PLATFORM
from homeassistant.components import logbook
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import extract_domain_configs, script, condition
from homeassistant.loader import get_platform
import homeassistant.helpers.config_validation as cv
2015-01-16 07:32:27 +00:00
2015-09-15 15:56:06 +00:00
DOMAIN = 'automation'
2015-01-16 07:32:27 +00:00
2015-09-15 15:56:06 +00:00
DEPENDENCIES = ['group']
2015-01-16 07:32:27 +00:00
2015-09-15 15:56:06 +00:00
CONF_ALIAS = 'alias'
2015-09-15 05:05:40 +00:00
2015-09-15 15:56:06 +00:00
CONF_CONDITION = 'condition'
2015-09-15 05:05:40 +00:00
CONF_ACTION = 'action'
2015-09-15 15:56:06 +00:00
CONF_TRIGGER = 'trigger'
CONF_CONDITION_TYPE = 'condition_type'
CONDITION_USE_TRIGGER_VALUES = 'use_trigger_values'
CONDITION_TYPE_AND = 'and'
CONDITION_TYPE_OR = 'or'
DEFAULT_CONDITION_TYPE = CONDITION_TYPE_AND
2015-01-16 07:32:27 +00:00
METHOD_TRIGGER = 'trigger'
METHOD_IF_ACTION = 'if_action'
2015-01-16 07:32:27 +00:00
_LOGGER = logging.getLogger(__name__)
def _platform_validator(method, schema):
"""Generate platform validator for different steps."""
def validator(config):
"""Validate it is a valid platform."""
platform = get_platform(DOMAIN, config[CONF_PLATFORM])
if not hasattr(platform, method):
raise vol.Invalid('invalid method platform')
if not hasattr(platform, schema):
return config
return getattr(platform, schema)(config)
return validator
_TRIGGER_SCHEMA = vol.All(
cv.ensure_list,
[
vol.All(
vol.Schema({
vol.Required(CONF_PLATFORM): cv.platform_validator(DOMAIN)
}, extra=vol.ALLOW_EXTRA),
_platform_validator(METHOD_TRIGGER, 'TRIGGER_SCHEMA')
),
]
)
_CONDITION_SCHEMA = vol.Any(
CONDITION_USE_TRIGGER_VALUES,
vol.All(
cv.ensure_list,
[
vol.All(
vol.Schema({
CONF_PLATFORM: str,
CONF_CONDITION: str,
}, extra=vol.ALLOW_EXTRA),
cv.has_at_least_one_key(CONF_PLATFORM, CONF_CONDITION),
),
]
)
)
PLATFORM_SCHEMA = vol.Schema({
CONF_ALIAS: cv.string,
vol.Required(CONF_TRIGGER): _TRIGGER_SCHEMA,
vol.Required(CONF_CONDITION_TYPE, default=DEFAULT_CONDITION_TYPE):
vol.All(vol.Lower, vol.Any(CONDITION_TYPE_AND, CONDITION_TYPE_OR)),
CONF_CONDITION: _CONDITION_SCHEMA,
vol.Required(CONF_ACTION): cv.SCRIPT_SCHEMA,
})
2015-01-16 07:32:27 +00:00
def setup(hass, config):
2016-03-07 16:14:55 +00:00
"""Setup the automation."""
success = False
for config_key in extract_domain_configs(config, DOMAIN):
conf = config[config_key]
2015-09-18 16:12:27 +00:00
for list_no, config_block in enumerate(conf):
name = config_block.get(CONF_ALIAS, "{}, {}".format(config_key,
list_no))
success = (_setup_automation(hass, config_block, name, config) or
success)
2015-01-16 07:32:27 +00:00
return success
2015-09-14 05:25:42 +00:00
2015-09-18 16:12:27 +00:00
def _setup_automation(hass, config_block, name, config):
2016-03-07 16:14:55 +00:00
"""Setup one instance of automation."""
2015-09-18 16:12:27 +00:00
action = _get_action(hass, config_block.get(CONF_ACTION, {}), name)
2015-09-14 05:25:42 +00:00
if CONF_CONDITION in config_block:
2015-09-18 16:12:27 +00:00
action = _process_if(hass, config, config_block, action)
2015-01-16 07:32:27 +00:00
2015-09-18 16:12:27 +00:00
if action is None:
return False
2015-01-16 07:32:27 +00:00
2015-09-18 16:12:27 +00:00
_process_trigger(hass, config, config_block.get(CONF_TRIGGER, []), name,
action)
2015-09-15 05:05:40 +00:00
return True
2015-01-16 07:32:27 +00:00
2015-09-15 05:05:40 +00:00
def _get_action(hass, config, name):
2016-03-07 16:14:55 +00:00
"""Return an action based on a configuration."""
script_obj = script.Script(hass, config, name)
def action(variables=None):
2016-03-07 16:14:55 +00:00
"""Action to be executed."""
_LOGGER.info('Executing %s', name)
logbook.log_entry(hass, name, 'has been triggered', DOMAIN)
script_obj.run(variables)
2015-01-16 07:32:27 +00:00
return action
2015-09-14 05:25:42 +00:00
2015-09-15 15:56:06 +00:00
def _process_if(hass, config, p_config, action):
2016-03-07 19:20:07 +00:00
"""Process if checks."""
2015-09-15 15:56:06 +00:00
cond_type = p_config.get(CONF_CONDITION_TYPE,
DEFAULT_CONDITION_TYPE).lower()
if_configs = p_config.get(CONF_CONDITION)
use_trigger = if_configs == CONDITION_USE_TRIGGER_VALUES
if use_trigger:
if_configs = p_config[CONF_TRIGGER]
checks = []
2015-09-14 05:25:42 +00:00
for if_config in if_configs:
if CONF_PLATFORM in if_config:
if not use_trigger:
_LOGGER.warning("Please switch your condition configuration "
"to use 'condition' instead of 'platform'.")
if_config = dict(if_config)
if_config[CONF_CONDITION] = if_config.pop(CONF_PLATFORM)
try:
checks.append(condition.from_config(if_config))
except HomeAssistantError as ex:
# Invalid conditions are allowed if we base it on trigger
if use_trigger:
_LOGGER.warning('Ignoring invalid condition: %s', ex)
else:
_LOGGER.warning('Invalid condition: %s', ex)
return None
if cond_type == CONDITION_TYPE_AND:
def if_action(variables=None):
2016-03-07 16:14:55 +00:00
"""AND all conditions."""
if all(check(hass, variables) for check in checks):
action(variables)
else:
def if_action(variables=None):
2016-03-07 16:14:55 +00:00
"""OR all conditions."""
if any(check(hass, variables) for check in checks):
action(variables)
return if_action
2015-09-14 05:25:42 +00:00
2015-09-15 05:05:40 +00:00
def _process_trigger(hass, config, trigger_configs, name, action):
2016-03-07 16:14:55 +00:00
"""Setup the triggers."""
2015-09-15 05:05:40 +00:00
for conf in trigger_configs:
platform = _resolve_platform(METHOD_TRIGGER, hass, config,
2015-09-15 05:05:40 +00:00
conf.get(CONF_PLATFORM))
if platform is None:
2015-09-14 05:25:42 +00:00
continue
2015-09-15 05:05:40 +00:00
if platform.trigger(hass, conf, action):
_LOGGER.info("Initialized rule %s", name)
else:
_LOGGER.error("Error setting up rule %s", name)
2015-09-14 05:25:42 +00:00
2015-09-15 05:05:40 +00:00
2015-09-15 15:56:06 +00:00
def _resolve_platform(method, hass, config, platform):
2016-03-07 16:14:55 +00:00
"""Find the automation platform."""
2015-09-15 05:05:40 +00:00
if platform is None:
return None
platform = prepare_setup_platform(hass, config, DOMAIN, platform)
2015-09-15 15:56:06 +00:00
if platform is None or not hasattr(platform, method):
2015-09-15 05:05:40 +00:00
_LOGGER.error("Unknown automation platform specified for %s: %s",
2015-09-15 15:56:06 +00:00
method, platform)
2015-09-15 05:05:40 +00:00
return None
return platform