hass-core/homeassistant/components/automation/time.py

120 lines
4.1 KiB
Python
Raw Normal View History

2015-01-15 23:32:27 -08:00
"""
homeassistant.components.automation.time
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers time listening automation rules.
2015-10-13 21:08:51 +02:00
For more details about this automation rule, please refer to the documentation
2015-11-09 13:12:18 +01:00
at https://home-assistant.io/components/automation/#time-trigger
2015-01-15 23:32:27 -08:00
"""
2015-09-13 22:25:42 -07:00
import logging
2016-01-26 19:37:53 +01:00
from homeassistant.util import convert
2015-09-13 22:25:42 -07:00
import homeassistant.util.dt as dt_util
from homeassistant.helpers.event import track_time_change
2015-01-15 23:32:27 -08:00
2015-09-14 22:05:40 -07:00
CONF_HOURS = "hours"
CONF_MINUTES = "minutes"
CONF_SECONDS = "seconds"
2015-09-13 22:25:42 -07:00
CONF_BEFORE = "before"
CONF_AFTER = "after"
CONF_WEEKDAY = "weekday"
WEEKDAYS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
2015-01-15 23:32:27 -08:00
_LOGGER = logging.getLogger(__name__)
2015-01-15 23:32:27 -08:00
2015-09-13 22:25:42 -07:00
def trigger(hass, config, action):
2015-01-15 23:32:27 -08:00
""" Listen for state changes based on `config`. """
2015-09-15 08:56:06 -07:00
if CONF_AFTER in config:
after = dt_util.parse_time_str(config[CONF_AFTER])
if after is None:
_error_time(config[CONF_AFTER], CONF_AFTER)
2015-09-15 08:56:06 -07:00
return False
hours, minutes, seconds = after.hour, after.minute, after.second
2016-01-12 21:53:27 -08:00
elif (CONF_HOURS in config or CONF_MINUTES in config or
CONF_SECONDS in config):
2016-01-26 17:06:50 +01:00
hours = config.get(CONF_HOURS)
2016-01-26 10:28:31 +01:00
minutes = config.get(CONF_MINUTES)
seconds = config.get(CONF_SECONDS)
2016-01-26 19:37:53 +01:00
if isinstance(minutes, str) and minutes.startswith('/') \
and not convert(minutes.lstrip('/'), int) % 60 == 0:
_LOGGER.warning('Periodic minutes should be divisible with 60'
'there will be an offset every hour')
if isinstance(seconds, str) and seconds.startswith('/') \
and not convert(seconds.lstrip('/'), int) % 60 == 0:
_LOGGER.warning('Periodic seconds should be divisible with 60'
'there will be an offset every minute')
if isinstance(hours, str) and hours.startswith('/') \
2016-01-26 19:37:53 +01:00
and not convert(hours.lstrip('/'), int) % 24 == 0:
_LOGGER.warning('Periodic hours should be divisible with 24'
'there will be an offset every midnight')
else:
_LOGGER.error('One of %s, %s, %s OR %s needs to be specified',
2015-09-17 08:35:18 +02:00
CONF_HOURS, CONF_MINUTES, CONF_SECONDS, CONF_AFTER)
return False
2015-09-15 08:56:06 -07:00
2015-01-15 23:32:27 -08:00
def time_automation_listener(now):
""" Listens for time changes and calls action. """
action()
track_time_change(hass, time_automation_listener,
hour=hours, minute=minutes, second=seconds)
2015-01-15 23:32:27 -08:00
return True
2015-09-13 22:25:42 -07:00
def if_action(hass, config):
2015-09-13 22:25:42 -07:00
""" 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)
return None
2015-09-13 22:25:42 -07:00
if before is not None:
before = dt_util.parse_time_str(before)
if before is None:
_error_time(before, CONF_BEFORE)
return None
if after is not None:
after = dt_util.parse_time_str(after)
if after is None:
_error_time(after, CONF_AFTER)
return None
2015-09-13 22:25:42 -07:00
def time_if():
""" Validate time based if-condition """
now = dt_util.now()
if before is not None and now > now.replace(hour=before.hour,
minute=before.minute):
2015-09-19 12:29:23 -07:00
return False
2015-09-13 22:25:42 -07:00
if after is not None and now < now.replace(hour=after.hour,
minute=after.minute):
2015-09-19 12:29:23 -07:00
return False
2015-09-13 22:25:42 -07:00
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 False
2015-09-13 22:25:42 -07:00
return True
2015-09-13 22:25:42 -07:00
return time_if
def _error_time(value, key):
""" Helper method to print error. """
_LOGGER.error(
"Received invalid value for '%s': %s", key, value)
if isinstance(value, int):
_LOGGER.error('Make sure you wrap time values in quotes')