Refactor automation configuration

This commit is contained in:
Paulus Schoutsen 2015-09-14 22:05:40 -07:00
parent fe2a9bb83e
commit 68c1dd7cd4
11 changed files with 836 additions and 223 deletions

View file

@ -7,7 +7,6 @@ Allows to setup simple automation rules via the config file.
import logging
from homeassistant.bootstrap import prepare_setup_platform
from homeassistant.helpers import config_per_platform
from homeassistant.util import split_entity_id
from homeassistant.const import ATTR_ENTITY_ID, CONF_PLATFORM
from homeassistant.components import logbook
@ -20,50 +19,45 @@ CONF_ALIAS = "alias"
CONF_SERVICE = "execute_service"
CONF_SERVICE_ENTITY_ID = "service_entity_id"
CONF_SERVICE_DATA = "service_data"
CONF_IF = "if"
CONF_CONDITION = "condition"
CONF_ACTION = 'action'
CONF_TRIGGER = "trigger"
_LOGGER = logging.getLogger(__name__)
def setup(hass, config):
""" Sets up automation. """
success = False
config_key = DOMAIN
found = 1
for p_type, p_config in config_per_platform(config, DOMAIN, _LOGGER):
platform = prepare_setup_platform(hass, config, DOMAIN, p_type)
while config_key in config:
p_config = _migrate_old_config(config[config_key])
found += 1
config_key = "{} {}".format(DOMAIN, found)
if platform is None:
_LOGGER.error("Unknown automation platform specified: %s", p_type)
continue
action = _get_action(hass, p_config)
name = p_config.get(CONF_ALIAS, config_key)
action = _get_action(hass, p_config.get(CONF_ACTION, {}), name)
if action is None:
return
continue
if CONF_IF in p_config:
action = _process_if(hass, config, p_config[CONF_IF], action)
if CONF_CONDITION in p_config:
action = _process_if(hass, config, p_config[CONF_CONDITION], action)
if platform.trigger(hass, p_config, action):
_LOGGER.info(
"Initialized %s rule %s", p_type, p_config.get(CONF_ALIAS, ""))
success = True
else:
_LOGGER.error(
"Error setting up rule %s", p_config.get(CONF_ALIAS, ""))
_process_trigger(hass, config, p_config.get(CONF_TRIGGER, []), name,
action)
return success
return True
def _get_action(hass, config):
def _get_action(hass, config, name):
""" Return an action based on a config. """
name = config.get(CONF_ALIAS, 'Unnamed automation')
if CONF_SERVICE not in config:
_LOGGER.error('Error setting up %s, no action specified.',
name)
return
_LOGGER.error('Error setting up %s, no action specified.', name)
return None
def action():
""" Action to be executed. """
@ -71,7 +65,6 @@ def _get_action(hass, config):
logbook.log_entry(hass, name, 'has been triggered', DOMAIN)
domain, service = split_entity_id(config[CONF_SERVICE])
service_data = config.get(CONF_SERVICE_DATA, {})
if not isinstance(service_data, dict):
@ -91,6 +84,37 @@ def _get_action(hass, config):
return action
def _migrate_old_config(config):
""" Migrate old config to new. """
if CONF_PLATFORM not in config:
return config
_LOGGER.warning(
'You are using an old configuration format. Please upgrade: '
'https://home-assistant.io/components/automation.html')
new_conf = {
CONF_TRIGGER: dict(config),
CONF_CONDITION: config.get('if', []),
CONF_ACTION: dict(config),
}
for cat, key, new_key in (('trigger', 'mqtt_topic', 'topic'),
('trigger', 'mqtt_payload', 'payload'),
('trigger', 'state_entity_id', 'entity_id'),
('trigger', 'state_before', 'before'),
('trigger', 'state_after', 'after'),
('trigger', 'state_to', 'to'),
('trigger', 'state_from', 'from'),
('trigger', 'state_hours', 'hours'),
('trigger', 'state_minutes', 'minutes'),
('trigger', 'state_seconds', 'seconds')):
if key in new_conf[cat]:
new_conf[cat][new_key] = new_conf[cat].pop(key)
return new_conf
def _process_if(hass, config, if_configs, action):
""" Processes if checks. """
@ -98,19 +122,42 @@ def _process_if(hass, config, if_configs, action):
if_configs = [if_configs]
for if_config in if_configs:
p_type = if_config.get(CONF_PLATFORM)
if p_type is None:
_LOGGER.error("No platform defined found for if-statement %s",
if_config)
continue
platform = prepare_setup_platform(hass, config, DOMAIN, p_type)
if platform is None or not hasattr(platform, 'if_action'):
_LOGGER.error("Unsupported if-statement platform specified: %s",
p_type)
platform = _resolve_platform('condition', hass, config,
if_config.get(CONF_PLATFORM))
if platform is None:
continue
action = platform.if_action(hass, if_config, action)
return action
def _process_trigger(hass, config, trigger_configs, name, action):
""" Setup triggers. """
if isinstance(trigger_configs, dict):
trigger_configs = [trigger_configs]
for conf in trigger_configs:
platform = _resolve_platform('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:
_LOGGER.error("Error setting up rule %s", name)
def _resolve_platform(requester, hass, config, platform):
""" Find automation platform. """
if platform is None:
return None
platform = prepare_setup_platform(hass, config, DOMAIN, platform)
if platform is None:
_LOGGER.error("Unknown automation platform specified for %s: %s",
requester, platform)
return None
return platform

View file

@ -10,8 +10,8 @@ import homeassistant.components.mqtt as mqtt
DEPENDENCIES = ['mqtt']
CONF_TOPIC = 'mqtt_topic'
CONF_PAYLOAD = 'mqtt_payload'
CONF_TOPIC = 'topic'
CONF_PAYLOAD = 'payload'
def trigger(hass, config, action):

View file

@ -9,9 +9,9 @@ import logging
from homeassistant.helpers.event import track_state_change
CONF_ENTITY_ID = "state_entity_id"
CONF_BELOW = "state_below"
CONF_ABOVE = "state_above"
CONF_ENTITY_ID = "entity_id"
CONF_BELOW = "below"
CONF_ABOVE = "above"
_LOGGER = logging.getLogger(__name__)

View file

@ -10,11 +10,10 @@ from homeassistant.helpers.event import track_state_change
from homeassistant.const import MATCH_ALL
CONF_ENTITY_ID = "state_entity_id"
CONF_FROM = "state_from"
CONF_TO = "state_to"
CONF_ENTITY_ID = "entity_id"
CONF_FROM = "from"
CONF_TO = "to"
CONF_STATE = "state"
CONF_IF_ENTITY_ID = "entity_id"
def trigger(hass, config, action):
@ -41,7 +40,7 @@ def trigger(hass, config, action):
def if_action(hass, config, action):
""" Wraps action method with state based condition. """
entity_id = config.get(CONF_IF_ENTITY_ID)
entity_id = config.get(CONF_ENTITY_ID)
state = config.get(CONF_STATE)
if entity_id is None or state is None:

View file

@ -10,9 +10,9 @@ from homeassistant.util import convert
import homeassistant.util.dt as dt_util
from homeassistant.helpers.event import track_time_change
CONF_HOURS = "time_hours"
CONF_MINUTES = "time_minutes"
CONF_SECONDS = "time_seconds"
CONF_HOURS = "hours"
CONF_MINUTES = "minutes"
CONF_SECONDS = "seconds"
CONF_BEFORE = "before"
CONF_AFTER = "after"
CONF_WEEKDAY = "weekday"

View file

@ -8,8 +8,6 @@ import unittest
import homeassistant.core as ha
import homeassistant.components.automation as automation
import homeassistant.components.automation.event as event
from homeassistant.const import CONF_PLATFORM
class TestAutomationEvent(unittest.TestCase):
@ -28,20 +26,57 @@ class TestAutomationEvent(unittest.TestCase):
""" Stop down stuff we started. """
self.hass.stop()
def test_fails_setup_if_no_event_type(self):
self.assertFalse(automation.setup(self.hass, {
def test_old_config_if_fires_on_event(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'event',
automation.CONF_SERVICE: 'test.automation'
'platform': 'event',
'event_type': 'test_event',
'execute_service': 'test.automation'
}
}))
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_old_config_if_fires_on_event_with_data(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'event',
'event_type': 'test_event',
'event_data': {'some_attr': 'some_value'},
'execute_service': 'test.automation'
}
}))
self.hass.bus.fire('test_event', {'some_attr': 'some_value'})
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_old_config_if_not_fires_if_event_data_not_matches(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'event',
'event_type': 'test_event',
'event_data': {'some_attr': 'some_value'},
'execute_service': 'test.automation'
}
}))
self.hass.bus.fire('test_event', {'some_attr': 'some_other_value'})
self.hass.pool.block_till_done()
self.assertEqual(0, len(self.calls))
def test_if_fires_on_event(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'event',
event.CONF_EVENT_TYPE: 'test_event',
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'event',
'event_type': 'test_event',
},
'action': {
'execute_service': 'test.automation',
}
}
}))
@ -52,10 +87,14 @@ class TestAutomationEvent(unittest.TestCase):
def test_if_fires_on_event_with_data(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'event',
event.CONF_EVENT_TYPE: 'test_event',
event.CONF_EVENT_DATA: {'some_attr': 'some_value'},
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'event',
'event_type': 'test_event',
'event_data': {'some_attr': 'some_value'}
},
'action': {
'execute_service': 'test.automation',
}
}
}))
@ -66,10 +105,14 @@ class TestAutomationEvent(unittest.TestCase):
def test_if_not_fires_if_event_data_not_matches(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'event',
event.CONF_EVENT_TYPE: 'test_event',
event.CONF_EVENT_DATA: {'some_attr': 'some_value'},
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'event',
'event_type': 'test_event',
'event_data': {'some_attr': 'some_value'}
},
'action': {
'execute_service': 'test.automation',
}
}
}))

