Next sun rising and sun setting are now in statemachine.

This commit is contained in:
Paulus Schoutsen 2013-10-06 11:47:24 -07:00
parent cb4fce7691
commit 97e82b3808
3 changed files with 32 additions and 60 deletions

View file

@ -9,13 +9,14 @@ This module provides actors that will react to events happening within homeassis
import logging
from datetime import datetime, timedelta
import dateutil.parser
from phue import Bridge
from . import track_state_change
from .observers import (STATE_CATEGORY_SUN, SUN_STATE_BELOW_HORIZON, SUN_STATE_ABOVE_HORIZON,
STATE_CATEGORY_ALL_DEVICES, DEVICE_STATE_HOME, DEVICE_STATE_NOT_HOME,
track_time_change)
STATE_CATEGORY_NEXT_SUN_SETTING, track_time_change)
LIGHT_TRANSITION_TIME = timedelta(minutes=15)
@ -30,10 +31,9 @@ def _hue_process_transition_time(transition_seconds):
class LightTrigger(object):
""" Class to turn on lights based on available devices and state of the sun. """
def __init__(self, eventbus, statemachine, weather, device_tracker, light_control):
def __init__(self, eventbus, statemachine, device_tracker, light_control):
self.eventbus = eventbus
self.statemachine = statemachine
self.weather = weather
self.light_control = light_control
self.logger = logging.getLogger(__name__)
@ -58,7 +58,7 @@ class LightTrigger(object):
We will schedule to have each light start after one another
and slowly transition in."""
start_point = self._get_start_point_turn_light_before_sun_set()
start_point = self._start_point_turn_light_before_sun_set()
def turn_on(light_id):
""" Lambda can keep track of function parameters, not from local parameters
@ -87,7 +87,7 @@ class LightTrigger(object):
if category != STATE_CATEGORY_ALL_DEVICES and new_state.state == DEVICE_STATE_HOME:
# These variables are needed for the elif check
now = datetime.now()
start_point = self._get_start_point_turn_light_before_sun_set()
start_point = self._start_point_turn_light_before_sun_set()
# Do we need lights?
if light_needed:
@ -96,7 +96,7 @@ class LightTrigger(object):
# Are we in the time span were we would turn on the lights if someone would be home?
# Check this by seeing if current time is later then the start point
elif now > start_point and now < self.weather.next_sun_setting():
elif now > start_point and now < self._next_sun_setting():
# If this is the case check for every light if it would be on
# if someone was home when the fading in started and turn it on
@ -116,11 +116,14 @@ class LightTrigger(object):
self.logger.info("Everyone has left but lights are on. Turning lights off")
self.light_control.turn_light_off()
def _next_sun_setting(self):
""" Returns the datetime object representing the next sun setting. """
return dateutil.parser.parse(self.statemachine.get_state(STATE_CATEGORY_NEXT_SUN_SETTING).state)
def _get_start_point_turn_light_before_sun_set(self):
def _start_point_turn_light_before_sun_set(self):
""" Helper method to calculate the point in time we have to start fading in lights
so that all the lights are on the moment the sun sets. """
return self.weather.next_sun_setting() - LIGHT_TRANSITION_TIME * len(self.light_control.light_ids)
return self._next_sun_setting() - LIGHT_TRANSITION_TIME * len(self.light_control.light_ids)
class HueLightControl(object):

View file

