mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Convert automation to entities with services
This commit is contained in:
parent
d9ecc4af64
commit
3fa1963345
@ -4,19 +4,26 @@ Allow to setup simple automation rules via the config file.
|
||||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/automation/
|
||||
"""
|
||||
from functools import partial
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.bootstrap import prepare_setup_platform
|
||||
from homeassistant.const import ATTR_ENTITY_ID, CONF_PLATFORM
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID, CONF_PLATFORM, STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF,
|
||||
SERVICE_TOGGLE)
|
||||
from homeassistant.components import logbook
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import extract_domain_configs, script, condition
|
||||
from homeassistant.helpers.entity import ToggleEntity
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.loader import get_platform
|
||||
from homeassistant.util.dt import utcnow
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
DOMAIN = 'automation'
|
||||
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
||||
|
||||
DEPENDENCIES = ['group']
|
||||
|
||||
@ -36,6 +43,10 @@ DEFAULT_CONDITION_TYPE = CONDITION_TYPE_AND
|
||||
METHOD_TRIGGER = 'trigger'
|
||||
METHOD_IF_ACTION = 'if_action'
|
||||
|
||||
ATTR_LAST_TRIGGERED = 'last_triggered'
|
||||
ATTR_VARIABLES = 'variables'
|
||||
SERVICE_TRIGGER = 'trigger'
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -88,41 +99,170 @@ PLATFORM_SCHEMA = vol.Schema({
|
||||
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.Optional(CONF_CONDITION): _CONDITION_SCHEMA,
|
||||
vol.Required(CONF_ACTION): cv.SCRIPT_SCHEMA,
|
||||
})
|
||||
|
||||
SERVICE_SCHEMA = vol.Schema({
|
||||
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
|
||||
})
|
||||
|
||||
TRIGGER_SERVICE_SCHEMA = vol.Schema({
|
||||
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
|
||||
vol.Optional(ATTR_VARIABLES, default={}): dict,
|
||||
})
|
||||
|
||||
|
||||
def is_on(hass, entity_id=None):
|
||||
"""
|
||||
Return true if specified automation entity_id is on.
|
||||
|
||||
Check all automation if no entity_id specified.
|
||||
"""
|
||||
entity_ids = [entity_id] if entity_id else hass.states.entity_ids(DOMAIN)
|
||||
return any(hass.states.is_state(entity_id, STATE_ON)
|
||||
for entity_id in entity_ids)
|
||||
|
||||
|
||||
def turn_on(hass, entity_id=None):
|
||||
"""Turn on specified automation or all."""
|
||||
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
|
||||
hass.services.call(DOMAIN, SERVICE_TURN_ON, data)
|
||||
|
||||
|
||||
def turn_off(hass, entity_id=None):
|
||||
"""Turn off specified automation or all."""
|
||||
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
|
||||
hass.services.call(DOMAIN, SERVICE_TURN_OFF, data)
|
||||
|
||||
|
||||
def toggle(hass, entity_id=None):
|
||||
"""Toggle specified automation or all."""
|
||||
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
|
||||
hass.services.call(DOMAIN, SERVICE_TOGGLE, data)
|
||||
|
||||
|
||||
def trigger(hass, entity_id=None):
|
||||
"""Trigger specified automation or all."""
|
||||
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
|
||||
hass.services.call(DOMAIN, SERVICE_TRIGGER, data)
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
"""Setup the automation."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
success = False
|
||||
for config_key in extract_domain_configs(config, DOMAIN):
|
||||
conf = config[config_key]
|
||||
|
||||
for list_no, config_block in enumerate(conf):
|
||||
name = config_block.get(CONF_ALIAS, "{}, {}".format(config_key,
|
||||
list_no))
|
||||
success = (_setup_automation(hass, config_block, name, config) or
|
||||
success)
|
||||
name = config_block.get(CONF_ALIAS) or "{} {}".format(config_key,
|
||||
list_no)
|
||||
|
||||
return success
|
||||
action = _get_action(hass, config_block.get(CONF_ACTION, {}), name)
|
||||
|
||||
if CONF_CONDITION in config_block:
|
||||
cond_func = _process_if(hass, config, config_block)
|
||||
|
||||
def _setup_automation(hass, config_block, name, config):
|
||||
"""Setup one instance of automation."""
|
||||
action = _get_action(hass, config_block.get(CONF_ACTION, {}), name)
|
||||
if cond_func is None:
|
||||
continue
|
||||
else:
|
||||
def cond_func(variables):
|
||||
"""Condition will always pass."""
|
||||
return True
|
||||
|
||||
if CONF_CONDITION in config_block:
|
||||
action = _process_if(hass, config, config_block, action)
|
||||
attach_triggers = partial(_process_trigger, hass, config,
|
||||
config_block.get(CONF_TRIGGER, []), name)
|
||||
entity = AutomationEntity(name, attach_triggers, cond_func, action)
|
||||
component.add_entities((entity,))
|
||||
success = True
|
||||
|
||||
if action is None:
|
||||
return False
|
||||
if not success:
|
||||
return False
|
||||
|
||||
def trigger_service_handler(service_call):
|
||||
"""Handle automation triggers."""
|
||||
for entity in component.extract_from_service(service_call):
|
||||
entity.trigger(service_call.data.get(ATTR_VARIABLES))
|
||||
|
||||
def service_handler(service_call):
|
||||
"""Handle automation service calls."""
|
||||
for entity in component.extract_from_service(service_call):
|
||||
getattr(entity, service_call.service)()
|
||||
|
||||
hass.services.register(DOMAIN, SERVICE_TRIGGER, trigger_service_handler,
|
||||
schema=TRIGGER_SERVICE_SCHEMA)
|
||||
|
||||
for service in (SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE):
|
||||
hass.services.register(DOMAIN, service, service_handler,
|
||||
schema=SERVICE_SCHEMA)
|
||||
|
||||
_process_trigger(hass, config, config_block.get(CONF_TRIGGER, []), name,
|
||||
action)
|
||||
return True
|
||||
|
||||
|
||||
class AutomationEntity(ToggleEntity):
|
||||
"""Entity to show status of entity."""
|
||||
|
||||
def __init__(self, name, attach_triggers, cond_func, action):
|
||||
"""Initialize an automation entity."""
|
||||
self._name = name
|
||||
self._attach_triggers = attach_triggers
|
||||
self._detach_triggers = attach_triggers(self.trigger)
|
||||
self._cond_func = cond_func
|
||||
self._action = action
|
||||
self._enabled = True
|
||||
self._last_triggered = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Name of the automation."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""No polling needed for automation entities."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def state_attributes(self):
|
||||
"""Return the entity state attributes."""
|
||||
return {
|
||||
ATTR_LAST_TRIGGERED: self._last_triggered
|
||||
}
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return True if entity is on."""
|
||||
return self._enabled
|
||||
|
||||
def turn_on(self, **kwargs) -> None:
|
||||
"""Turn the entity on."""
|
||||
if self._enabled:
|
||||
return
|
||||
|
||||
self._detach_triggers = self._attach_triggers(self.trigger)
|
||||
self._enabled = True
|
||||
self.update_ha_state()
|
||||
|
||||
def turn_off(self, **kwargs) -> None:
|
||||
"""Turn the entity off."""
|
||||
if not self._enabled:
|
||||
return
|
||||
|
||||
self._detach_triggers()
|
||||
self._detach_triggers = None
|
||||
self._enabled = False
|
||||
self.update_ha_state()
|
||||
|
||||
def trigger(self, variables):
|
||||
"""Trigger automation."""
|
||||
if self._cond_func(variables):
|
||||
self._action(variables)
|
||||
self._last_triggered = utcnow()
|
||||
self.update_ha_state()
|
||||
|
||||
|
||||
def _get_action(hass, config, name):
|
||||
"""Return an action based on a configuration."""
|
||||
script_obj = script.Script(hass, config, name)
|
||||
@ -136,7 +276,7 @@ def _get_action(hass, config, name):
|
||||
return action
|
||||
|
||||
|
||||
def _process_if(hass, config, p_config, action):
|
||||
def _process_if(hass, config, p_config):
|
||||
"""Process if checks."""
|
||||
cond_type = p_config.get(CONF_CONDITION_TYPE,
|
||||
DEFAULT_CONDITION_TYPE).lower()
|
||||
@ -182,29 +322,43 @@ def _process_if(hass, config, p_config, action):
|
||||
if cond_type == CONDITION_TYPE_AND:
|
||||
def if_action(variables=None):
|
||||
"""AND all conditions."""
|
||||
if all(check(hass, variables) for check in checks):
|
||||
action(variables)
|
||||
return all(check(hass, variables) for check in checks)
|
||||
else:
|
||||
def if_action(variables=None):
|
||||
"""OR all conditions."""
|
||||
if any(check(hass, variables) for check in checks):
|
||||
action(variables)
|
||||
return any(check(hass, variables) for check in checks)
|
||||
|
||||
return if_action
|
||||
|
||||
|
||||
def _process_trigger(hass, config, trigger_configs, name, action):
|
||||
"""Setup the triggers."""
|
||||
removes = []
|
||||
|
||||
for conf in trigger_configs:
|
||||
platform = _resolve_platform(METHOD_TRIGGER, hass, config,
|
||||
conf.get(CONF_PLATFORM))
|
||||
if platform is None:
|
||||
continue
|
||||
|
||||
if platform.trigger(hass, conf, action):
|
||||
_LOGGER.info("Initialized rule %s", name)
|
||||
else:
|
||||
remove = platform.trigger(hass, conf, action)
|
||||
|
||||
if not remove:
|
||||
_LOGGER.error("Error setting up rule %s", name)
|
||||
continue
|
||||
|
||||
_LOGGER.info("Initialized rule %s", name)
|
||||
removes.append(remove)
|
||||
|
||||
if not removes:
|
||||
return None
|
||||
|
||||
def remove_triggers():
|
||||
"""Remove attached triggers."""
|
||||
for remove in removes:
|
||||
remove()
|
||||
|
||||
return remove_triggers
|
||||
|
||||
|
||||
def _resolve_platform(method, hass, config, platform):
|
||||
|
@ -39,5 +39,4 @@ def trigger(hass, config, action):
|
||||
},
|
||||
})
|
||||
|
||||
hass.bus.listen(event_type, handle_event)
|
||||
return True
|
||||
return hass.bus.listen(event_type, handle_event)
|
||||
|
@ -39,6 +39,4 @@ def trigger(hass, config, action):
|
||||
}
|
||||
})
|
||||
|
||||
mqtt.subscribe(hass, topic, mqtt_automation_listener)
|
||||
|
||||
return True
|
||||
return mqtt.subscribe(hass, topic, mqtt_automation_listener)
|
||||
|
@ -63,7 +63,4 @@ def trigger(hass, config, action):
|
||||
|
||||
action(variables)
|
||||
|
||||
track_state_change(
|
||||
hass, entity_id, state_automation_listener)
|
||||
|
||||
return True
|
||||
return track_state_change(hass, entity_id, state_automation_listener)
|
||||
|
@ -38,9 +38,13 @@ def trigger(hass, config, action):
|
||||
from_state = config.get(CONF_FROM, MATCH_ALL)
|
||||
to_state = config.get(CONF_TO) or config.get(CONF_STATE) or MATCH_ALL
|
||||
time_delta = config.get(CONF_FOR)
|
||||
remove_state_for_cancel = None
|
||||
remove_state_for_listener = None
|
||||
|
||||
def state_automation_listener(entity, from_s, to_s):
|
||||
"""Listen for state changes and calls action."""
|
||||
nonlocal remove_state_for_cancel, remove_state_for_listener
|
||||
|
||||
def call_action():
|
||||
"""Call action with right context."""
|
||||
action({
|
||||
@ -75,7 +79,17 @@ def trigger(hass, config, action):
|
||||
remove_state_for_cancel = track_state_change(
|
||||
hass, entity, state_for_cancel_listener)
|
||||
|
||||
track_state_change(
|
||||
hass, entity_id, state_automation_listener, from_state, to_state)
|
||||
unsub = track_state_change(hass, entity_id, state_automation_listener,
|
||||
from_state, to_state)
|
||||
|
||||
return True
|
||||
def remove():
|
||||
"""Remove state listeners."""
|
||||
unsub()
|
||||
|
||||
if remove_state_for_cancel is not None:
|
||||
remove_state_for_cancel()
|
||||
|
||||
if remove_state_for_listener is not None:
|
||||
remove_state_for_listener()
|
||||
|
||||
return remove
|
||||
|
@ -42,8 +42,6 @@ def trigger(hass, config, action):
|
||||
|
||||
# Do something to call action
|
||||
if event == SUN_EVENT_SUNRISE:
|
||||
track_sunrise(hass, call_action, offset)
|
||||
return track_sunrise(hass, call_action, offset)
|
||||
else:
|
||||
track_sunset(hass, call_action, offset)
|
||||
|
||||
return True
|
||||
return track_sunset(hass, call_action, offset)
|
||||
|
@ -49,5 +49,4 @@ def trigger(hass, config, action):
|
||||
elif not template_result:
|
||||
already_triggered = False
|
||||
|
||||
track_state_change(hass, MATCH_ALL, state_changed_listener)
|
||||
return True
|
||||
return track_state_change(hass, MATCH_ALL, state_changed_listener)
|
||||
|
@ -47,7 +47,5 @@ def trigger(hass, config, action):
|
||||
},
|
||||
})
|
||||
|
||||
track_time_change(hass, time_automation_listener,
|
||||
hour=hours, minute=minutes, second=seconds)
|
||||
|
||||
return True
|
||||
return track_time_change(hass, time_automation_listener,
|
||||
hour=hours, minute=minutes, second=seconds)
|
||||
|
@ -58,7 +58,5 @@ def trigger(hass, config, action):
|
||||
},
|
||||
})
|
||||
|
||||
track_state_change(
|
||||
hass, entity_id, zone_automation_listener, MATCH_ALL, MATCH_ALL)
|
||||
|
||||
return True
|
||||
return track_state_change(hass, entity_id, zone_automation_listener,
|
||||
MATCH_ALL, MATCH_ALL)
|
||||
|
@ -44,6 +44,13 @@ class TestAutomationEvent(unittest.TestCase):
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
|
||||
automation.turn_off(self.hass)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.hass.bus.fire('test_event')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
|
||||
def test_if_fires_on_event_with_data(self):
|
||||
"""Test the firing of events with data."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
|
@ -1,9 +1,11 @@
|
||||
"""The tests for the automation component."""
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
import homeassistant.components.automation as automation
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
@ -45,6 +47,7 @@ class TestAutomation(unittest.TestCase):
|
||||
"""Test service data."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'alias': 'hello',
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
'event_type': 'test_event',
|
||||
@ -59,10 +62,17 @@ class TestAutomation(unittest.TestCase):
|
||||
}
|
||||
})
|
||||
|
||||
self.hass.bus.fire('test_event')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
self.assertEqual('event - test_event', self.calls[0].data['some'])
|
||||
time = dt_util.utcnow()
|
||||
|
||||
with patch('homeassistant.components.automation.utcnow',
|
||||
return_value=time):
|
||||
self.hass.bus.fire('test_event')
|
||||
self.hass.pool.block_till_done()
|
||||
assert len(self.calls) == 1
|
||||
assert 'event - test_event' == self.calls[0].data['some']
|
||||
state = self.hass.states.get('automation.hello')
|
||||
assert state is not None
|
||||
assert state.attributes.get('last_triggered') == time
|
||||
|
||||
def test_service_specify_entity_id(self):
|
||||
"""Test service data."""
|
||||
@ -347,3 +357,60 @@ class TestAutomation(unittest.TestCase):
|
||||
assert len(self.calls) == 2
|
||||
assert self.calls[0].data['position'] == 0
|
||||
assert self.calls[1].data['position'] == 1
|
||||
|
||||
def test_services(self):
|
||||
""" """
|
||||
entity_id = 'automation.hello'
|
||||
|
||||
assert self.hass.states.get(entity_id) is None
|
||||
assert not automation.is_on(self.hass, entity_id)
|
||||
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'alias': 'hello',
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
'event_type': 'test_event',
|
||||
},
|
||||
'action': {
|
||||
'service': 'test.automation',
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
assert self.hass.states.get(entity_id) is not None
|
||||
assert automation.is_on(self.hass, entity_id)
|
||||
|
||||
self.hass.bus.fire('test_event')
|
||||
self.hass.pool.block_till_done()
|
||||
assert len(self.calls) == 1
|
||||
|
||||
automation.turn_off(self.hass, entity_id)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
assert not automation.is_on(self.hass, entity_id)
|
||||
self.hass.bus.fire('test_event')
|
||||
self.hass.pool.block_till_done()
|
||||
assert len(self.calls) == 1
|
||||
|
||||
automation.toggle(self.hass, entity_id)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
assert automation.is_on(self.hass, entity_id)
|
||||
self.hass.bus.fire('test_event')
|
||||
self.hass.pool.block_till_done()
|
||||
assert len(self.calls) == 2
|
||||
|
||||
automation.trigger(self.hass, entity_id)
|
||||
self.hass.pool.block_till_done()
|
||||
assert len(self.calls) == 3
|
||||
|
||||
automation.turn_off(self.hass, entity_id)
|
||||
self.hass.pool.block_till_done()
|
||||
automation.trigger(self.hass, entity_id)
|
||||
self.hass.pool.block_till_done()
|
||||
assert len(self.calls) == 4
|
||||
|
||||
automation.turn_on(self.hass, entity_id)
|
||||
self.hass.pool.block_till_done()
|
||||
assert automation.is_on(self.hass, entity_id)
|
||||
|
@ -50,6 +50,12 @@ class TestAutomationMQTT(unittest.TestCase):
|
||||
self.assertEqual('mqtt - test-topic - test_payload',
|
||||
self.calls[0].data['some'])
|
||||
|
||||
automation.turn_off(self.hass)
|
||||
self.hass.pool.block_till_done()
|
||||
fire_mqtt_message(self.hass, 'test-topic', 'test_payload')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
|
||||
def test_if_fires_on_topic_and_payload_match(self):
|
||||
"""Test if message is fired on topic and payload match."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
|
@ -45,6 +45,14 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
|
||||
# Set above 12 so the automation will fire again
|
||||
self.hass.states.set('test.entity', 12)
|
||||
automation.turn_off(self.hass)
|
||||
self.hass.pool.block_till_done()
|
||||
self.hass.states.set('test.entity', 9)
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
|
||||
def test_if_fires_on_entity_change_over_to_below(self):
|
||||
""""Test the firing with changed entity."""
|
||||
self.hass.states.set('test.entity', 11)
|
||||
|
@ -59,6 +59,12 @@ class TestAutomationState(unittest.TestCase):
|
||||
'state - test.entity - hello - world - None',
|
||||
self.calls[0].data['some'])
|
||||
|
||||
automation.turn_off(self.hass)
|
||||
self.hass.pool.block_till_done()
|
||||
self.hass.states.set('test.entity', 'planet')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
|
||||
def test_if_fires_on_entity_change_with_from_filter(self):
|
||||
"""Test for firing on entity change with filter."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
|
@ -54,6 +54,18 @@ class TestAutomationSun(unittest.TestCase):
|
||||
}
|
||||
})
|
||||
|
||||
automation.turn_off(self.hass)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
fire_time_changed(self.hass, trigger_time)
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(0, len(self.calls))
|
||||
|
||||
with patch('homeassistant.util.dt.utcnow',
|
||||
return_value=now):
|
||||
automation.turn_on(self.hass)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
fire_time_changed(self.hass, trigger_time)
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
|
@ -45,6 +45,13 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
|
||||
automation.turn_off(self.hass)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.hass.states.set('test.entity', 'planet')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
|
||||
def test_if_fires_on_change_str(self):
|
||||
"""Test for firing on change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
@ -149,6 +156,9 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
}
|
||||
})
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
self.calls = []
|
||||
|
||||
self.hass.states.set('test.entity', 'hello')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(0, len(self.calls))
|
||||
@ -209,9 +219,12 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
}
|
||||
})
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
self.calls = []
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(0, len(self.calls))
|
||||
assert len(self.calls) == 0
|
||||
|
||||
def test_if_fires_on_change_with_template_advanced(self):
|
||||
"""Test for firing on change with template advanced."""
|
||||
@ -237,6 +250,9 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
}
|
||||
})
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
self.calls = []
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
@ -287,29 +303,32 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
}
|
||||
})
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
self.calls = []
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(0, len(self.calls))
|
||||
assert len(self.calls) == 0
|
||||
|
||||
self.hass.states.set('test.entity', 'home')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
assert len(self.calls) == 1
|
||||
|
||||
self.hass.states.set('test.entity', 'work')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
assert len(self.calls) == 1
|
||||
|
||||
self.hass.states.set('test.entity', 'not_home')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
assert len(self.calls) == 1
|
||||
|
||||
self.hass.states.set('test.entity', 'world')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
assert len(self.calls) == 1
|
||||
|
||||
self.hass.states.set('test.entity', 'home')
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(2, len(self.calls))
|
||||
assert len(self.calls) == 2
|
||||
|
||||
def test_if_action(self):
|
||||
"""Test for firing if action."""
|
||||
|
@ -43,7 +43,13 @@ class TestAutomationTime(unittest.TestCase):
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(hour=0))
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
|
||||
automation.turn_off(self.hass)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(hour=0))
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(1, len(self.calls))
|
||||
|
||||
|
@ -74,6 +74,24 @@ class TestAutomationZone(unittest.TestCase):
|
||||
'zone - test.entity - hello - hello - test',
|
||||
self.calls[0].data['some'])
|
||||
|
||||
# Set out of zone again so we can trigger call
|
||||
self.hass.states.set('test.entity', 'hello', {
|
||||
'latitude': 32.881011,
|
||||
'longitude': -117.234758
|
||||
})
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
automation.turn_off(self.hass)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.hass.states.set('test.entity', 'hello', {
|
||||
'latitude': 32.880586,
|
||||
'longitude': -117.237564
|
||||
})
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertEqual(1, len(self.calls))
|
||||
|
||||
def test_if_not_fires_for_enter_on_zone_leave(self):
|
||||
"""Test for not firing on zone leave."""
|
||||
self.hass.states.set('test.entity', 'hello', {
|
||||
|
Loading…
x
Reference in New Issue
Block a user