View file

@ -8,8 +8,7 @@ import unittest
import homeassistant.core as ha
import homeassistant.components.automation as automation
import homeassistant.components.automation.event as event
from homeassistant.const import CONF_PLATFORM, ATTR_ENTITY_ID
from homeassistant.const import ATTR_ENTITY_ID
class TestAutomationEvent(unittest.TestCase):
@ -28,20 +27,13 @@ class TestAutomationEvent(unittest.TestCase):
""" Stop down stuff we started. """
self.hass.stop()
def test_setup_fails_if_unknown_platform(self):
self.assertFalse(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'i_do_not_exist'
}
}))
def test_service_data_not_a_dict(self):
automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'event',
event.CONF_EVENT_TYPE: 'test_event',
automation.CONF_SERVICE: 'test.automation',
automation.CONF_SERVICE_DATA: 100
'platform': 'event',
'event_type': 'test_event',
'execute_service': 'test.automation',
'service_data': 100
}
})
@ -49,13 +41,64 @@ class TestAutomationEvent(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_old_config_service_specify_data(self):
automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'event',
'event_type': 'test_event',
'execute_service': 'test.automation',
'service_data': {'some': 'data'}
}
})
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
self.assertEqual('data', self.calls[0].data['some'])
def test_old_config_service_specify_entity_id(self):
automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'event',
'event_type': 'test_event',
'execute_service': 'test.automation',
'service_entity_id': 'hello.world'
}
})
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
self.assertEqual(['hello.world'],
self.calls[0].data.get(ATTR_ENTITY_ID))
def test_old_config_service_specify_entity_id_list(self):
automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'event',
'event_type': 'test_event',
'execute_service': 'test.automation',
'service_entity_id': ['hello.world', 'hello.world2']
}
})
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
self.assertEqual(['hello.world', 'hello.world2'],
self.calls[0].data.get(ATTR_ENTITY_ID))
def test_service_specify_data(self):
automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'event',
event.CONF_EVENT_TYPE: 'test_event',
automation.CONF_SERVICE: 'test.automation',
automation.CONF_SERVICE_DATA: {'some': 'data'}
'trigger': {
'platform': 'event',
'event_type': 'test_event',
},
'action': {
'execute_service': 'test.automation',
'service_data': {'some': 'data'}
}
}
})
@ -67,29 +110,66 @@ class TestAutomationEvent(unittest.TestCase):
def test_service_specify_entity_id(self):
automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'event',
event.CONF_EVENT_TYPE: 'test_event',
automation.CONF_SERVICE: 'test.automation',
automation.CONF_SERVICE_ENTITY_ID: 'hello.world'
'trigger': {
'platform': 'event',
'event_type': 'test_event',
},
'action': {
'execute_service': 'test.automation',
'service_entity_id': 'hello.world'
}
}
})
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
self.assertEqual(['hello.world'], self.calls[0].data[ATTR_ENTITY_ID])
self.assertEqual(['hello.world'],
self.calls[0].data.get(ATTR_ENTITY_ID))
def test_service_specify_entity_id_list(self):
automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'event',
event.CONF_EVENT_TYPE: 'test_event',
automation.CONF_SERVICE: 'test.automation',
automation.CONF_SERVICE_ENTITY_ID: ['hello.world', 'hello.world2']
'trigger': {
'platform': 'event',
'event_type': 'test_event',
},
'action': {
'execute_service': 'test.automation',
'service_entity_id': ['hello.world', 'hello.world2']
}
}
})
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
self.assertEqual(['hello.world', 'hello.world2'], self.calls[0].data[ATTR_ENTITY_ID])
self.assertEqual(['hello.world', 'hello.world2'],
self.calls[0].data.get(ATTR_ENTITY_ID))
def test_two_triggers(self):
automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': [
{
'platform': 'event',
'event_type': 'test_event',
},
{
'platform': 'state',
'entity_id': 'test.entity',
}
],
'action': {
'execute_service': 'test.automation',
'service_entity_id': ['hello.world', 'hello.world2']
}
}
})
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
self.hass.states.set('test.entity', 'hello')
self.hass.pool.block_till_done()
self.assertEqual(2, len(self.calls))

