Add if to automation
parent
046c5653cb
commit
2a11d02fe4
|
@ -9,7 +9,7 @@ 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
|
||||
from homeassistant.const import ATTR_ENTITY_ID, CONF_PLATFORM
|
||||
|
||||
DOMAIN = "automation"
|
||||
|
||||
|
@ -19,6 +19,7 @@ CONF_ALIAS = "alias"
|
|||
CONF_SERVICE = "execute_service"
|
||||
CONF_SERVICE_ENTITY_ID = "service_entity_id"
|
||||
CONF_SERVICE_DATA = "service_data"
|
||||
CONF_IF = "if"
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -34,7 +35,12 @@ def setup(hass, config):
|
|||
_LOGGER.error("Unknown automation platform specified: %s", p_type)
|
||||
continue
|
||||
|
||||
if platform.register(hass, p_config, _get_action(hass, p_config)):
|
||||
action = _get_action(hass, p_config)
|
||||
|
||||
if CONF_IF in p_config:
|
||||
action = _process_if(hass, config, p_config[CONF_IF], action)
|
||||
|
||||
if platform.trigger(hass, p_config, action):
|
||||
_LOGGER.info(
|
||||
"Initialized %s rule %s", p_type, p_config.get(CONF_ALIAS, ""))
|
||||
success = True
|
||||
|
@ -72,3 +78,28 @@ def _get_action(hass, config):
|
|||
hass.services.call(domain, service, service_data)
|
||||
|
||||
return action
|
||||
|
||||
|
||||
def _process_if(hass, config, if_configs, action):
|
||||
""" Processes if checks. """
|
||||
|
||||
if isinstance(if_configs, dict):
|
||||
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)
|
||||
continue
|
||||
|
||||
action = platform.if_action(hass, if_config, action)
|
||||
|
||||
return action
|
||||
|
|
|
@ -12,7 +12,7 @@ CONF_EVENT_DATA = "event_data"
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def register(hass, config, action):
|
||||
def trigger(hass, config, action):
|
||||
""" Listen for events based on config. """
|
||||
event_type = config.get(CONF_EVENT_TYPE)
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ CONF_TOPIC = 'mqtt_topic'
|
|||
CONF_PAYLOAD = 'mqtt_payload'
|
||||
|
||||
|
||||
def register(hass, config, action):
|
||||
def trigger(hass, config, action):
|
||||
""" Listen for state changes based on `config`. """
|
||||
topic = config.get(CONF_TOPIC)
|
||||
payload = config.get(CONF_PAYLOAD)
|
||||
|
|
|
@ -16,7 +16,7 @@ CONF_ABOVE = "state_above"
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def register(hass, config, action):
|
||||
def trigger(hass, config, action):
|
||||
""" Listen for state changes based on `config`. """
|
||||
entity_id = config.get(CONF_ENTITY_ID)
|
||||
|
||||
|
|
|
@ -13,15 +13,16 @@ from homeassistant.const import MATCH_ALL
|
|||
CONF_ENTITY_ID = "state_entity_id"
|
||||
CONF_FROM = "state_from"
|
||||
CONF_TO = "state_to"
|
||||
CONF_STATE = "state"
|
||||
|
||||
|
||||
def register(hass, config, action):
|
||||
def trigger(hass, config, action):
|
||||
""" Listen for state changes based on `config`. """
|
||||
entity_id = config.get(CONF_ENTITY_ID)
|
||||
|
||||
if entity_id is None:
|
||||
logging.getLogger(__name__).error(
|
||||
"Missing configuration key %s", CONF_ENTITY_ID)
|
||||
"Missing trigger configuration key %s", CONF_ENTITY_ID)
|
||||
return False
|
||||
|
||||
from_state = config.get(CONF_FROM, MATCH_ALL)
|
||||
|
@ -35,3 +36,22 @@ def register(hass, config, action):
|
|||
hass, entity_id, state_automation_listener, from_state, to_state)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def if_action(hass, config, action):
|
||||
""" Wraps 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 action
|
||||
|
||||
def state_if():
|
||||
""" Execute action if state matches. """
|
||||
if hass.states.is_state(entity_id, state):
|
||||
action()
|
||||
|
||||
return state_if
|
||||
|
|
|
@ -4,15 +4,23 @@ homeassistant.components.automation.time
|
|||
|
||||
Offers time listening automation rules.
|
||||
"""
|
||||
import logging
|
||||
|
||||
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_BEFORE = "before"
|
||||
CONF_AFTER = "after"
|
||||
CONF_WEEKDAY = "weekday"
|
||||
|
||||
WEEKDAYS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
|
||||
|
||||
|
||||
def register(hass, config, action):
|
||||
def trigger(hass, config, action):
|
||||
""" Listen for state changes based on `config`. """
|
||||
hours = convert(config.get(CONF_HOURS), int)
|
||||
minutes = convert(config.get(CONF_MINUTES), int)
|
||||
|
@ -26,3 +34,49 @@ def register(hass, config, action):
|
|||
hour=hours, minute=minutes, second=seconds)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def if_action(hass, config, action):
|
||||
""" Wraps action method with time based condition. """
|
||||
before = config.get(CONF_BEFORE)
|
||||
after = config.get(CONF_AFTER)
|
||||
weekday = config.get(CONF_WEEKDAY)
|
||||
|
||||
if before is None and after is None and weekday is None:
|
||||
logging.getLogger(__name__).error(
|
||||
"Missing if-condition configuration key %s, %s or %s",
|
||||
CONF_BEFORE, CONF_AFTER, CONF_WEEKDAY)
|
||||
|
||||
def time_if():
|
||||
""" Validate time based if-condition """
|
||||
now = dt_util.now()
|
||||
|
||||
if before is not None:
|
||||
# Strip seconds if given
|
||||
before_h, before_m = before.split(':')[0:2]
|
||||
|
||||
before_point = now.replace(hour=int(before_h),
|
||||
minute=int(before_m))
|
||||
|
||||
if now > before_point:
|
||||
return
|
||||
|
||||
if after is not None:
|
||||
# Strip seconds if given
|
||||
after_h, after_m = after.split(':')[0:2]
|
||||
|
||||
after_point = now.replace(hour=int(after_h), minute=int(after_m))
|
||||
|
||||
if now < after_point:
|
||||
return
|
||||
|
||||
if weekday is not None:
|
||||
now_weekday = WEEKDAYS[now.weekday()]
|
||||
|
||||
if isinstance(weekday, str) and weekday != now_weekday or \
|
||||
now_weekday not in weekday:
|
||||
return
|
||||
|
||||
action()
|
||||
|
||||
return time_if
|
||||
|
|
|
@ -8,7 +8,7 @@ import unittest
|
|||
|
||||
import homeassistant.core as ha
|
||||
import homeassistant.components.automation as automation
|
||||
import homeassistant.components.automation.state as state
|
||||
from homeassistant.components.automation import event, state
|
||||
from homeassistant.const import CONF_PLATFORM
|
||||
|
||||
|
||||
|
@ -137,3 +137,31 @@ class TestAutomationState(unittest.TestCase):
|
|||
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: {
|
||||
CONF_PLATFORM: 'event',
|
||||
event.CONF_EVENT_TYPE: 'test_event',
|
||||
automation.CONF_SERVICE: 'test.automation',
|
||||
automation.CONF_IF: [{
|
||||
CONF_PLATFORM: 'state',
|
||||
state.CONF_ENTITY_ID: entity_id,
|
||||
state.CONF_STATE: test_state,
|
||||
}]
|
||||
}
|
||||
})
|
||||
|
||||
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))
|
||||
|
|
|
@ -4,13 +4,14 @@ tests.test_component_demo
|
|||
|
||||
Tests demo component.
|
||||
"""
|
||||
from datetime import timedelta
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
import homeassistant.core as ha
|
||||
import homeassistant.loader as loader
|
||||
import homeassistant.util.dt as dt_util
|
||||
import homeassistant.components.automation as automation
|
||||
import homeassistant.components.automation.time as time
|
||||
from homeassistant.components.automation import time, event
|
||||
from homeassistant.const import CONF_PLATFORM
|
||||
|
||||
from tests.common import fire_time_changed
|
||||
|
@ -94,3 +95,133 @@ class TestAutomationTime(unittest.TestCase):
|
|||
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: {
|
||||
CONF_PLATFORM: 'event',
|
||||
event.CONF_EVENT_TYPE: 'test_event',
|
||||
automation.CONF_SERVICE: 'test.automation',
|
||||
automation.CONF_IF: {
|
||||
CONF_PLATFORM: 'time',
|
||||
time.CONF_BEFORE: '10:00'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
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: {
|
||||
CONF_PLATFORM: 'event',
|
||||
event.CONF_EVENT_TYPE: 'test_event',
|
||||
automation.CONF_SERVICE: 'test.automation',
|
||||
automation.CONF_IF: {
|
||||
CONF_PLATFORM: 'time',
|
||||
time.CONF_AFTER: '10:00'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
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: {
|
||||
CONF_PLATFORM: 'event',
|
||||
event.CONF_EVENT_TYPE: 'test_event',
|
||||
automation.CONF_SERVICE: 'test.automation',
|
||||
automation.CONF_IF: {
|
||||
CONF_PLATFORM: 'time',
|
||||
time.CONF_WEEKDAY: 'mon',
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
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: {
|
||||
CONF_PLATFORM: 'event',
|
||||
event.CONF_EVENT_TYPE: 'test_event',
|
||||
automation.CONF_SERVICE: 'test.automation',
|
||||
automation.CONF_IF: {
|
||||
CONF_PLATFORM: 'time',
|
||||
time.CONF_WEEKDAY: ['mon', 'tue'],
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
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))
|
||||
|
|
Loading…
Reference in New Issue