I have followed @ReneTode 's light schedule closely. I even implemented a similar version using a csv file to maintain the schedule for each light.
With the new updates to the appdaemon config and moving to yaml, I’ve taken another stab at it in an attempt to make it easier to maintain. Here is what my current version looks like:
The App
import appdaemon.appapi as appapi
import re
import datetime
# App to schedule lights on and off
#
# EXAMPLE appdaemon.yaml entry below
#
# # Apps
#
# Lights V2:
# class: lights_v2
# module: lights_v2
# lights:
# - light: light.eave_lights
# on_time: "sunset - 00:15:00"
# on_random_start: 10
# on_random_end: 20
# off_time: "23:00:00"
# off_random_start: -5
# off_random_end: 0
# constrain_days: "mon,tue,wed,thu,fri,sat,sun"
# - light: light.eave_lights
# on_time: "05:40:00"
# on_random_start: -5
# on_random_end: 5
# off_time: "sunrise"
# off_random_start: -15
# off_random_end: 0
# constrain_days: "mon,tue,wed,thu,fri"
class lights_v2(appapi.AppDaemon):
def initialize(self):
# self.log("test")
# self.log(self.args["lights"])
if "lights" in self.args:
for lightconfig in self.args["lights"]:
light = lightconfig["light"]
constrain_days = lightconfig["constrain_days"]
## Light On Detail
on_time = lightconfig["on_time"]
on_random_start = int(lightconfig["on_random_start"]) * 60
on_random_end = int(lightconfig["on_random_end"]) * 60
self.setup_on_time(light, on_time, on_random_start, on_random_end, constrain_days)
## Light Off Detail
off_time = lightconfig["off_time"]
off_random_start = int(lightconfig["off_random_start"]) * 60
off_random_end = int(lightconfig["off_random_end"]) * 60
self.setup_off_time(light, off_time, off_random_start, off_random_end, constrain_days)
def setup_on_time(self, light, on_time, start, end, constrain_days):
on_time_parsed = self.parse_time(on_time)
if int(start) >= int(end):
self.log("{}: on_random_start must be numerically lower than on_random_end".format(light), "ERROR")
elif type(on_time_parsed) is not datetime.time:
self.log("{}: on_time must be in string format".format(light), "ERROR")
else:
sun_on = False
on_time_set = False
if on_time == "sunset":
sun_on = True
on_time_set = True
self.run_at_sunset(self.set_lights_on, random_start=start, random_end=end, constrain_days=constrain_days, switch=light)
if on_time == "sunrise":
sun_on = True
on_time_set = True
self.run_at_sunrise(self.set_lights_on, random_start=start, random_end=end, constrain_days=constrain_days, switch=light)
if not sun_on:
on_time_set = True
self.run_daily(self.set_lights_on, on_time_parsed, random_start=start, random_end=end, constrain_days=constrain_days, switch=light)
if on_time_set:
msg = "{} set to turn on at {}".format(light, on_time)
if on_time != str(on_time_parsed):
msg += " ({})".format(on_time_parsed)
self.log(msg, "INFO")
def setup_off_time(self, light, off_time, start, end, constrain_days):
off_time_parsed = self.parse_time(off_time)
if int(start) >= int(end):
self.log("{}: off_random_start must be numerically lower than off_random_end".format(light), "ERROR")
elif type(off_time_parsed) is not datetime.time:
self.log("{}: off_time must be in string format".format(light), "ERROR")
else:
sun_off = False
off_time_set = False
if off_time == "sunset":
sun_off = True
off_time_set = True
self.run_at_sunset(self.set_lights_off, random_start=start, random_end=end, constrain_days=constrain_days, switch=light)
if off_time == "sunrise":
sun_off = True
off_time_set = True
self.run_at_sunrise(self.set_lights_off, random_start=start, random_end=end, constrain_days=constrain_days, switch=light)
if not sun_off:
off_time_set = True
self.run_daily(self.set_lights_off, off_time_parsed, random_start=start, random_end=end, constrain_days=constrain_days, switch=light)
if off_time_set:
msg = "{} set to turn off at {}".format(light, off_time)
if off_time != str(off_time_parsed):
msg += " ({})".format(off_time_parsed)
self.log(msg, "INFO")
def set_lights_on(self, kwargs):
msg = "Turned {} on.".format(self.friendly_name(kwargs["switch"]))
self.log(msg, "INFO")
self.call_service("notify/notify", message=msg)
self.turn_on(kwargs["switch"])
def set_lights_off(self, kwargs):
msg = "Turned {} off.".format(self.friendly_name(kwargs["switch"]))
self.log(msg, "INFO")
self.call_service("notify/notify", message=msg)
self.turn_off(kwargs["switch"])