View file

@ -8,9 +8,6 @@ import unittest
import homeassistant.core as ha
import homeassistant.components.automation as automation
import homeassistant.components.automation.mqtt as mqtt
from homeassistant.const import CONF_PLATFORM
from tests.common import mock_mqtt_component, fire_mqtt_message
@ -31,20 +28,57 @@ class TestAutomationState(unittest.TestCase):
""" Stop down stuff we started. """
self.hass.stop()
def test_setup_fails_if_no_topic(self):
self.assertFalse(automation.setup(self.hass, {
def test_old_config_if_fires_on_topic_match(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'mqtt',
automation.CONF_SERVICE: 'test.automation'
'platform': 'mqtt',
'mqtt_topic': 'test-topic',
'execute_service': 'test.automation'
}
}))
fire_mqtt_message(self.hass, 'test-topic', '')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_old_config_if_fires_on_topic_and_payload_match(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'mqtt',
'mqtt_topic': 'test-topic',
'mqtt_payload': 'hello',
'execute_service': 'test.automation'
}
}))
fire_mqtt_message(self.hass, 'test-topic', 'hello')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_old_config_if_not_fires_on_topic_but_no_payload_match(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'mqtt',
'mqtt_topic': 'test-topic',
'mqtt_payload': 'hello',
'execute_service': 'test.automation'
}
}))
fire_mqtt_message(self.hass, 'test-topic', 'no-hello')
self.hass.pool.block_till_done()
self.assertEqual(0, len(self.calls))
def test_if_fires_on_topic_match(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'mqtt',
mqtt.CONF_TOPIC: 'test-topic',
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'mqtt',
'topic': 'test-topic'
},
'action': {
'execute_service': 'test.automation'
}
}
}))
@ -55,10 +89,14 @@ class TestAutomationState(unittest.TestCase):
def test_if_fires_on_topic_and_payload_match(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'mqtt',
mqtt.CONF_TOPIC: 'test-topic',
mqtt.CONF_PAYLOAD: 'hello',
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'mqtt',
'topic': 'test-topic',
'payload': 'hello'
},
'action': {
'execute_service': 'test.automation'
}
}
}))
@ -69,10 +107,14 @@ class TestAutomationState(unittest.TestCase):
def test_if_not_fires_on_topic_but_no_payload_match(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'mqtt',
mqtt.CONF_TOPIC: 'test-topic',
mqtt.CONF_PAYLOAD: 'hello',
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'mqtt',
'topic': 'test-topic',
'payload': 'hello'
},
'action': {
'execute_service': 'test.automation'
}
}
}))