@ -21,6 +21,8 @@ import ephem
from . import track_time_change
STATE_CATEGORY_SUN = "weather.sun"
STATE_CATEGORY_NEXT_SUN_RISING = "weather.next_sun_rising"
STATE_CATEGORY_NEXT_SUN_SETTING = "weather.next_setting"
STATE_CATEGORY_ALL_DEVICES = 'all_devices'
STATE_CATEGORY_DEVICE_FORMAT = '{}'
@ -37,46 +39,19 @@ TOMATO_MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5)
TOMATO_KNOWN_DEVICES_FILE = "tomato_known_devices.csv"
class WeatherWatcher(object):
""" Class that keeps track of the state of the sun. """
def track_sun(eventbus, statemachine, latitude, longitude):
""" Tracks the state of the sun. """
def __init__(self, eventbus, statemachine, latitude, longitude):
self.logger = logging.getLogger(__name__)
self.eventbus = eventbus
self.statemachine = statemachine
self.latitude = latitude
self.longitude = longitude
sun = ephem.Sun()
logger = logging.getLogger(__name__)
self.sun = ephem.Sun()
def update_sun_state(now):
observer = ephem.Observer()
observer.lat = latitude
observer.long = longitude
self._update_sun_state()
def next_sun_rising(self, observer=None):
""" Returns a datetime object that points at the next sun rising. """
if observer is None:
observer = self._get_observer()
return ephem.localtime(observer.next_rising(self.sun))
def next_sun_setting(self, observer=None):
""" Returns a datetime object that points at the next sun setting. """
if observer is None:
observer = self._get_observer()
return ephem.localtime(observer.next_setting(self.sun))
def _update_sun_state(self, now=None):
""" Updates the state of the sun and schedules when to check next. """
observer = self._get_observer()
next_rising = self.next_sun_rising(observer)
next_setting = self.next_sun_setting(observer)
next_rising = ephem.localtime(observer.next_rising(sun))
next_setting = ephem.localtime(observer.next_setting(sun))
if next_rising > next_setting:
new_state = SUN_STATE_ABOVE_HORIZON
@ -86,21 +61,17 @@ class WeatherWatcher(object):
new_state = SUN_STATE_BELOW_HORIZON
next_change = next_rising
self.logger.info("Sun:{}. Next change: {}".format(new_state, next_change.strftime("%H:%M")))
logger.info("Sun:{}. Next change: {}".format(new_state, next_change.strftime("%H:%M")))
self.statemachine.set_state(STATE_CATEGORY_SUN, new_state)
statemachine.set_state(STATE_CATEGORY_SUN, new_state)
statemachine.set_state(STATE_CATEGORY_NEXT_SUN_RISING, next_rising.isoformat())
statemachine.set_state(STATE_CATEGORY_NEXT_SUN_SETTING, next_setting.isoformat())
# +10 seconds to be sure that the change has occured
track_time_change(self.eventbus, self._update_sun_state, point_in_time=next_change + timedelta(seconds=10))
track_time_change(eventbus, update_sun_state, point_in_time=next_change + timedelta(seconds=10))
update_sun_state(None)
def _get_observer(self):
""" Creates an observer representing the location and the current time. """
observer = ephem.Observer()
observer.lat = self.latitude
observer.long = self.longitude
return observer
class DeviceTracker(object):
""" Class that tracks which devices are home and which are not. """

View file

@ -2,7 +2,7 @@ from ConfigParser import SafeConfigParser
from homeassistant import StateMachine, EventBus, start_home_assistant
from homeassistant.observers import TomatoDeviceScanner, DeviceTracker, WeatherWatcher
from homeassistant.observers import TomatoDeviceScanner, DeviceTracker, track_sun
from homeassistant.actors import HueLightControl, LightTrigger
from homeassistant.httpinterface import HTTPInterface
@ -20,12 +20,10 @@ tomato = TomatoDeviceScanner(config.get('tomato','host'), config.get('tomato','u
devicetracker = DeviceTracker(eventbus, statemachine, tomato)
weatherwatcher = WeatherWatcher(eventbus, statemachine,
config.get("common","latitude"),
config.get("common","longitude"))
track_sun(eventbus, statemachine, config.get("common","latitude"), config.get("common","longitude"))
# Init actors
LightTrigger(eventbus, statemachine, weatherwatcher, devicetracker, HueLightControl())
LightTrigger(eventbus, statemachine, devicetracker, HueLightControl())
# Init HTTP interface
HTTPInterface(eventbus, statemachine, config.get("common","api_password"))