mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +00:00
bug fixes
This commit is contained in:
parent
f3a093feda
commit
0ff00ae5e0
@ -3,7 +3,6 @@ import time
|
||||
|
||||
from app.StateMachine import StateMachine
|
||||
from app.EventBus import EventBus
|
||||
from app.Logging import EventLogger
|
||||
from app.DeviceTracker import DeviceTracker
|
||||
|
||||
from app.observer.WeatherWatcher import WeatherWatcher
|
||||
@ -72,7 +71,7 @@ class HomeAssistant:
|
||||
if self.huetrigger is None:
|
||||
assert self.devicetracker is not None, "Cannot setup Hue Trigger without a device tracker being setup"
|
||||
|
||||
self.huetrigger = HueTrigger(self.get_config(), self.get_event_bus(), self.get_state_machine(), self.devicetracker)
|
||||
self.huetrigger = HueTrigger(self.get_config(), self.get_event_bus(), self.get_state_machine(), self.devicetracker, self.setup_weather_watcher())
|
||||
|
||||
return self.huetrigger
|
||||
|
||||
|
@ -1,15 +1,19 @@
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from phue import Bridge
|
||||
|
||||
from app.observer.WeatherWatcher import EVENT_PRE_SUN_SET_WARNING, STATE_CATEGORY_SUN, SOLAR_STATE_BELOW_HORIZON
|
||||
from app.observer.WeatherWatcher import STATE_CATEGORY_SUN, SUN_STATE_BELOW_HORIZON, SUN_STATE_ABOVE_HORIZON
|
||||
from app.StateMachine import track_state_change
|
||||
from app.DeviceTracker import STATE_CATEGORY_ALL_DEVICES, STATE_DEVICE_HOME, STATE_DEVICE_NOT_HOME
|
||||
|
||||
LIGHTS_TURNING_ON_BEFORE_SUN_SET_PERIOD = timedelta(minutes=20)
|
||||
|
||||
class HueTrigger:
|
||||
def __init__(self, config, eventbus, statemachine, device_tracker):
|
||||
def __init__(self, config, eventbus, statemachine, device_tracker, weather):
|
||||
self.eventbus = eventbus
|
||||
self.statemachine = statemachine
|
||||
self.weather = weather
|
||||
|
||||
self.bridge = Bridge(config.get("hue","host"))
|
||||
self.lights = self.bridge.get_light_objects()
|
||||
@ -22,14 +26,17 @@ class HueTrigger:
|
||||
# Track when all devices are gone to shut down lights
|
||||
track_state_change(eventbus, STATE_CATEGORY_ALL_DEVICES, STATE_DEVICE_HOME, STATE_DEVICE_NOT_HOME, self.handle_device_state_change)
|
||||
|
||||
# Listen for when sun is about to set
|
||||
eventbus.listen(EVENT_PRE_SUN_SET_WARNING, self.handle_sun_setting)
|
||||
# Track every time sun rises so we can schedule a time-based pre-sun set event
|
||||
track_state_change(eventbus, STATE_CATEGORY_SUN, SUN_STATE_BELOW_HORIZON, SUN_STATE_ABOVE_HORIZON, self.handle_sun_rising)
|
||||
|
||||
# If the sun is already above horizon schedule the time-based pre-sun set event
|
||||
if statemachine.get_state(STATE_CATEGORY_SUN, SUN_STATE_ABOVE_HORIZON):
|
||||
self.handle_sun_rising()
|
||||
|
||||
def get_lights_status(self):
|
||||
lights_are_on = sum([1 for light in self.lights if light.on]) > 0
|
||||
|
||||
light_needed = not lights_are_on and self.statemachine.get_state(STATE_CATEGORY_SUN).state == SOLAR_STATE_BELOW_HORIZON
|
||||
light_needed = not lights_are_on and self.statemachine.get_state(STATE_CATEGORY_SUN).state == SUN_STATE_BELOW_HORIZON
|
||||
|
||||
return lights_are_on, light_needed
|
||||
|
||||
@ -52,16 +59,21 @@ class HueTrigger:
|
||||
self.bridge.set_light([1,2,3], command)
|
||||
|
||||
|
||||
def handle_sun_rising(self, event=None):
|
||||
# Schedule an event X minutes prior to sun setting
|
||||
track_time_change(self.eventBus, self.handle_sun_setting, datetime=self.weather.next_sun_setting()-LIGHTS_TURNING_ON_BEFORE_SUN_SET_PERIOD)
|
||||
|
||||
|
||||
# Gets called when darkness starts falling in, slowly turn on the lights
|
||||
def handle_sun_setting(self, event):
|
||||
def handle_sun_setting(self, now):
|
||||
lights_are_on, light_needed = self.get_lights_status()
|
||||
|
||||
if light_needed and self.statemachine.get_state(STATE_CATEGORY_ALL_DEVICES).state == STATE_DEVICE_HOME:
|
||||
if not lights_are_on and self.statemachine.get_state(STATE_CATEGORY_ALL_DEVICES).state == STATE_DEVICE_HOME:
|
||||
self.logger.info("Sun setting and devices home. Turning on lights.")
|
||||
|
||||
# We will start the lights now and by the time the sun sets
|
||||
# the lights will be at full brightness
|
||||
transitiontime = (event.data['sun_setting'] - datetime.now()).seconds * 10
|
||||
transitiontime = (self.weather.next_sun_setting() - datetime.now()).seconds * 10
|
||||
|
||||
self.turn_lights_on(transitiontime)
|
||||
|
||||
|
@ -1,21 +1,32 @@
|
||||
import logging
|
||||
import csv
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
from threading import Lock
|
||||
|
||||
import requests
|
||||
|
||||
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5)
|
||||
|
||||
KNOWN_DEVICES_FILE = "tomato_known_devices.csv"
|
||||
|
||||
class TomatoDeviceScanner:
|
||||
# self.logger
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
self.logger = logging.getLogger("TomatoDeviceScanner")
|
||||
self.lock = Lock()
|
||||
self.date_updated = None
|
||||
self.last_results = None
|
||||
|
||||
# Read known devices
|
||||
with open('tomato_known_devices.csv') as inp:
|
||||
known_devices = { row['mac']: row for row in csv.DictReader(inp) }
|
||||
if os.path.isfile(KNOWN_DEVICES_FILE):
|
||||
with open(KNOWN_DEVICES_FILE) as inp:
|
||||
known_devices = { row['mac']: row for row in csv.DictReader(inp) }
|
||||
|
||||
# Update known devices csv file for future use
|
||||
with open('tomato_known_devices.csv', 'a') as outp:
|
||||
with open(KNOWN_DEVICES_FILE, 'a') as outp:
|
||||
writer = csv.writer(outp)
|
||||
|
||||
# Query for new devices
|
||||
@ -40,18 +51,24 @@ class TomatoDeviceScanner:
|
||||
return self.devices_to_track
|
||||
|
||||
def scan_devices(self):
|
||||
self.logger.info("Scanning for new devices")
|
||||
self.lock.acquire()
|
||||
|
||||
# We don't want to hammer the router. Only update if MIN_TIME_BETWEEN_SCANS has passed
|
||||
if self.date_updated is None or datetime.now() - self.date_updated > MIN_TIME_BETWEEN_SCANS:
|
||||
self.logger.info("Scanning for new devices")
|
||||
|
||||
try:
|
||||
# Query for new devices
|
||||
exec(self.tomato_request("devlist"))
|
||||
|
||||
self.last_results = [mac for iface, mac, rssi, tx, rx, quality, unknown_num in wldev]
|
||||
|
||||
except:
|
||||
self.logger.error("Scanning failed")
|
||||
|
||||
|
||||
# Query for new devices
|
||||
try:
|
||||
exec(self.tomato_request("devlist"))
|
||||
|
||||
return [mac for iface, mac, rssi, tx, rx, quality, unknown_num in wldev]
|
||||
|
||||
except:
|
||||
self.logger.error("Scanning failed")
|
||||
|
||||
return []
|
||||
self.lock.release()
|
||||
return self.last_results
|
||||
|
||||
def tomato_request(self, action):
|
||||
# Get router info
|
||||
|
@ -7,16 +7,10 @@ from app.EventBus import Event
|
||||
|
||||
from app.observer.Timer import track_time_change
|
||||
|
||||
PRE_SUN_SET_WARNING_TIME = 20 # minutes
|
||||
STATE_CATEGORY_SUN = "weather.sun"
|
||||
|
||||
EVENT_PRE_SUN_SET_WARNING = "sun_set_soon"
|
||||
|
||||
STATE_CATEGORY_TEMPLATE_SOLAR = "solar.{}"
|
||||
|
||||
STATE_CATEGORY_SUN = STATE_CATEGORY_TEMPLATE_SOLAR.format("sun")
|
||||
|
||||
SOLAR_STATE_ABOVE_HORIZON = "above_horizon"
|
||||
SOLAR_STATE_BELOW_HORIZON = "below_horizon"
|
||||
SUN_STATE_ABOVE_HORIZON = "above_horizon"
|
||||
SUN_STATE_BELOW_HORIZON = "below_horizon"
|
||||
|
||||
class WeatherWatcher:
|
||||
def __init__(self, config, eventbus, statemachine):
|
||||
@ -25,40 +19,39 @@ class WeatherWatcher:
|
||||
self.eventbus = eventbus
|
||||
self.statemachine = statemachine
|
||||
|
||||
self.observer = ephem.Observer()
|
||||
self.observer.lat = self.config.get('common','latitude')
|
||||
self.observer.long = self.config.get('common','longitude')
|
||||
|
||||
self.sun = ephem.Sun()
|
||||
|
||||
statemachine.add_category(STATE_CATEGORY_SUN, SOLAR_STATE_BELOW_HORIZON)
|
||||
|
||||
self.update_sun_state()
|
||||
|
||||
def update_sun_state(self, now=datetime.now()):
|
||||
self.update_solar_state(ephem.Sun(), STATE_CATEGORY_SUN, self.update_sun_state)
|
||||
def next_sun_rising(self):
|
||||
return ephem.localtime(self.observer.next_rising(self.sun))
|
||||
|
||||
def update_solar_state(self, solar_body, state_category, update_callback):
|
||||
# We don't cache these objects because we use them so rarely
|
||||
observer = ephem.Observer()
|
||||
observer.lat = self.config.get('common','latitude')
|
||||
observer.long = self.config.get('common','longitude')
|
||||
def next_sun_setting(self):
|
||||
return ephem.localtime(self.observer.next_setting(self.sun))
|
||||
|
||||
next_rising = ephem.localtime(observer.next_rising(solar_body))
|
||||
next_setting = ephem.localtime(observer.next_setting(solar_body))
|
||||
def update_sun_state(self, update_callback):
|
||||
next_rising = ephem.localtime(self.observer.next_rising(self.sun))
|
||||
next_setting = ephem.localtime(self.observer.next_setting(self.sun))
|
||||
|
||||
if next_rising > next_setting:
|
||||
new_state = SOLAR_STATE_ABOVE_HORIZON
|
||||
new_state = SUN_STATE_ABOVE_HORIZON
|
||||
next_change = next_setting
|
||||
|
||||
else:
|
||||
new_state = SOLAR_STATE_BELOW_HORIZON
|
||||
new_state = SUN_STATE_BELOW_HORIZON
|
||||
next_change = next_rising
|
||||
|
||||
self.logger.info("Updating solar state for {} to {}. Next change: {}".format(state_category, new_state, next_change))
|
||||
self.logger.info("Updating solar state for {} to {}. Next change: {}".format(STATE_CATEGORY_SUN, new_state, next_change))
|
||||
|
||||
self.statemachine.set_state(state_category, new_state)
|
||||
self.statemachine.set_state(STATE_CATEGORY_SUN, new_state)
|
||||
|
||||
# +10 seconds to be sure that the change has occured
|
||||
track_time_change(self.eventbus, update_callback, datetime=next_change + timedelta(seconds=10))
|
||||
|
||||
# If the sun is visible, schedule to fire an event X minutes before sun set
|
||||
if solar_body.name == 'Sun' and new_state == SOLAR_STATE_ABOVE_HORIZON:
|
||||
track_time_change(self.eventbus, lambda time: self.eventbus.fire(Event(EVENT_PRE_SUN_SET_WARNING, {'sun_setting':next_change})),
|
||||
datetime=next_change - timedelta(minutes=PRE_SUN_SET_WARNING_TIME))
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user