View file

@ -8,8 +8,6 @@ import unittest
import homeassistant.core as ha
import homeassistant.components.automation as automation
from homeassistant.components.automation import event, numeric_state
from homeassistant.const import CONF_PLATFORM
class TestAutomationNumericState(unittest.TestCase):
@ -28,31 +26,17 @@ class TestAutomationNumericState(unittest.TestCase):
""" Stop down stuff we started. """
self.hass.stop()
def test_setup_fails_if_no_entity_id(self):
self.assertFalse(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_BELOW: 10,
automation.CONF_SERVICE: 'test.automation'
}
}))
def test_setup_fails_if_no_condition(self):
self.assertFalse(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_ENTITY_ID: 'test.entity',
automation.CONF_SERVICE: 'test.automation'
}
}))
def test_if_fires_on_entity_change_below(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_ENTITY_ID: 'test.entity',
numeric_state.CONF_BELOW: 10,
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'numeric_state',
'entity_id': 'test.entity',
'below': 10,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
# 9 is below 10
@ -66,10 +50,14 @@ class TestAutomationNumericState(unittest.TestCase):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_ENTITY_ID: 'test.entity',
numeric_state.CONF_BELOW: 10,
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'numeric_state',
'entity_id': 'test.entity',
'below': 10,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
@ -78,17 +66,20 @@ class TestAutomationNumericState(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_not_fires_on_entity_change_below_to_below(self):
self.hass.states.set('test.entity', 9)
self.hass.pool.block_till_done()
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_ENTITY_ID: 'test.entity',
numeric_state.CONF_BELOW: 10,
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'numeric_state',
'entity_id': 'test.entity',
'below': 10,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
@ -97,14 +88,17 @@ class TestAutomationNumericState(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(0, len(self.calls))
def test_if_fires_on_entity_change_above(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_ENTITY_ID: 'test.entity',
numeric_state.CONF_ABOVE: 10,
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'numeric_state',
'entity_id': 'test.entity',
'above': 10,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
# 11 is above 10
@ -119,10 +113,14 @@ class TestAutomationNumericState(unittest.TestCase):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_ENTITY_ID: 'test.entity',
numeric_state.CONF_ABOVE: 10,
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'numeric_state',
'entity_id': 'test.entity',
'above': 10,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
@ -131,7 +129,6 @@ class TestAutomationNumericState(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_not_fires_on_entity_change_above_to_above(self):
# set initial state
self.hass.states.set('test.entity', 11)
@ -139,10 +136,14 @@ class TestAutomationNumericState(unittest.TestCase):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_ENTITY_ID: 'test.entity',
numeric_state.CONF_ABOVE: 10,
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'numeric_state',
'entity_id': 'test.entity',
'above': 10,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
@ -154,11 +155,15 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_fires_on_entity_change_below_range(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_ENTITY_ID: 'test.entity',
numeric_state.CONF_ABOVE: 5,
numeric_state.CONF_BELOW: 10,
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'numeric_state',
'entity_id': 'test.entity',
'below': 10,
'above': 5,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
# 9 is below 10
@ -169,11 +174,15 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_fires_on_entity_change_below_above_range(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_ENTITY_ID: 'test.entity',
numeric_state.CONF_ABOVE: 5,
numeric_state.CONF_BELOW: 10,
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'numeric_state',
'entity_id': 'test.entity',
'below': 10,
'above': 5,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
# 4 is below 5
@ -187,11 +196,15 @@ class TestAutomationNumericState(unittest.TestCase):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_ENTITY_ID: 'test.entity',
numeric_state.CONF_ABOVE: 5,
numeric_state.CONF_BELOW: 10,
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'numeric_state',
'entity_id': 'test.entity',
'below': 10,
'above': 5,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
@ -206,11 +219,15 @@ class TestAutomationNumericState(unittest.TestCase):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_ENTITY_ID: 'test.entity',
numeric_state.CONF_ABOVE: 5,
numeric_state.CONF_BELOW: 10,
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'numeric_state',
'entity_id': 'test.entity',
'below': 10,
'above': 5,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
@ -222,10 +239,13 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_not_fires_if_entity_not_match(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_ENTITY_ID: 'test.another_entity',
numeric_state.CONF_ABOVE: 10,
automation.CONF_SERVICE: 'test.automation'
'trigger': {
'platform': 'numeric_state',
'entity_id': 'test.another_entity',
},
'action': {
'execute_service': 'test.automation'
}
}
}))
@ -238,19 +258,23 @@ class TestAutomationNumericState(unittest.TestCase):
test_state = 10
automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'event',
event.CONF_EVENT_TYPE: 'test_event',
automation.CONF_SERVICE: 'test.automation',
automation.CONF_IF: [{
CONF_PLATFORM: 'numeric_state',
numeric_state.CONF_ENTITY_ID: entity_id,
numeric_state.CONF_ABOVE: test_state,
numeric_state.CONF_BELOW: test_state + 2,
}]
'trigger': {
'platform': 'event',
'event_type': 'test_event',
},
'condition': {
'platform': 'numeric_state',
'entity_id': entity_id,
'above': test_state,
'below': test_state + 2
},
'action': {
'execute_service': 'test.automation'
}
}
})
self.hass.states.set(entity_id, test_state )
self.hass.states.set(entity_id, test_state)
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()

View file

@ -27,15 +27,7 @@ class TestAutomationState(unittest.TestCase):
""" Stop down stuff we started. """
self.hass.stop()
def test_setup_fails_if_no_entity_id(self):
self.assertFalse(automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'state',
'execute_service': 'test.automation'
}
}))
def test_if_fires_on_entity_change(self):
def test_old_config_if_fires_on_entity_change(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'state',
@ -48,7 +40,7 @@ class TestAutomationState(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_fires_on_entity_change_with_from_filter(self):
def test_old_config_if_fires_on_entity_change_with_from_filter(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'state',
@ -62,7 +54,7 @@ class TestAutomationState(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_fires_on_entity_change_with_to_filter(self):
def test_old_config_if_fires_on_entity_change_with_to_filter(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'state',
@ -76,7 +68,7 @@ class TestAutomationState(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_fires_on_entity_change_with_both_filters(self):
def test_old_config_if_fires_on_entity_change_with_both_filters(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'state',
@ -91,7 +83,7 @@ class TestAutomationState(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_not_fires_if_to_filter_not_match(self):
def test_old_config_if_not_fires_if_to_filter_not_match(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'state',
@ -106,7 +98,7 @@ class TestAutomationState(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(0, len(self.calls))
def test_if_not_fires_if_from_filter_not_match(self):
def test_old_config_if_not_fires_if_from_filter_not_match(self):
self.hass.states.set('test.entity', 'bye')
self.assertTrue(automation.setup(self.hass, {
@ -123,7 +115,7 @@ class TestAutomationState(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(0, len(self.calls))
def test_if_not_fires_if_entity_not_match(self):
def test_old_config_if_not_fires_if_entity_not_match(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'platform': 'state',
@ -136,7 +128,7 @@ class TestAutomationState(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(0, len(self.calls))
def test_if_action(self):
def test_old_config_if_action(self):
entity_id = 'domain.test_entity'
test_state = 'new_state'
automation.setup(self.hass, {
@ -163,3 +155,164 @@ class TestAutomationState(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_fires_on_entity_change(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
'entity_id': 'test.entity',
},
'action': {
'execute_service': 'test.automation'
}
}
}))
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_fires_on_entity_change_with_from_filter(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
'entity_id': 'test.entity',
'from': 'hello'
},
'action': {
'execute_service': 'test.automation'
}
}
}))
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_fires_on_entity_change_with_to_filter(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
'entity_id': 'test.entity',
'to': 'world'
},
'action': {
'execute_service': 'test.automation'
}
}
}))
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_fires_on_entity_change_with_both_filters(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
'entity_id': 'test.entity',
'from': 'hello',
'to': 'world'
},
'action': {
'execute_service': 'test.automation'
}
}
}))
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_not_fires_if_to_filter_not_match(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
'entity_id': 'test.entity',
'from': 'hello',
'to': 'world'
},
'action': {
'execute_service': 'test.automation'
}
}
}))
self.hass.states.set('test.entity', 'moon')
self.hass.pool.block_till_done()
self.assertEqual(0, len(self.calls))
def test_if_not_fires_if_from_filter_not_match(self):
self.hass.states.set('test.entity', 'bye')
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
'entity_id': 'test.entity',
'from': 'hello',
'to': 'world'
},
'action': {
'execute_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_not_fires_if_entity_not_match(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
'entity_id': 'test.anoter_entity',
},
'action': {
'execute_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_action(self):
entity_id = 'domain.test_entity'
test_state = 'new_state'
automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'event',
'event_type': 'test_event',
},
'condition': [{
'platform': 'state',
'entity_id': entity_id,
'state': test_state
}],
'action': {
'execute_service': 'test.automation'
}
}
})
self.hass.states.set(entity_id, test_state)
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
self.hass.states.set(entity_id, test_state + 'something')
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))

