From 97e82b3808f1e3d77a860a1bdea619214d21a2b6 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Oct 2013 11:47:24 -0700 Subject: [PATCH] Next sun rising and sun setting are now in statemachine. --- homeassistant/actors.py | 19 ++++++----- homeassistant/observers.py | 65 +++++++++++--------------------------- start.py | 8 ++--- 3 files changed, 32 insertions(+), 60 deletions(-) diff --git a/homeassistant/actors.py b/homeassistant/actors.py index aac0984a4e8..fe4004dea71 100644 --- a/homeassistant/actors.py +++ b/homeassistant/actors.py @@ -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): diff --git a/homeassistant/observers.py b/homeassistant/observers.py index 59fb464eed6..476b0b02aa3 100644 --- a/homeassistant/observers.py +++ b/homeassistant/observers.py @@ -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. """ diff --git a/start.py b/start.py index c2b9cebfa7e..0852988ca3a 100644 --- a/start.py +++ b/start.py @@ -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"))