mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Add automation config validation
* Add automation config validation * Remove unnecessary dict validator * Downgrade voluptuous to 0.8.9 * Fix linting * Address issues
This commit is contained in:
parent
cbe9a7d2a3
commit
8ef542927f
@ -72,6 +72,7 @@ omit =
|
||||
homeassistant/components/camera/foscam.py
|
||||
homeassistant/components/camera/generic.py
|
||||
homeassistant/components/camera/mjpeg.py
|
||||
homeassistant/components/camera/rpi_camera.py
|
||||
homeassistant/components/device_tracker/actiontec.py
|
||||
homeassistant/components/device_tracker/aruba.py
|
||||
homeassistant/components/device_tracker/asuswrt.py
|
||||
|
@ -21,7 +21,7 @@ import homeassistant.util.package as pkg_util
|
||||
from homeassistant.const import (
|
||||
CONF_CUSTOMIZE, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME,
|
||||
CONF_TEMPERATURE_UNIT, CONF_TIME_ZONE, EVENT_COMPONENT_LOADED,
|
||||
TEMP_CELCIUS, TEMP_FAHRENHEIT, __version__)
|
||||
TEMP_CELCIUS, TEMP_FAHRENHEIT, PLATFORM_FORMAT, __version__)
|
||||
from homeassistant.helpers import (
|
||||
event_decorators, service, config_per_platform, extract_domain_configs)
|
||||
from homeassistant.helpers.entity import Entity
|
||||
@ -32,7 +32,6 @@ _CURRENT_SETUP = []
|
||||
|
||||
ATTR_COMPONENT = 'component'
|
||||
|
||||
PLATFORM_FORMAT = '{}.{}'
|
||||
ERROR_LOG_FILENAME = 'home-assistant.log'
|
||||
|
||||
|
||||
@ -117,6 +116,13 @@ def _setup_component(hass, domain, config):
|
||||
domain, ex, p_config)
|
||||
return False
|
||||
|
||||
# Not all platform components follow same pattern for platforms
|
||||
# Sof if p_name is None we are not going to validate platform
|
||||
# (the automation component is one of them)
|
||||
if p_name is None:
|
||||
platforms.append(p_validated)
|
||||
continue
|
||||
|
||||
platform = prepare_setup_platform(hass, config, domain,
|
||||
p_name)
|
||||
|
||||
@ -176,7 +182,7 @@ def prepare_setup_platform(hass, config, domain, platform_name):
|
||||
|
||||
platform_path = PLATFORM_FORMAT.format(domain, platform_name)
|
||||
|
||||
platform = loader.get_component(platform_path)
|
||||
platform = loader.get_platform(domain, platform_name)
|
||||
|
||||
# Not found
|
||||
if platform is None:
|
||||
|
@ -6,13 +6,15 @@ https://home-assistant.io/components/automation/
|
||||
"""
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.bootstrap import prepare_setup_platform
|
||||
from homeassistant.const import CONF_PLATFORM
|
||||
from homeassistant.components import logbook
|
||||
from homeassistant.helpers import extract_domain_configs
|
||||
from homeassistant.helpers.service import (call_from_config,
|
||||
validate_service_call)
|
||||
|
||||
from homeassistant.helpers.service import call_from_config
|
||||
from homeassistant.loader import get_platform
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
DOMAIN = 'automation'
|
||||
|
||||
@ -31,17 +33,72 @@ CONDITION_TYPE_OR = 'or'
|
||||
|
||||
DEFAULT_CONDITION_TYPE = CONDITION_TYPE_AND
|
||||
|
||||
METHOD_TRIGGER = 'trigger'
|
||||
METHOD_IF_ACTION = 'if_action'
|
||||
|
||||
_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
|
||||
|
||||
print('validating config', method, 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({
|
||||
vol.Required(CONF_PLATFORM): cv.platform_validator(DOMAIN),
|
||||
}, extra=vol.ALLOW_EXTRA),
|
||||
_platform_validator(METHOD_IF_ACTION, 'IF_ACTION_SCHEMA'),
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
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.SERVICE_SCHEMA,
|
||||
})
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
"""Setup the automation."""
|
||||
for config_key in extract_domain_configs(config, DOMAIN):
|
||||
conf = config[config_key]
|
||||
|
||||
if not isinstance(conf, list):
|
||||
conf = [conf]
|
||||
|
||||
for list_no, config_block in enumerate(conf):
|
||||
name = config_block.get(CONF_ALIAS, "{}, {}".format(config_key,
|
||||
list_no))
|
||||
@ -54,10 +111,7 @@ def _setup_automation(hass, config_block, name, config):
|
||||
"""Setup one instance of automation."""
|
||||
action = _get_action(hass, config_block.get(CONF_ACTION, {}), name)
|
||||
|
||||
if action is None:
|
||||
return False
|
||||
|
||||
if CONF_CONDITION in config_block or CONF_CONDITION_TYPE in config_block:
|
||||
if CONF_CONDITION in config_block:
|
||||
action = _process_if(hass, config, config_block, action)
|
||||
|
||||
if action is None:
|
||||
@ -70,11 +124,6 @@ def _setup_automation(hass, config_block, name, config):
|
||||
|
||||
def _get_action(hass, config, name):
|
||||
"""Return an action based on a configuration."""
|
||||
validation_error = validate_service_call(config)
|
||||
if validation_error:
|
||||
_LOGGER.error(validation_error)
|
||||
return None
|
||||
|
||||
def action():
|
||||
"""Action to be executed."""
|
||||
_LOGGER.info('Executing %s', name)
|
||||
@ -96,12 +145,9 @@ def _process_if(hass, config, p_config, action):
|
||||
if use_trigger:
|
||||
if_configs = p_config[CONF_TRIGGER]
|
||||
|
||||
if isinstance(if_configs, dict):
|
||||
if_configs = [if_configs]
|
||||
|
||||
checks = []
|
||||
for if_config in if_configs:
|
||||
platform = _resolve_platform('if_action', hass, config,
|
||||
platform = _resolve_platform(METHOD_IF_ACTION, hass, config,
|
||||
if_config.get(CONF_PLATFORM))
|
||||
if platform is None:
|
||||
continue
|
||||
@ -134,7 +180,7 @@ def _process_trigger(hass, config, trigger_configs, name, action):
|
||||
trigger_configs = [trigger_configs]
|
||||
|
||||
for conf in trigger_configs:
|
||||
platform = _resolve_platform('trigger', hass, config,
|
||||
platform = _resolve_platform(METHOD_TRIGGER, hass, config,
|
||||
conf.get(CONF_PLATFORM))
|
||||
if platform is None:
|
||||
continue
|
||||
|
@ -4,16 +4,17 @@ Offer state listening automation rules.
|
||||
For more details about this automation rule, please refer to the documentation
|
||||
at https://home-assistant.io/components/automation/#state-trigger
|
||||
"""
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
import homeassistant.util.dt as dt_util
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.util.dt as dt_util
|
||||
from homeassistant.const import (
|
||||
EVENT_STATE_CHANGED, EVENT_TIME_CHANGED, MATCH_ALL)
|
||||
EVENT_STATE_CHANGED, EVENT_TIME_CHANGED, MATCH_ALL, CONF_PLATFORM)
|
||||
from homeassistant.components.automation.time import (
|
||||
CONF_HOURS, CONF_MINUTES, CONF_SECONDS)
|
||||
from homeassistant.helpers.event import track_state_change, track_point_in_time
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
CONF_ENTITY_ID = "entity_id"
|
||||
CONF_FROM = "from"
|
||||
@ -21,6 +22,33 @@ CONF_TO = "to"
|
||||
CONF_STATE = "state"
|
||||
CONF_FOR = "for"
|
||||
|
||||
BASE_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_PLATFORM): 'state',
|
||||
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
||||
# These are str on purpose. Want to catch YAML conversions
|
||||
CONF_STATE: str,
|
||||
CONF_FOR: vol.All(vol.Schema({
|
||||
CONF_HOURS: vol.Coerce(int),
|
||||
CONF_MINUTES: vol.Coerce(int),
|
||||
CONF_SECONDS: vol.Coerce(int),
|
||||
}), cv.has_at_least_one_key(CONF_HOURS, CONF_MINUTES, CONF_SECONDS)),
|
||||
})
|
||||
|
||||
TRIGGER_SCHEMA = vol.Schema(vol.All(
|
||||
BASE_SCHEMA.extend({
|
||||
# These are str on purpose. Want to catch YAML conversions
|
||||
CONF_FROM: str,
|
||||
CONF_TO: str,
|
||||
}),
|
||||
vol.Any(cv.key_dependency(CONF_FOR, CONF_TO),
|
||||
cv.key_dependency(CONF_FOR, CONF_STATE))
|
||||
))
|
||||
|
||||
IF_ACTION_SCHEMA = vol.Schema(vol.All(
|
||||
BASE_SCHEMA,
|
||||
cv.key_dependency(CONF_FOR, CONF_STATE)
|
||||
))
|
||||
|
||||
|
||||
def get_time_config(config):
|
||||
"""Helper function to extract the time specified in the configuration."""
|
||||
@ -31,18 +59,6 @@ def get_time_config(config):
|
||||
minutes = config[CONF_FOR].get(CONF_MINUTES)
|
||||
seconds = config[CONF_FOR].get(CONF_SECONDS)
|
||||
|
||||
if hours is None and minutes is None and seconds is None:
|
||||
logging.getLogger(__name__).error(
|
||||
"Received invalid value for '%s': %s",
|
||||
config[CONF_FOR], CONF_FOR)
|
||||
return None
|
||||
|
||||
if config.get(CONF_TO) is None and config.get(CONF_STATE) is None:
|
||||
logging.getLogger(__name__).error(
|
||||
"For: requires a to: value'%s': %s",
|
||||
config[CONF_FOR], CONF_FOR)
|
||||
return None
|
||||
|
||||
return timedelta(hours=(hours or 0.0),
|
||||
minutes=(minutes or 0.0),
|
||||
seconds=(seconds or 0.0))
|
||||
@ -51,24 +67,10 @@ def get_time_config(config):
|
||||
def trigger(hass, config, action):
|
||||
"""Listen for state changes based on configuration."""
|
||||
entity_id = config.get(CONF_ENTITY_ID)
|
||||
|
||||
if entity_id is None:
|
||||
logging.getLogger(__name__).error(
|
||||
"Missing trigger configuration key %s", CONF_ENTITY_ID)
|
||||
return None
|
||||
|
||||
from_state = config.get(CONF_FROM, MATCH_ALL)
|
||||
to_state = config.get(CONF_TO) or config.get(CONF_STATE) or MATCH_ALL
|
||||
time_delta = get_time_config(config)
|
||||
|
||||
if isinstance(from_state, bool) or isinstance(to_state, bool):
|
||||
logging.getLogger(__name__).error(
|
||||
'Config error. Surround to/from values with quotes.')
|
||||
return None
|
||||
|
||||
if CONF_FOR in config and time_delta is None:
|
||||
return None
|
||||
|
||||
def state_automation_listener(entity, from_s, to_s):
|
||||
"""Listen for state changes and calls action."""
|
||||
def state_for_listener(now):
|
||||
@ -105,18 +107,7 @@ def if_action(hass, config):
|
||||
"""Wrap action method with state based condition."""
|
||||
entity_id = config.get(CONF_ENTITY_ID)
|
||||
state = config.get(CONF_STATE)
|
||||
|
||||
if entity_id is None or state is None:
|
||||
logging.getLogger(__name__).error(
|
||||
"Missing if-condition configuration key %s or %s", CONF_ENTITY_ID,
|
||||
CONF_STATE)
|
||||
return None
|
||||
|
||||
time_delta = get_time_config(config)
|
||||
if CONF_FOR in config and time_delta is None:
|
||||
return None
|
||||
|
||||
state = str(state)
|
||||
|
||||
def if_state():
|
||||
"""Test if condition."""
|
||||
|
@ -4,12 +4,16 @@ Offer sun based automation rules.
|
||||
For more details about this automation rule, please refer to the documentation
|
||||
at https://home-assistant.io/components/automation/#sun-trigger
|
||||
"""
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import CONF_PLATFORM
|
||||
import homeassistant.util.dt as dt_util
|
||||
from homeassistant.components import sun
|
||||
from homeassistant.helpers.event import track_sunrise, track_sunset
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
DEPENDENCIES = ['sun']
|
||||
|
||||
@ -26,22 +30,30 @@ EVENT_SUNRISE = 'sunrise'
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
_SUN_EVENT = vol.All(vol.Lower, vol.Any(EVENT_SUNRISE, EVENT_SUNSET))
|
||||
|
||||
TRIGGER_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_PLATFORM): 'sun',
|
||||
vol.Required(CONF_EVENT): _SUN_EVENT,
|
||||
vol.Required(CONF_OFFSET, default=timedelta(0)): cv.time_offset,
|
||||
})
|
||||
|
||||
IF_ACTION_SCHEMA = vol.All(
|
||||
vol.Schema({
|
||||
vol.Required(CONF_PLATFORM): 'sun',
|
||||
CONF_BEFORE: _SUN_EVENT,
|
||||
CONF_AFTER: _SUN_EVENT,
|
||||
vol.Required(CONF_BEFORE_OFFSET, default=timedelta(0)): cv.time_offset,
|
||||
vol.Required(CONF_AFTER_OFFSET, default=timedelta(0)): cv.time_offset,
|
||||
}),
|
||||
cv.has_at_least_one_key(CONF_BEFORE, CONF_AFTER),
|
||||
)
|
||||
|
||||
|
||||
def trigger(hass, config, action):
|
||||
"""Listen for events based on configuration."""
|
||||
event = config.get(CONF_EVENT)
|
||||
|
||||
if event is None:
|
||||
_LOGGER.error("Missing configuration key %s", CONF_EVENT)
|
||||
return False
|
||||
|
||||
event = event.lower()
|
||||
if event not in (EVENT_SUNRISE, EVENT_SUNSET):
|
||||
_LOGGER.error("Invalid value for %s: %s", CONF_EVENT, event)
|
||||
return False
|
||||
|
||||
offset = _parse_offset(config.get(CONF_OFFSET))
|
||||
if offset is False:
|
||||
return False
|
||||
offset = config.get(CONF_OFFSET)
|
||||
|
||||
# Do something to call action
|
||||
if event == EVENT_SUNRISE:
|
||||
@ -56,26 +68,8 @@ def if_action(hass, config):
|
||||
"""Wrap action method with sun based condition."""
|
||||
before = config.get(CONF_BEFORE)
|
||||
after = config.get(CONF_AFTER)
|
||||
|
||||
# Make sure required configuration keys are present
|
||||
if before is None and after is None:
|
||||
logging.getLogger(__name__).error(
|
||||
"Missing if-condition configuration key %s or %s",
|
||||
CONF_BEFORE, CONF_AFTER)
|
||||
return None
|
||||
|
||||
# Make sure configuration keys have the right value
|
||||
if before not in (None, EVENT_SUNRISE, EVENT_SUNSET) or \
|
||||
after not in (None, EVENT_SUNRISE, EVENT_SUNSET):
|
||||
logging.getLogger(__name__).error(
|
||||
"%s and %s can only be set to %s or %s",
|
||||
CONF_BEFORE, CONF_AFTER, EVENT_SUNRISE, EVENT_SUNSET)
|
||||
return None
|
||||
|
||||
before_offset = _parse_offset(config.get(CONF_BEFORE_OFFSET))
|
||||
after_offset = _parse_offset(config.get(CONF_AFTER_OFFSET))
|
||||
if before_offset is False or after_offset is False:
|
||||
return None
|
||||
before_offset = config.get(CONF_BEFORE_OFFSET)
|
||||
after_offset = config.get(CONF_AFTER_OFFSET)
|
||||
|
||||
if before is None:
|
||||
def before_func():
|
||||
@ -120,27 +114,3 @@ def if_action(hass, config):
|
||||
return True
|
||||
|
||||
return time_if
|
||||
|
||||
|
||||
def _parse_offset(raw_offset):
|
||||
"""Parse the offset."""
|
||||
if raw_offset is None:
|
||||
return timedelta(0)
|
||||
|
||||
negative_offset = False
|
||||
if raw_offset.startswith('-'):
|
||||
negative_offset = True
|
||||
raw_offset = raw_offset[1:]
|
||||
|
||||
try:
|
||||
(hour, minute, second) = [int(x) for x in raw_offset.split(':')]
|
||||
except ValueError:
|
||||
_LOGGER.error('Could not parse offset %s', raw_offset)
|
||||
return False
|
||||
|
||||
offset = timedelta(hours=hour, minutes=minute, seconds=second)
|
||||
|
||||
if negative_offset:
|
||||
offset *= -1
|
||||
|
||||
return offset
|
||||
|
@ -6,21 +6,27 @@ at https://home-assistant.io/components/automation/#template-trigger
|
||||
"""
|
||||
import logging
|
||||
|
||||
from homeassistant.const import CONF_VALUE_TEMPLATE, EVENT_STATE_CHANGED
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_VALUE_TEMPLATE, EVENT_STATE_CHANGED, CONF_PLATFORM)
|
||||
from homeassistant.exceptions import TemplateError
|
||||
from homeassistant.helpers import template
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
TRIGGER_SCHEMA = IF_ACTION_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_PLATFORM): 'template',
|
||||
vol.Required(CONF_VALUE_TEMPLATE): cv.template,
|
||||
})
|
||||
|
||||
|
||||
def trigger(hass, config, action):
|
||||
"""Listen for state changes based on configuration."""
|
||||
value_template = config.get(CONF_VALUE_TEMPLATE)
|
||||
|
||||
if value_template is None:
|
||||
_LOGGER.error("Missing configuration key %s", CONF_VALUE_TEMPLATE)
|
||||
return False
|
||||
|
||||
# Local variable to keep track of if the action has already been triggered
|
||||
already_triggered = False
|
||||
|
||||
@ -44,10 +50,6 @@ def if_action(hass, config):
|
||||
"""Wrap action method with state based condition."""
|
||||
value_template = config.get(CONF_VALUE_TEMPLATE)
|
||||
|
||||
if value_template is None:
|
||||
_LOGGER.error("Missing configuration key %s", CONF_VALUE_TEMPLATE)
|
||||
return False
|
||||
|
||||
return lambda: _check_template(hass, value_template)
|
||||
|
||||
|
||||
|
@ -4,12 +4,13 @@ Offer zone automation rules.
|
||||
For more details about this automation rule, please refer to the documentation
|
||||
at https://home-assistant.io/components/automation/#zone-trigger
|
||||
"""
|
||||
import logging
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components import zone
|
||||
from homeassistant.const import (
|
||||
ATTR_GPS_ACCURACY, ATTR_LATITUDE, ATTR_LONGITUDE, MATCH_ALL)
|
||||
ATTR_GPS_ACCURACY, ATTR_LATITUDE, ATTR_LONGITUDE, MATCH_ALL, CONF_PLATFORM)
|
||||
from homeassistant.helpers.event import track_state_change
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
CONF_ENTITY_ID = "entity_id"
|
||||
CONF_ZONE = "zone"
|
||||
@ -18,19 +19,26 @@ EVENT_ENTER = "enter"
|
||||
EVENT_LEAVE = "leave"
|
||||
DEFAULT_EVENT = EVENT_ENTER
|
||||
|
||||
TRIGGER_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_PLATFORM): 'zone',
|
||||
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
||||
vol.Required(CONF_ZONE): cv.entity_id,
|
||||
vol.Required(CONF_EVENT, default=DEFAULT_EVENT):
|
||||
vol.Any(EVENT_ENTER, EVENT_LEAVE),
|
||||
})
|
||||
|
||||
IF_ACTION_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_PLATFORM): 'zone',
|
||||
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
||||
vol.Required(CONF_ZONE): cv.entity_id,
|
||||
})
|
||||
|
||||
|
||||
def trigger(hass, config, action):
|
||||
"""Listen for state changes based on configuration."""
|
||||
entity_id = config.get(CONF_ENTITY_ID)
|
||||
zone_entity_id = config.get(CONF_ZONE)
|
||||
|
||||
if entity_id is None or zone_entity_id is None:
|
||||
logging.getLogger(__name__).error(
|
||||
"Missing trigger configuration key %s or %s", CONF_ENTITY_ID,
|
||||
CONF_ZONE)
|
||||
return False
|
||||
|
||||
event = config.get(CONF_EVENT, DEFAULT_EVENT)
|
||||
event = config.get(CONF_EVENT)
|
||||
|
||||
def zone_automation_listener(entity, from_s, to_s):
|
||||
"""Listen for state changes and calls action."""
|
||||
@ -59,12 +67,6 @@ def if_action(hass, config):
|
||||
entity_id = config.get(CONF_ENTITY_ID)
|
||||
zone_entity_id = config.get(CONF_ZONE)
|
||||
|
||||
if entity_id is None or zone_entity_id is None:
|
||||
logging.getLogger(__name__).error(
|
||||
"Missing condition configuration key %s or %s", CONF_ENTITY_ID,
|
||||
CONF_ZONE)
|
||||
return False
|
||||
|
||||
def if_in_zone():
|
||||
"""Test if condition."""
|
||||
return _in_zone(hass, zone_entity_id, hass.states.get(entity_id))
|
||||
|
@ -77,9 +77,9 @@ _DELAY_SCHEMA = {
|
||||
'minutes': vol.All(vol.Coerce(int), vol.Range(min=0)),
|
||||
'hours': vol.All(vol.Coerce(int), vol.Range(min=0)),
|
||||
'weeks': vol.All(vol.Coerce(int), vol.Range(min=0)),
|
||||
}, cv.has_at_least_one_key([
|
||||
}, cv.has_at_least_one_key(
|
||||
'days', 'seconds', 'microseconds', 'milliseconds', 'minutes', 'hours',
|
||||
'weeks']))
|
||||
'weeks'))
|
||||
}
|
||||
|
||||
_EVENT_SCHEMA = cv.EVENT_SCHEMA.extend({
|
||||
@ -97,7 +97,7 @@ _SCRIPT_ENTRY_SCHEMA = vol.Schema({
|
||||
})
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
vol.Required(DOMAIN): cv.DictValidator(_SCRIPT_ENTRY_SCHEMA, cv.slug)
|
||||
vol.Required(DOMAIN): {cv.slug: _SCRIPT_ENTRY_SCHEMA}
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
__version__ = "0.17.0.dev0"
|
||||
REQUIRED_PYTHON_VER = (3, 4)
|
||||
|
||||
PLATFORM_FORMAT = '{}.{}'
|
||||
|
||||
# Can be used to specify a catch all when registering state or event listeners.
|
||||
MATCH_ALL = '*'
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
"""Helpers for config validation using voluptuous."""
|
||||
from datetime import timedelta
|
||||
|
||||
import jinja2
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.loader import get_platform
|
||||
from homeassistant.const import (
|
||||
CONF_PLATFORM, CONF_SCAN_INTERVAL, TEMP_CELCIUS, TEMP_FAHRENHEIT)
|
||||
from homeassistant.helpers.entity import valid_entity_id
|
||||
@ -11,7 +14,6 @@ from homeassistant.util import slugify
|
||||
# pylint: disable=invalid-name
|
||||
|
||||
# Home Assistant types
|
||||
|
||||
byte = vol.All(vol.Coerce(int), vol.Range(min=0, max=255))
|
||||
small_float = vol.All(vol.Coerce(float), vol.Range(min=0, max=1))
|
||||
latitude = vol.All(vol.Coerce(float), vol.Range(min=-90, max=90),
|
||||
@ -32,6 +34,11 @@ def boolean(value):
|
||||
return bool(value)
|
||||
|
||||
|
||||
def ensure_list(value):
|
||||
"""Wrap value in list if it is not one."""
|
||||
return value if isinstance(value, list) else [value]
|
||||
|
||||
|
||||
def entity_id(value):
|
||||
"""Validate Entity ID."""
|
||||
if valid_entity_id(value):
|
||||
@ -61,6 +68,59 @@ def icon(value):
|
||||
raise vol.Invalid('Icons should start with prefix "mdi:"')
|
||||
|
||||
|
||||
def time_offset(value):
|
||||
"""Validate and transform time offset."""
|
||||
if not isinstance(value, str):
|
||||
raise vol.Invalid('offset should be a string')
|
||||
|
||||
negative_offset = False
|
||||
if value.startswith('-'):
|
||||
negative_offset = True
|
||||
value = value[1:]
|
||||
elif value.startswith('+'):
|
||||
value = value[1:]
|
||||
|
||||
try:
|
||||
parsed = [int(x) for x in value.split(':')]
|
||||
except ValueError:
|
||||
raise vol.Invalid(
|
||||
'offset {} should be format HH:MM or HH:MM:SS'.format(value))
|
||||
|
||||
if len(parsed) == 2:
|
||||
hour, minute = parsed
|
||||
second = 0
|
||||
elif len(parsed) == 3:
|
||||
hour, minute, second = parsed
|
||||
else:
|
||||
raise vol.Invalid(
|
||||
'offset {} should be format HH:MM or HH:MM:SS'.format(value))
|
||||
|
||||
offset = timedelta(hours=hour, minutes=minute, seconds=second)
|
||||
|
||||
if negative_offset:
|
||||
offset *= -1
|
||||
|
||||
return offset
|
||||
|
||||
|
||||
def match_all(value):
|
||||
"""Validator that matches all values."""
|
||||
return value
|
||||
|
||||
|
||||
def platform_validator(domain):
|
||||
"""Validate if platform exists for given domain."""
|
||||
def validator(value):
|
||||
"""Test if platform exists."""
|
||||
if value is None:
|
||||
raise vol.Invalid('platform cannot be None')
|
||||
if get_platform(domain, str(value)):
|
||||
return value
|
||||
raise vol.Invalid(
|
||||
'platform {} does not exist for {}'.format(value, domain))
|
||||
return validator
|
||||
|
||||
|
||||
def service(value):
|
||||
"""Validate service."""
|
||||
# Services use same format as entities so we can use same helper.
|
||||
@ -122,60 +182,24 @@ def time_zone(value):
|
||||
|
||||
# Validator helpers
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
def key_dependency(key, dependency):
|
||||
"""Validate that all dependencies exist for key."""
|
||||
def validator(value):
|
||||
"""Test dependencies."""
|
||||
if not isinstance(value, dict):
|
||||
raise vol.Invalid('key dependencies require a dict')
|
||||
print(key, value)
|
||||
if key in value and dependency not in value:
|
||||
raise vol.Invalid('dependency violation - key "{}" requires '
|
||||
'key "{}" to exist'.format(key, dependency))
|
||||
|
||||
class DictValidator(object):
|
||||
"""Validate keys and values in a dictionary."""
|
||||
|
||||
def __init__(self, value_validator=None, key_validator=None):
|
||||
"""Initialize the dict validator."""
|
||||
if value_validator is not None:
|
||||
value_validator = vol.Schema(value_validator)
|
||||
|
||||
self.value_validator = value_validator
|
||||
|
||||
if key_validator is not None:
|
||||
key_validator = vol.Schema(key_validator)
|
||||
|
||||
self.key_validator = key_validator
|
||||
|
||||
def __call__(self, obj):
|
||||
"""Validate the dict."""
|
||||
if not isinstance(obj, dict):
|
||||
raise vol.Invalid('Expected dictionary.')
|
||||
|
||||
errors = []
|
||||
|
||||
# So we keep it an OrderedDict if it is one
|
||||
result = obj.__class__()
|
||||
|
||||
for key, value in obj.items():
|
||||
if self.key_validator is not None:
|
||||
try:
|
||||
key = self.key_validator(key)
|
||||
except vol.Invalid as ex:
|
||||
errors.append('key {} is invalid ({})'.format(key, ex))
|
||||
|
||||
if self.value_validator is not None:
|
||||
try:
|
||||
value = self.value_validator(value)
|
||||
except vol.Invalid as ex:
|
||||
errors.append(
|
||||
'key {} contains invalid value ({})'.format(key, ex))
|
||||
|
||||
if not errors:
|
||||
result[key] = value
|
||||
|
||||
if errors:
|
||||
raise vol.Invalid(
|
||||
'invalid dictionary: {}'.format(', '.join(errors)))
|
||||
|
||||
return result
|
||||
return value
|
||||
return validator
|
||||
|
||||
|
||||
# Adapted from:
|
||||
# https://github.com/alecthomas/voluptuous/issues/115#issuecomment-144464666
|
||||
def has_at_least_one_key(keys):
|
||||
def has_at_least_one_key(*keys):
|
||||
"""Validator that at least one key exists."""
|
||||
def validate(obj):
|
||||
"""Test keys exist in dict."""
|
||||
@ -206,5 +230,6 @@ 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'): DictValidator(template),
|
||||
}), has_at_least_one_key(['service', 'service_template']))
|
||||
vol.Exclusive('data_template', 'service data'): {match_all: template},
|
||||
'entity_id': entity_ids,
|
||||
}), has_at_least_one_key('service', 'service_template'))
|
||||
|
@ -16,6 +16,7 @@ import os
|
||||
import pkgutil
|
||||
import sys
|
||||
|
||||
from homeassistant.const import PLATFORM_FORMAT
|
||||
from homeassistant.util import OrderedSet
|
||||
|
||||
PREPARED = False
|
||||
@ -77,6 +78,11 @@ def set_component(comp_name, component):
|
||||
_COMPONENT_CACHE[comp_name] = component
|
||||
|
||||
|
||||
def get_platform(domain, platform):
|
||||
"""Try to load specified platform."""
|
||||
return get_component(PLATFORM_FORMAT.format(domain, platform))
|
||||
|
||||
|
||||
def get_component(comp_name):
|
||||
"""Try to load specified component.
|
||||
|
||||
|
@ -5,7 +5,7 @@ pytz>=2016.3
|
||||
pip>=7.0.0
|
||||
vincenty==0.1.4
|
||||
jinja2>=2.8
|
||||
voluptuous==0.8.10
|
||||
voluptuous==0.8.9
|
||||
|
||||
# homeassistant.components.isy994
|
||||
PyISY==1.0.5
|
||||
|
2
setup.py
2
setup.py
@ -17,7 +17,7 @@ REQUIRES = [
|
||||
'pip>=7.0.0',
|
||||
'vincenty==0.1.4',
|
||||
'jinja2>=2.8',
|
||||
'voluptuous==0.8.10',
|
||||
'voluptuous==0.8.9',
|
||||
]
|
||||
|
||||
setup(
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""The tests for the Event automation."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
import homeassistant.components.automation as automation
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
@ -12,6 +13,7 @@ class TestAutomationEvent(unittest.TestCase):
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.components.append('group')
|
||||
self.calls = []
|
||||
|
||||
def record_call(service):
|
||||
@ -26,7 +28,7 @@ class TestAutomationEvent(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_event(self):
|
||||
"""Test the firing of events."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -36,7 +38,7 @@ class TestAutomationEvent(unittest.TestCase):
|
||||
'service': 'test.automation',
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.bus.fire('test_event')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -44,7 +46,7 @@ class TestAutomationEvent(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_event_with_data(self):
|
||||
"""Test the firing of events with data."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -55,7 +57,7 @@ class TestAutomationEvent(unittest.TestCase):
|
||||
'service': 'test.automation',
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.bus.fire('test_event', {'some_attr': 'some_value',
|
||||
'another': 'value'})
|
||||
@ -64,7 +66,7 @@ class TestAutomationEvent(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_if_event_data_not_matches(self):
|
||||
"""Test firing of event if no match."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -75,7 +77,7 @@ class TestAutomationEvent(unittest.TestCase):
|
||||
'service': 'test.automation',
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.bus.fire('test_event', {'some_attr': 'some_other_value'})
|
||||
self.hass.pool.block_till_done()
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""The tests for the automation component."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
import homeassistant.components.automation as automation
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
|
||||
@ -13,6 +14,7 @@ class TestAutomation(unittest.TestCase):
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.components.append('group')
|
||||
self.calls = []
|
||||
|
||||
def record_call(service):
|
||||
@ -26,7 +28,7 @@ class TestAutomation(unittest.TestCase):
|
||||
|
||||
def test_service_data_not_a_dict(self):
|
||||
"""Test service data not dict."""
|
||||
automation.setup(self.hass, {
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -39,13 +41,9 @@ class TestAutomation(unittest.TestCase):
|
||||
}
|
||||
})
|
||||
|
||||
self.hass.bus.fire('test_event')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
|
||||
def test_service_specify_data(self):
|
||||
"""Test service data."""
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -65,7 +63,7 @@ class TestAutomation(unittest.TestCase):
|
||||
|
||||
def test_service_specify_entity_id(self):
|
||||
"""Test service data."""
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -86,7 +84,7 @@ class TestAutomation(unittest.TestCase):
|
||||
|
||||
def test_service_specify_entity_id_list(self):
|
||||
"""Test service data."""
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -107,7 +105,7 @@ class TestAutomation(unittest.TestCase):
|
||||
|
||||
def test_two_triggers(self):
|
||||
"""Test triggers."""
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': [
|
||||
{
|
||||
@ -135,7 +133,7 @@ class TestAutomation(unittest.TestCase):
|
||||
def test_two_conditions_with_and(self):
|
||||
"""Test two and conditions."""
|
||||
entity_id = 'test.entity'
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': [
|
||||
{
|
||||
@ -147,7 +145,7 @@ class TestAutomation(unittest.TestCase):
|
||||
{
|
||||
'platform': 'state',
|
||||
'entity_id': entity_id,
|
||||
'state': 100
|
||||
'state': '100'
|
||||
},
|
||||
{
|
||||
'platform': 'numeric_state',
|
||||
@ -179,7 +177,7 @@ class TestAutomation(unittest.TestCase):
|
||||
def test_two_conditions_with_or(self):
|
||||
"""Test two or conditions."""
|
||||
entity_id = 'test.entity'
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': [
|
||||
{
|
||||
@ -192,7 +190,7 @@ class TestAutomation(unittest.TestCase):
|
||||
{
|
||||
'platform': 'state',
|
||||
'entity_id': entity_id,
|
||||
'state': 200
|
||||
'state': '200'
|
||||
},
|
||||
{
|
||||
'platform': 'numeric_state',
|
||||
@ -224,13 +222,13 @@ class TestAutomation(unittest.TestCase):
|
||||
def test_using_trigger_as_condition(self):
|
||||
"""Test triggers as condition."""
|
||||
entity_id = 'test.entity'
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': [
|
||||
{
|
||||
'platform': 'state',
|
||||
'entity_id': entity_id,
|
||||
'state': 100
|
||||
'state': '100'
|
||||
},
|
||||
{
|
||||
'platform': 'numeric_state',
|
||||
@ -247,21 +245,21 @@ class TestAutomation(unittest.TestCase):
|
||||
|
||||
self.hass.states.set(entity_id, 100)
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
self.assertEqual(2, len(self.calls))
|
||||
|
||||
self.hass.states.set(entity_id, 120)
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
self.assertEqual(2, len(self.calls))
|
||||
|
||||
self.hass.states.set(entity_id, 151)
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
self.assertEqual(2, len(self.calls))
|
||||
|
||||
def test_using_trigger_as_condition_with_invalid_condition(self):
|
||||
"""Event is not a valid condition."""
|
||||
entity_id = 'test.entity'
|
||||
self.hass.states.set(entity_id, 100)
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': [
|
||||
{
|
||||
@ -287,7 +285,7 @@ class TestAutomation(unittest.TestCase):
|
||||
|
||||
def test_automation_list_setting(self):
|
||||
"""Event is not a valid condition."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
self.assertTrue(_setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: [{
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""The tests for the MQTT automation."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
import homeassistant.components.automation as automation
|
||||
from tests.common import (
|
||||
mock_mqtt_component, fire_mqtt_message, get_test_home_assistant)
|
||||
@ -12,6 +13,7 @@ class TestAutomationMQTT(unittest.TestCase):
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.components.append('group')
|
||||
mock_mqtt_component(self.hass)
|
||||
self.calls = []
|
||||
|
||||
@ -26,7 +28,7 @@ class TestAutomationMQTT(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_topic_match(self):
|
||||
"""Test if message is fired on topic match."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'mqtt',
|
||||
@ -36,7 +38,7 @@ class TestAutomationMQTT(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_mqtt_message(self.hass, 'test-topic', '')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -44,7 +46,7 @@ class TestAutomationMQTT(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_topic_and_payload_match(self):
|
||||
"""Test if message is fired on topic and payload match."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'mqtt',
|
||||
@ -55,7 +57,7 @@ class TestAutomationMQTT(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_mqtt_message(self.hass, 'test-topic', 'hello')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -63,7 +65,7 @@ class TestAutomationMQTT(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_topic_but_no_payload_match(self):
|
||||
"""Test if message is not fired on topic but no payload."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'mqtt',
|
||||
@ -74,7 +76,7 @@ class TestAutomationMQTT(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_mqtt_message(self.hass, 'test-topic', 'no-hello')
|
||||
self.hass.pool.block_till_done()
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""The tests for numeric state automation."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
import homeassistant.components.automation as automation
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
@ -12,6 +13,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.components.append('group')
|
||||
self.calls = []
|
||||
|
||||
def record_call(service):
|
||||
@ -26,7 +28,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_below(self):
|
||||
""""Test the firing with changed entity."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -37,7 +39,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 9 is below 10
|
||||
self.hass.states.set('test.entity', 9)
|
||||
self.hass.pool.block_till_done()
|
||||
@ -48,7 +50,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
self.hass.states.set('test.entity', 11)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -59,7 +61,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
# 9 is below 10
|
||||
self.hass.states.set('test.entity', 9)
|
||||
@ -71,7 +73,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
self.hass.states.set('test.entity', 9)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -82,7 +84,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
# 9 is below 10 so this should not fire again
|
||||
self.hass.states.set('test.entity', 8)
|
||||
@ -91,7 +93,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_above(self):
|
||||
""""Test the firing with changed entity."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -102,7 +104,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 11 is above 10
|
||||
self.hass.states.set('test.entity', 11)
|
||||
self.hass.pool.block_till_done()
|
||||
@ -114,7 +116,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
self.hass.states.set('test.entity', 9)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -125,7 +127,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
# 11 is above 10 and 9 is below
|
||||
self.hass.states.set('test.entity', 11)
|
||||
@ -138,7 +140,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
self.hass.states.set('test.entity', 11)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -149,7 +151,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
# 11 is above 10 so this should fire again
|
||||
self.hass.states.set('test.entity', 12)
|
||||
@ -158,7 +160,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_below_range(self):
|
||||
""""Test the firing with changed entity."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -170,7 +172,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 9 is below 10
|
||||
self.hass.states.set('test.entity', 9)
|
||||
self.hass.pool.block_till_done()
|
||||
@ -178,7 +180,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_below_above_range(self):
|
||||
""""Test the firing with changed entity."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -190,7 +192,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 4 is below 5
|
||||
self.hass.states.set('test.entity', 4)
|
||||
self.hass.pool.block_till_done()
|
||||
@ -201,7 +203,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
self.hass.states.set('test.entity', 11)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -213,7 +215,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
# 9 is below 10
|
||||
self.hass.states.set('test.entity', 9)
|
||||
@ -225,7 +227,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
self.hass.states.set('test.entity', 11)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -237,7 +239,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
# 4 is below 5 so it should not fire
|
||||
self.hass.states.set('test.entity', 4)
|
||||
@ -246,7 +248,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_if_entity_not_match(self):
|
||||
""""Test if not fired with non matching entity."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -256,7 +258,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 11)
|
||||
self.hass.pool.block_till_done()
|
||||
@ -264,7 +266,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_below_with_attribute(self):
|
||||
""""Test attributes change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -275,7 +277,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 9 is below 10
|
||||
self.hass.states.set('test.entity', 9, {'test_attribute': 11})
|
||||
self.hass.pool.block_till_done()
|
||||
@ -283,7 +285,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_entity_change_not_below_with_attribute(self):
|
||||
""""Test attributes."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -294,7 +296,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 11 is not below 10
|
||||
self.hass.states.set('test.entity', 11, {'test_attribute': 9})
|
||||
self.hass.pool.block_till_done()
|
||||
@ -302,7 +304,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_attribute_change_with_attribute_below(self):
|
||||
""""Test attributes change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -314,7 +316,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 9 is below 10
|
||||
self.hass.states.set('test.entity', 'entity', {'test_attribute': 9})
|
||||
self.hass.pool.block_till_done()
|
||||
@ -322,7 +324,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_attribute_change_with_attribute_not_below(self):
|
||||
""""Test attributes change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -334,7 +336,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 11 is not below 10
|
||||
self.hass.states.set('test.entity', 'entity', {'test_attribute': 11})
|
||||
self.hass.pool.block_till_done()
|
||||
@ -342,7 +344,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_entity_change_with_attribute_below(self):
|
||||
""""Test attributes change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -354,7 +356,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 11 is not below 10, entity state value should not be tested
|
||||
self.hass.states.set('test.entity', '9', {'test_attribute': 11})
|
||||
self.hass.pool.block_till_done()
|
||||
@ -362,7 +364,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_entity_change_with_not_attribute_below(self):
|
||||
""""Test attributes change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -374,7 +376,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 11 is not below 10, entity state value should not be tested
|
||||
self.hass.states.set('test.entity', 'entity')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -382,7 +384,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_fires_on_attr_change_with_attribute_below_and_multiple_attr(self):
|
||||
""""Test attributes change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -394,7 +396,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 9 is not below 10
|
||||
self.hass.states.set('test.entity', 'entity',
|
||||
{'test_attribute': 9, 'not_test_attribute': 11})
|
||||
@ -403,7 +405,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_template_list(self):
|
||||
""""Test template list."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -416,7 +418,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 3 is below 10
|
||||
self.hass.states.set('test.entity', 'entity',
|
||||
{'test_attribute': [11, 15, 3]})
|
||||
@ -425,7 +427,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_template_string(self):
|
||||
""""Test template string."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -438,7 +440,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 9 is below 10
|
||||
self.hass.states.set('test.entity', 'entity',
|
||||
{'test_attribute': '0.9'})
|
||||
@ -447,7 +449,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_not_fires_on_attr_change_with_attr_not_below_multiple_attr(self):
|
||||
""""Test if not fired changed attributes."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -459,7 +461,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
# 11 is not below 10
|
||||
self.hass.states.set('test.entity', 'entity',
|
||||
{'test_attribute': 11, 'not_test_attribute': 9})
|
||||
@ -470,7 +472,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
""""Test if action."""
|
||||
entity_id = 'domain.test_entity'
|
||||
test_state = 10
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
|
@ -3,9 +3,9 @@ import unittest
|
||||
from datetime import timedelta
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
import homeassistant.util.dt as dt_util
|
||||
import homeassistant.components.automation as automation
|
||||
import homeassistant.components.automation.state as state
|
||||
|
||||
from tests.common import fire_time_changed, get_test_home_assistant
|
||||
|
||||
@ -16,6 +16,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.components.append('group')
|
||||
self.hass.states.set('test.entity', 'hello')
|
||||
self.calls = []
|
||||
|
||||
@ -30,7 +31,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change(self):
|
||||
"""Test for firing on entity change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -40,7 +41,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -48,7 +49,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_with_from_filter(self):
|
||||
"""Test for firing on entity change with filter."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -59,7 +60,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -67,7 +68,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_with_to_filter(self):
|
||||
"""Test for firing on entity change with no filter."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -78,7 +79,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -86,7 +87,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_with_state_filter(self):
|
||||
"""Test for firing on entity change with state filter."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -97,7 +98,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -105,7 +106,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_with_both_filters(self):
|
||||
"""Test for firing if both filters are a non match."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -117,7 +118,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -125,7 +126,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_if_to_filter_not_match(self):
|
||||
"""Test for not firing if to filter is not a match."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -137,7 +138,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'moon')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -147,7 +148,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
"""Test for not firing if from filter is not a match."""
|
||||
self.hass.states.set('test.entity', 'bye')
|
||||
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -159,7 +160,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -167,7 +168,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_if_entity_not_match(self):
|
||||
"""Test for not firing if entity is not matching."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -177,7 +178,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -187,7 +188,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
"""Test for to action."""
|
||||
entity_id = 'domain.test_entity'
|
||||
test_state = 'new_state'
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -218,48 +219,68 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fails_setup_if_to_boolean_value(self):
|
||||
"""Test for setup failure for boolean to."""
|
||||
self.assertFalse(state.trigger(
|
||||
self.hass, {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'to': True,
|
||||
}, lambda x: x))
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'to': True,
|
||||
},
|
||||
'action': {
|
||||
'service': 'homeassistant.turn_on',
|
||||
}
|
||||
}})
|
||||
|
||||
def test_if_fails_setup_if_from_boolean_value(self):
|
||||
"""Test for setup failure for boolean from."""
|
||||
self.assertFalse(state.trigger(
|
||||
self.hass, {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'from': True,
|
||||
}, lambda x: x))
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'from': True,
|
||||
},
|
||||
'action': {
|
||||
'service': 'homeassistant.turn_on',
|
||||
}
|
||||
}})
|
||||
|
||||
def test_if_fails_setup_bad_for(self):
|
||||
"""Test for setup failure for bad for."""
|
||||
self.assertFalse(state.trigger(
|
||||
self.hass, {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'to': 'world',
|
||||
'for': {
|
||||
'invalid': 5
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'to': 'world',
|
||||
'for': {
|
||||
'invalid': 5
|
||||
},
|
||||
},
|
||||
}, lambda x: x))
|
||||
'action': {
|
||||
'service': 'homeassistant.turn_on',
|
||||
}
|
||||
}})
|
||||
|
||||
def test_if_fails_setup_for_without_to(self):
|
||||
"""Test for setup failures for missing to."""
|
||||
self.assertFalse(state.trigger(
|
||||
self.hass, {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'for': {
|
||||
'seconds': 5
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'for': {
|
||||
'seconds': 5
|
||||
},
|
||||
},
|
||||
}, lambda x: x))
|
||||
'action': {
|
||||
'service': 'homeassistant.turn_on',
|
||||
}
|
||||
}})
|
||||
|
||||
def test_if_not_fires_on_entity_change_with_for(self):
|
||||
"""Test for not firing on entity change with for."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -273,7 +294,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -285,7 +306,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_with_for(self):
|
||||
"""Test for firing on entity change with for."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -299,7 +320,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -314,7 +335,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
with patch('homeassistant.core.dt_util.utcnow') as mock_utcnow:
|
||||
mock_utcnow.return_value = point1
|
||||
self.hass.states.set('test.entity', 'on')
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -328,12 +349,9 @@ class TestAutomationState(unittest.TestCase):
|
||||
'seconds': 5
|
||||
},
|
||||
},
|
||||
|
||||
'action': {
|
||||
'service': 'test.automation'
|
||||
}
|
||||
'action': {'service': 'test.automation'},
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
# not enough time has passed
|
||||
self.hass.bus.fire('test_event')
|
||||
@ -348,21 +366,32 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fails_setup_for_without_time(self):
|
||||
"""Test for setup failure if no time is provided."""
|
||||
self.assertIsNone(state.if_action(
|
||||
self.hass, {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'state': 'on',
|
||||
'for': {},
|
||||
}))
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
'event_type': 'bla'
|
||||
},
|
||||
'condition': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'state': 'on',
|
||||
'for': {},
|
||||
},
|
||||
'action': {'service': 'test.automation'},
|
||||
}})
|
||||
|
||||
def test_if_fails_setup_for_without_entity(self):
|
||||
"""Test for setup failure if no entity is provided."""
|
||||
self.assertIsNone(state.if_action(
|
||||
self.hass, {
|
||||
'platform': 'state',
|
||||
'state': 'on',
|
||||
'for': {
|
||||
'seconds': 5
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {'event_type': 'bla'},
|
||||
'condition': {
|
||||
'platform': 'state',
|
||||
'state': 'on',
|
||||
'for': {
|
||||
'seconds': 5
|
||||
},
|
||||
},
|
||||
}))
|
||||
'action': {'service': 'test.automation'},
|
||||
}})
|
||||
|
@ -3,6 +3,7 @@ from datetime import datetime
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.components import sun
|
||||
import homeassistant.components.automation as automation
|
||||
import homeassistant.util.dt as dt_util
|
||||
@ -16,6 +17,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.components.append('group')
|
||||
self.hass.config.components.append('sun')
|
||||
|
||||
self.calls = []
|
||||
@ -40,7 +42,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
|
||||
with patch('homeassistant.components.automation.sun.dt_util.utcnow',
|
||||
return_value=now):
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'sun',
|
||||
@ -50,7 +52,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
'service': 'test.automation',
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, trigger_time)
|
||||
self.hass.pool.block_till_done()
|
||||
@ -67,7 +69,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
|
||||
with patch('homeassistant.components.automation.sun.dt_util.utcnow',
|
||||
return_value=now):
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'sun',
|
||||
@ -77,7 +79,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
'service': 'test.automation',
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, trigger_time)
|
||||
self.hass.pool.block_till_done()
|
||||
@ -94,7 +96,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
|
||||
with patch('homeassistant.components.automation.sun.dt_util.utcnow',
|
||||
return_value=now):
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'sun',
|
||||
@ -105,7 +107,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
'service': 'test.automation',
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, trigger_time)
|
||||
self.hass.pool.block_till_done()
|
||||
@ -122,7 +124,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
|
||||
with patch('homeassistant.components.automation.sun.dt_util.utcnow',
|
||||
return_value=now):
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'sun',
|
||||
@ -133,7 +135,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
'service': 'test.automation',
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, trigger_time)
|
||||
self.hass.pool.block_till_done()
|
||||
@ -145,7 +147,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
sun.STATE_ATTR_NEXT_RISING: '14:00:00 16-09-2015',
|
||||
})
|
||||
|
||||
automation.setup(self.hass, {
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -181,7 +183,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
sun.STATE_ATTR_NEXT_RISING: '14:00:00 16-09-2015',
|
||||
})
|
||||
|
||||
automation.setup(self.hass, {
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -217,7 +219,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
sun.STATE_ATTR_NEXT_RISING: '14:00:00 16-09-2015',
|
||||
})
|
||||
|
||||
automation.setup(self.hass, {
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -254,7 +256,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
sun.STATE_ATTR_NEXT_RISING: '14:00:00 16-09-2015',
|
||||
})
|
||||
|
||||
automation.setup(self.hass, {
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -292,7 +294,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
sun.STATE_ATTR_NEXT_SETTING: '15:00:00 16-09-2015',
|
||||
})
|
||||
|
||||
automation.setup(self.hass, {
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -338,7 +340,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
sun.STATE_ATTR_NEXT_SETTING: '17:30:00 16-09-2015',
|
||||
})
|
||||
|
||||
automation.setup(self.hass, {
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""The tests fr the Template automation."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
import homeassistant.components.automation as automation
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
@ -12,6 +13,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.components.append('group')
|
||||
self.hass.states.set('test.entity', 'hello')
|
||||
self.calls = []
|
||||
|
||||
@ -27,7 +29,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_bool(self):
|
||||
"""Test for firing on boolean change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -37,7 +39,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -45,7 +47,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_str(self):
|
||||
"""Test for firing on change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -55,7 +57,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -63,7 +65,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_str_crazy(self):
|
||||
"""Test for firing on change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -73,7 +75,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -81,7 +83,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_change_bool(self):
|
||||
"""Test for not firing on boolean change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -91,7 +93,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -99,7 +101,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_change_str(self):
|
||||
"""Test for not firing on string change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -109,7 +111,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -117,7 +119,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_change_str_crazy(self):
|
||||
"""Test for not firing on string change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -127,7 +129,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -135,7 +137,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_no_change(self):
|
||||
"""Test for firing on no change."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -145,7 +147,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'hello')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -153,7 +155,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_two_change(self):
|
||||
"""Test for firing on two changes."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -163,7 +165,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
# Trigger once
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
@ -177,7 +179,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_with_template(self):
|
||||
"""Test for firing on change with template."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -187,7 +189,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -195,7 +197,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_change_with_template(self):
|
||||
"""Test for not firing on change with template."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -205,7 +207,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -213,7 +215,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_with_template_advanced(self):
|
||||
"""Test for firing on change with template advanced."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -227,7 +229,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -235,7 +237,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_no_change_with_template_advanced(self):
|
||||
"""Test for firing on no change with template advanced."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -249,7 +251,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
# Different state
|
||||
self.hass.states.set('test.entity', 'worldz')
|
||||
@ -263,7 +265,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_with_template_2(self):
|
||||
"""Test for firing on change with template."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -274,7 +276,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
@ -302,7 +304,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_action(self):
|
||||
"""Test for firing if action."""
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -335,7 +337,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_with_bad_template(self):
|
||||
"""Test for firing on change with bad template."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -345,15 +347,11 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(0, len(self.calls))
|
||||
})
|
||||
|
||||
def test_if_fires_on_change_with_bad_template_2(self):
|
||||
"""Test for firing on change with bad template."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -363,7 +361,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
|
@ -3,6 +3,7 @@ from datetime import timedelta
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
import homeassistant.util.dt as dt_util
|
||||
import homeassistant.components.automation as automation
|
||||
|
||||
@ -15,6 +16,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.components.append('group')
|
||||
self.calls = []
|
||||
|
||||
def record_call(service):
|
||||
@ -28,7 +30,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_when_hour_matches(self):
|
||||
"""Test for firing if hour is matching."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -38,7 +40,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(hour=0))
|
||||
|
||||
@ -47,7 +49,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_when_minute_matches(self):
|
||||
"""Test for firing if minutes are matching."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -57,7 +59,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(minute=0))
|
||||
|
||||
@ -66,7 +68,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_when_second_matches(self):
|
||||
"""Test for firing if seconds are matching."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -76,7 +78,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(second=0))
|
||||
|
||||
@ -85,7 +87,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_when_all_matches(self):
|
||||
"""Test for firing if everything matches."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -97,7 +99,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(
|
||||
hour=1, minute=2, second=3))
|
||||
@ -107,7 +109,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_periodic_seconds(self):
|
||||
"""Test for firing periodically every second."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -117,7 +119,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(
|
||||
hour=0, minute=0, second=2))
|
||||
@ -127,7 +129,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_periodic_minutes(self):
|
||||
"""Test for firing periodically every minute."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -137,7 +139,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(
|
||||
hour=0, minute=2, second=0))
|
||||
@ -147,7 +149,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_periodic_hours(self):
|
||||
"""Test for firing periodically every hour."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -157,7 +159,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(
|
||||
hour=2, minute=0, second=0))
|
||||
@ -167,7 +169,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_using_after(self):
|
||||
"""Test for firing after."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -177,7 +179,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(
|
||||
hour=5, minute=0, second=0))
|
||||
@ -187,7 +189,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_not_working_if_no_values_in_conf_provided(self):
|
||||
"""Test for failure if no configuration."""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -196,7 +198,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(
|
||||
hour=5, minute=0, second=0))
|
||||
@ -210,7 +212,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
This should break the before rule.
|
||||
"""
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -221,7 +223,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(
|
||||
hour=1, minute=0, second=5))
|
||||
@ -232,7 +234,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_action_before(self):
|
||||
"""Test for if action before."""
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -267,7 +269,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_action_after(self):
|
||||
"""Test for if action after."""
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -302,7 +304,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_action_one_weekday(self):
|
||||
"""Test for if action with one weekday."""
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -338,7 +340,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_action_list_weekday(self):
|
||||
"""Test for action with a list of weekdays."""
|
||||
automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""The tests for the location automation."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.components import automation, zone
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
@ -12,6 +13,7 @@ class TestAutomationZone(unittest.TestCase):
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.components.append('group')
|
||||
zone.setup(self.hass, {
|
||||
'zone': {
|
||||
'name': 'test',
|
||||
@ -40,7 +42,7 @@ class TestAutomationZone(unittest.TestCase):
|
||||
})
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'zone',
|
||||
@ -52,7 +54,7 @@ class TestAutomationZone(unittest.TestCase):
|
||||
'service': 'test.automation',
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'hello', {
|
||||
'latitude': 32.880586,
|
||||
@ -70,7 +72,7 @@ class TestAutomationZone(unittest.TestCase):
|
||||
})
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'zone',
|
||||
@ -82,7 +84,7 @@ class TestAutomationZone(unittest.TestCase):
|
||||
'service': 'test.automation',
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'hello', {
|
||||
'latitude': 32.881011,
|
||||
@ -100,7 +102,7 @@ class TestAutomationZone(unittest.TestCase):
|
||||
})
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'zone',
|
||||
@ -112,7 +114,7 @@ class TestAutomationZone(unittest.TestCase):
|
||||
'service': 'test.automation',
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'hello', {
|
||||
'latitude': 32.881011,
|
||||
@ -130,7 +132,7 @@ class TestAutomationZone(unittest.TestCase):
|
||||
})
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'zone',
|
||||
@ -142,7 +144,7 @@ class TestAutomationZone(unittest.TestCase):
|
||||
'service': 'test.automation',
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.states.set('test.entity', 'hello', {
|
||||
'latitude': 32.880586,
|
||||
@ -160,7 +162,7 @@ class TestAutomationZone(unittest.TestCase):
|
||||
})
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(automation.setup(self.hass, {
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -175,7 +177,7 @@ class TestAutomationZone(unittest.TestCase):
|
||||
'service': 'test.automation',
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
self.hass.bus.fire('test_event')
|
||||
self.hass.pool.block_till_done()
|
||||
|
@ -31,7 +31,7 @@ class TestScript(unittest.TestCase):
|
||||
{'test': {}},
|
||||
{
|
||||
'test hello world': {
|
||||
'sequence': []
|
||||
'sequence': [{'event': 'bla'}]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1,8 +1,12 @@
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
|
||||
def test_boolean():
|
||||
"""Test boolean validation."""
|
||||
@ -117,6 +121,19 @@ def test_event_schema():
|
||||
cv.EVENT_SCHEMA(value)
|
||||
|
||||
|
||||
def test_platform_validator():
|
||||
"""Test platform validation."""
|
||||
# Prepares loading
|
||||
get_test_home_assistant()
|
||||
|
||||
schema = vol.Schema(cv.platform_validator('light'))
|
||||
|
||||
with pytest.raises(vol.MultipleInvalid):
|
||||
schema('platform_that_does_not_exist')
|
||||
|
||||
schema('hue')
|
||||
|
||||
|
||||
def test_icon():
|
||||
"""Test icon validation."""
|
||||
schema = vol.Schema(cv.icon)
|
||||
@ -128,6 +145,25 @@ def test_icon():
|
||||
schema('mdi:work')
|
||||
|
||||
|
||||
def test_time_offset():
|
||||
"""Test time_offset validation."""
|
||||
schema = vol.Schema(cv.time_offset)
|
||||
|
||||
for value in (
|
||||
None, '', 1234, 'hello:world', '12:', '12:34:56:78'
|
||||
):
|
||||
with pytest.raises(vol.MultipleInvalid):
|
||||
schema(value)
|
||||
|
||||
for value in (
|
||||
'8:20', '23:59', '-8:20', '-23:59:59', '-48:00'
|
||||
):
|
||||
schema(value)
|
||||
|
||||
assert timedelta(hours=23, minutes=59) == schema('23:59')
|
||||
assert -1 * timedelta(hours=1, minutes=15) == schema('-1:15')
|
||||
|
||||
|
||||
def test_service():
|
||||
"""Test service validation."""
|
||||
schema = vol.Schema(cv.service)
|
||||
@ -165,6 +201,14 @@ def test_service_schema():
|
||||
|
||||
for value in (
|
||||
{'service': 'homeassistant.turn_on'},
|
||||
{
|
||||
'service': 'homeassistant.turn_on',
|
||||
'entity_id': 'light.kitchen',
|
||||
},
|
||||
{
|
||||
'service': 'homeassistant.turn_on',
|
||||
'entity_id': ['light.kitchen', 'light.ceiling'],
|
||||
},
|
||||
):
|
||||
cv.SERVICE_SCHEMA(value)
|
||||
|
||||
@ -232,31 +276,26 @@ def test_time_zone():
|
||||
schema('UTC')
|
||||
|
||||
|
||||
def test_dict_validator():
|
||||
"""Test DictValidator."""
|
||||
schema = vol.Schema(cv.DictValidator(cv.entity_ids, cv.slug))
|
||||
def test_key_dependency():
|
||||
"""Test key_dependency validator."""
|
||||
schema = vol.Schema(cv.key_dependency('beer', 'soda'))
|
||||
|
||||
for value in (
|
||||
None,
|
||||
{'invalid slug': 'sensor.temp'},
|
||||
{'hello world': 'invalid_entity'}
|
||||
{'beer': None}
|
||||
):
|
||||
with pytest.raises(vol.MultipleInvalid):
|
||||
schema(value)
|
||||
|
||||
for value in (
|
||||
{},
|
||||
{'hello_world': 'sensor.temp'},
|
||||
{'beer': None, 'soda': None},
|
||||
{'soda': None}, {}
|
||||
):
|
||||
schema(value)
|
||||
|
||||
assert schema({'hello_world': 'sensor.temp'}) == \
|
||||
{'hello_world': ['sensor.temp']}
|
||||
|
||||
|
||||
def test_has_at_least_one_key():
|
||||
"""Test has_at_least_one_key validator."""
|
||||
schema = vol.Schema(cv.has_at_least_one_key(['beer', 'soda']))
|
||||
schema = vol.Schema(cv.has_at_least_one_key('beer', 'soda'))
|
||||
|
||||
for value in (None, [], {}, {'wine': None}):
|
||||
with pytest.raises(vol.MultipleInvalid):
|
||||
|
Loading…
x
Reference in New Issue
Block a user