View file

@ -33,7 +33,7 @@ class TestAutomationTime(unittest.TestCase):
""" Stop down stuff we started. """
self.hass.stop()
def test_if_fires_when_hour_matches(self):
def test_old_config_if_fires_when_hour_matches(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'time',
@ -48,7 +48,7 @@ class TestAutomationTime(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_fires_when_minute_matches(self):
def test_old_config_if_fires_when_minute_matches(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'time',
@ -63,7 +63,7 @@ class TestAutomationTime(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_fires_when_second_matches(self):
def test_old_config_if_fires_when_second_matches(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'time',
@ -78,7 +78,7 @@ class TestAutomationTime(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_fires_when_all_matches(self):
def test_old_config_if_fires_when_all_matches(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'time',
@ -96,13 +96,13 @@ class TestAutomationTime(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_action_before(self):
def test_old_config_if_action_before(self):
automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'event',
event.CONF_EVENT_TYPE: 'test_event',
automation.CONF_SERVICE: 'test.automation',
automation.CONF_IF: {
'if': {
CONF_PLATFORM: 'time',
time.CONF_BEFORE: '10:00'
}
@ -126,13 +126,13 @@ class TestAutomationTime(unittest.TestCase):
self.assertEqual(1, len(self.calls))
def test_if_action_after(self):
def test_old_config_if_action_after(self):
automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'event',
event.CONF_EVENT_TYPE: 'test_event',
automation.CONF_SERVICE: 'test.automation',
automation.CONF_IF: {
'if': {
CONF_PLATFORM: 'time',
time.CONF_AFTER: '10:00'
}
@ -156,13 +156,13 @@ class TestAutomationTime(unittest.TestCase):
self.assertEqual(1, len(self.calls))
def test_if_action_one_weekday(self):
def test_old_config_if_action_one_weekday(self):
automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'event',
event.CONF_EVENT_TYPE: 'test_event',
automation.CONF_SERVICE: 'test.automation',
automation.CONF_IF: {
'if': {
CONF_PLATFORM: 'time',
time.CONF_WEEKDAY: 'mon',
}
@ -187,13 +187,13 @@ class TestAutomationTime(unittest.TestCase):
self.assertEqual(1, len(self.calls))
def test_if_action_list_weekday(self):
def test_old_config_if_action_list_weekday(self):
automation.setup(self.hass, {
automation.DOMAIN: {
CONF_PLATFORM: 'event',
event.CONF_EVENT_TYPE: 'test_event',
automation.CONF_SERVICE: 'test.automation',
automation.CONF_IF: {
'if': {
CONF_PLATFORM: 'time',
time.CONF_WEEKDAY: ['mon', 'tue'],
}
@ -225,3 +225,228 @@ class TestAutomationTime(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(2, len(self.calls))
def test_if_fires_when_hour_matches(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'time',
'hours': 0,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
fire_time_changed(self.hass, dt_util.utcnow().replace(hour=0))
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_fires_when_minute_matches(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'time',
'minutes': 0,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
fire_time_changed(self.hass, dt_util.utcnow().replace(minute=0))
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_fires_when_second_matches(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'time',
'seconds': 0,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
fire_time_changed(self.hass, dt_util.utcnow().replace(second=0))
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_fires_when_all_matches(self):
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'time',
'hours': 0,
'minutes': 0,
'seconds': 0,
},
'action': {
'execute_service': 'test.automation'
}
}
}))
fire_time_changed(self.hass, dt_util.utcnow().replace(
hour=0, minute=0, second=0))
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_action_before(self):
automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'event',
'event_type': 'test_event'
},
'condition': {
'platform': 'time',
'before': '10:00',
},
'action': {
'execute_service': 'test.automation'
}
}
})
before_10 = dt_util.now().replace(hour=8)
after_10 = dt_util.now().replace(hour=14)
with patch('homeassistant.components.automation.time.dt_util.now',
return_value=before_10):
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
with patch('homeassistant.components.automation.time.dt_util.now',
return_value=after_10):
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_action_after(self):
automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'event',
'event_type': 'test_event'
},
'condition': {
'platform': 'time',
'after': '10:00',
},
'action': {
'execute_service': 'test.automation'
}
}
})
before_10 = dt_util.now().replace(hour=8)
after_10 = dt_util.now().replace(hour=14)
with patch('homeassistant.components.automation.time.dt_util.now',
return_value=before_10):
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(0, len(self.calls))
with patch('homeassistant.components.automation.time.dt_util.now',
return_value=after_10):
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_action_one_weekday(self):
automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'event',
'event_type': 'test_event'
},
'condition': {
'platform': 'time',
'weekday': 'mon',
},
'action': {
'execute_service': 'test.automation'
}
}
})
days_past_monday = dt_util.now().weekday()
monday = dt_util.now() - timedelta(days=days_past_monday)
tuesday = monday + timedelta(days=1)
with patch('homeassistant.components.automation.time.dt_util.now',
return_value=monday):
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
with patch('homeassistant.components.automation.time.dt_util.now',
return_value=tuesday):
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_action_list_weekday(self):
automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'event',
'event_type': 'test_event'
},
'condition': {
'platform': 'time',
'weekday': ['mon', 'tue'],
},
'action': {
'execute_service': 'test.automation'
}
}
})
days_past_monday = dt_util.now().weekday()
monday = dt_util.now() - timedelta(days=days_past_monday)
tuesday = monday + timedelta(days=1)
wednesday = tuesday + timedelta(days=1)
with patch('homeassistant.components.automation.time.dt_util.now',
return_value=monday):
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
with patch('homeassistant.components.automation.time.dt_util.now',
return_value=tuesday):
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(2, len(self.calls))
with patch('homeassistant.components.automation.time.dt_util.now',
return_value=wednesday):
self.hass.bus.fire('test_event')
self.hass.pool.block_till_done()
self.assertEqual(2, len(self.calls))