mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
Add sun automation trigger
This commit is contained in:
parent
e26f0f7b7d
commit
2978e0dabe
103
homeassistant/components/automation/sun.py
Normal file
103
homeassistant/components/automation/sun.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
"""
|
||||||
|
homeassistant.components.automation.sun
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Offers sun based automation rules.
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from homeassistant.components import sun
|
||||||
|
from homeassistant.helpers.event import track_point_in_utc_time
|
||||||
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
|
DEPENDENCIES = ['sun']
|
||||||
|
|
||||||
|
CONF_OFFSET = 'offset'
|
||||||
|
CONF_EVENT = 'event'
|
||||||
|
|
||||||
|
EVENT_SUNSET = 'sunset'
|
||||||
|
EVENT_SUNRISE = 'sunrise'
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def trigger(hass, config, action):
|
||||||
|
""" Listen for events based on config. """
|
||||||
|
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
|
||||||
|
|
||||||
|
if CONF_OFFSET in config:
|
||||||
|
raw_offset = config.get(CONF_OFFSET)
|
||||||
|
|
||||||
|
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
|
||||||
|
else:
|
||||||
|
offset = timedelta(0)
|
||||||
|
|
||||||
|
# Do something to call action
|
||||||
|
if event == EVENT_SUNRISE:
|
||||||
|
trigger_sunrise(hass, action, offset)
|
||||||
|
else:
|
||||||
|
trigger_sunset(hass, action, offset)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def trigger_sunrise(hass, action, offset):
|
||||||
|
""" Trigger action at next sun rise. """
|
||||||
|
def next_rise():
|
||||||
|
""" Returns next sunrise. """
|
||||||
|
next_time = sun.next_rising_utc(hass) + offset
|
||||||
|
|
||||||
|
while next_time < dt_util.utcnow():
|
||||||
|
next_time = next_time + timedelta(days=1)
|
||||||
|
|
||||||
|
return next_time
|
||||||
|
|
||||||
|
def sunrise_automation_listener(now):
|
||||||
|
""" Called when it's time for action. """
|
||||||
|
track_point_in_utc_time(hass, sunrise_automation_listener, next_rise())
|
||||||
|
action()
|
||||||
|
|
||||||
|
track_point_in_utc_time(hass, sunrise_automation_listener, next_rise())
|
||||||
|
|
||||||
|
|
||||||
|
def trigger_sunset(hass, action, offset):
|
||||||
|
""" Trigger action at next sun set. """
|
||||||
|
def next_set():
|
||||||
|
""" Returns next sunrise. """
|
||||||
|
next_time = sun.next_setting_utc(hass) + offset
|
||||||
|
|
||||||
|
while next_time < dt_util.utcnow():
|
||||||
|
next_time = next_time + timedelta(days=1)
|
||||||
|
|
||||||
|
return next_time
|
||||||
|
|
||||||
|
def sunset_automation_listener(now):
|
||||||
|
""" Called when it's time for action. """
|
||||||
|
track_point_in_utc_time(hass, sunset_automation_listener, next_set())
|
||||||
|
action()
|
||||||
|
|
||||||
|
track_point_in_utc_time(hass, sunset_automation_listener, next_set())
|
128
tests/components/automation/test_sun.py
Normal file
128
tests/components/automation/test_sun.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
"""
|
||||||
|
tests.components.automation.test_sun
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Tests sun automation.
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import homeassistant.core as ha
|
||||||
|
from homeassistant.components import sun
|
||||||
|
import homeassistant.components.automation as automation
|
||||||
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
|
from tests.common import fire_time_changed
|
||||||
|
|
||||||
|
|
||||||
|
class TestAutomationSun(unittest.TestCase):
|
||||||
|
""" Test the sun automation. """
|
||||||
|
|
||||||
|
def setUp(self): # pylint: disable=invalid-name
|
||||||
|
self.hass = ha.HomeAssistant()
|
||||||
|
self.hass.config.components.append('sun')
|
||||||
|
|
||||||
|
self.calls = []
|
||||||
|
|
||||||
|
def record_call(service):
|
||||||
|
self.calls.append(service)
|
||||||
|
|
||||||
|
self.hass.services.register('test', 'automation', record_call)
|
||||||
|
|
||||||
|
def tearDown(self): # pylint: disable=invalid-name
|
||||||
|
""" Stop down stuff we started. """
|
||||||
|
self.hass.stop()
|
||||||
|
|
||||||
|
def test_sunset_trigger(self):
|
||||||
|
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
|
||||||
|
sun.STATE_ATTR_NEXT_SETTING: '02:00:00 16-09-2015',
|
||||||
|
})
|
||||||
|
|
||||||
|
trigger_time = datetime(2015, 9, 16, 2, tzinfo=dt_util.UTC)
|
||||||
|
|
||||||
|
self.assertTrue(automation.setup(self.hass, {
|
||||||
|
automation.DOMAIN: {
|
||||||
|
'trigger': {
|
||||||
|
'platform': 'sun',
|
||||||
|
'event': 'sunset',
|
||||||
|
},
|
||||||
|
'action': {
|
||||||
|
'execute_service': 'test.automation',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
fire_time_changed(self.hass, trigger_time)
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
self.assertEqual(1, len(self.calls))
|
||||||
|
|
||||||
|
def test_sunrise_trigger(self):
|
||||||
|
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
|
||||||
|
sun.STATE_ATTR_NEXT_RISING: '14:00:00 16-09-2015',
|
||||||
|
})
|
||||||
|
|
||||||
|
trigger_time = datetime(2015, 9, 16, 14, tzinfo=dt_util.UTC)
|
||||||
|
|
||||||
|
self.assertTrue(automation.setup(self.hass, {
|
||||||
|
automation.DOMAIN: {
|
||||||
|
'trigger': {
|
||||||
|
'platform': 'sun',
|
||||||
|
'event': 'sunset',
|
||||||
|
},
|
||||||
|
'action': {
|
||||||
|
'execute_service': 'test.automation',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
fire_time_changed(self.hass, trigger_time)
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
self.assertEqual(1, len(self.calls))
|
||||||
|
|
||||||
|
def test_sunset_trigger_with_offset(self):
|
||||||
|
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
|
||||||
|
sun.STATE_ATTR_NEXT_SETTING: '02:00:00 16-09-2015',
|
||||||
|
})
|
||||||
|
|
||||||
|
trigger_time = datetime(2015, 9, 16, 2, 30, tzinfo=dt_util.UTC)
|
||||||
|
|
||||||
|
self.assertTrue(automation.setup(self.hass, {
|
||||||
|
automation.DOMAIN: {
|
||||||
|
'trigger': {
|
||||||
|
'platform': 'sun',
|
||||||
|
'event': 'sunset',
|
||||||
|
'offset': '0:30:00'
|
||||||
|
},
|
||||||
|
'action': {
|
||||||
|
'execute_service': 'test.automation',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
fire_time_changed(self.hass, trigger_time)
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
self.assertEqual(1, len(self.calls))
|
||||||
|
|
||||||
|
def test_sunrise_trigger_with_offset(self):
|
||||||
|
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
|
||||||
|
sun.STATE_ATTR_NEXT_RISING: '14:00:00 16-09-2015',
|
||||||
|
})
|
||||||
|
|
||||||
|
trigger_time = datetime(2015, 9, 16, 13, 30, tzinfo=dt_util.UTC)
|
||||||
|
|
||||||
|
self.assertTrue(automation.setup(self.hass, {
|
||||||
|
automation.DOMAIN: {
|
||||||
|
'trigger': {
|
||||||
|
'platform': 'sun',
|
||||||
|
'event': 'sunset',
|
||||||
|
'offset': '-0:30:00'
|
||||||
|
},
|
||||||
|
'action': {
|
||||||
|
'execute_service': 'test.automation',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
fire_time_changed(self.hass, trigger_time)
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
self.assertEqual(1, len(self.calls))
|
Loading…
x
Reference in New Issue
Block a user