-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvacationmode.py
97 lines (82 loc) · 3.95 KB
/
vacationmode.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import random
from astral import Astral
from datetime import datetime, timedelta, time
from timedevent import TimedEvent
from scenes import VACATION_SCENES
import logging
logger = logging.getLogger(__name__)
#
# This event builds the script of events for vacation mode for a single day. Once it executes, it will rescue
#
class VacationBuildEvent(TimedEvent):
def __init__(self, event_time, parent):
TimedEvent.__init__(self, event_time)
self.parent = parent
def execute(self):
date = datetime.now().date()
events = self.parent.create_scene_script(date)
for event in events:
if event.event_time >= datetime.now():
self.parent.home.timed_event_queue.add_event(event)
date += timedelta(days=1)
next_build_time = datetime.combine(date, time(10)) # Build the next day's script at 10am
self.parent.home.timed_event_queue.add_event(VacationBuildEvent(next_build_time, self.parent))
class VacationLightEvent(TimedEvent):
def __init__(self, event_time, home, scene_off, scene_on):
TimedEvent.__init__(self, event_time)
self.home = home
self.scene_off = scene_off
self.scene_on = scene_on
def execute(self):
if self.scene_off is not None:
logger.info("Vacation turning off {0}".format(self.scene_off.names[0]))
self.scene_off.off(self.home.lights)
if self.scene_on is not None:
logger.info("Vacation turning on {0}".format(self.scene_on.names[0]))
self.scene_on.on(self.home.lights)
class VacationMode:
def __init__(self, home, start=timedelta(minutes=-30), end_time=time(23, 0, 0), interval=timedelta(minutes=30)):
self.start = start # Can be either a timedelta or a datetime.time
self.end_time = end_time
self.interval = interval
self.home = home
self.enabled = False
# After all the services have been started this method is called. If the persistent store shows that we are
# in vacation mode then we probably just had a power failure.
def init_from_persistent_store(self):
if self.home.persistent_store.get_value('vacation_mode', default=False):
logger.info("Enabling vacation mode because enabled in persistent store")
self.enable()
def enable(self, delay=timedelta(minutes=5)):
if not self.enabled:
logger.info("Enabling vacation mode")
self.enabled = True
self.home.persistent_store['vacation_mode'] = True
self.home.timed_event_queue.add_event(VacationBuildEvent(datetime.now() + delay, self))
def disable(self):
if self.enabled:
logger.info("Disabling vacation mode")
self.enabled = False
self.home.persistent_store['vacation_mode'] = False
self.home.timed_event_queue.remove_events(VacationBuildEvent)
self.home.timed_event_queue.remove_events(VacationLightEvent)
def create_scene_script(self, date):
if isinstance(self.start, timedelta):
a = Astral()
start_time = (a['seattle'].sun(date=date, local=True)['sunset'] + self.start).time()
else:
start_time = self.start
last_on = None
events = []
start_datetime = datetime.combine(date, start_time)
end_datetime = datetime.combine(date, self.end_time)
while start_datetime < end_datetime:
next_on = random.choice(VACATION_SCENES.all_scenes)
if next_on == last_on:
next_on = None # If we randomly choose the same scene twice in a row, don't turn anything on
events.append(VacationLightEvent(start_datetime, self.home, last_on, next_on))
last_on = next_on
start_datetime += self.interval
# always turn off the last_on light at the end of the script
events.append(VacationLightEvent(start_datetime, self.home, last_on, None))
return events