From 1c94bb1c0f935125b4ba504c56068a1bac8d729d Mon Sep 17 00:00:00 2001 From: Gustav Ahlberg Date: Wed, 26 Nov 2014 19:28:36 +0100 Subject: [PATCH] Schedule component and time event The schedule can read a schedule.json file and create time events --- .../components/scheduler/__init__.py | 80 ++++++++++++++++--- homeassistant/components/scheduler/sun.py | 6 +- homeassistant/components/scheduler/time.py | 75 ++++++++++++++++- 3 files changed, 145 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/scheduler/__init__.py b/homeassistant/components/scheduler/__init__.py index de950d03a47..1894d9eb8bf 100644 --- a/homeassistant/components/scheduler/__init__.py +++ b/homeassistant/components/scheduler/__init__.py @@ -1,14 +1,25 @@ """ homeassistant.components.scheduler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +A component that will act as a scheduler and performe actions based +on the events in the schedule. + +It will read a json object from schedule.json in the config dir +and create a schedule based on it. +Each schedule is a JSON with the keys id, name, description, +entity_ids, and events. +- days is an array with the weekday number (monday=0) that the schdule + is active +- entity_ids an array with entity ids that the events in the schedule should + effect (can also be groups) +- events is an array of objects that describe the different events that is + supported. Read in the events descriptions for more information """ import logging -from datetime import datetime, timedelta import json -from pprint import pprint import importlib -from homeassistant.components import switch, sun +from homeassistant.components import switch from homeassistant.loader import get_component # The domain of your component. Should be equal to the name of your component @@ -17,27 +28,33 @@ DOMAIN = 'scheduler' # List of component names (string) your component depends upon # If you are setting up a group but not using a group for anything, # don't depend on group -DEPENDENCIES = ['sun'] +DEPENDENCIES = [] _LOGGER = logging.getLogger(__name__) _SCHEDULE_FILE = 'schedule.json' -_RULE_TYPE_CACHE = {} # pylint: disable=unused-argument def setup(hass, config): - """ Register services or listen for events that your component needs. """ + """ Create the schedules """ def setup_schedule(description): + """ setup a schedule based on the description """ - for rule in description['rules']: - rule_init = get_component('scheduler.{}'.format(rule['type'])) + schedule = Schedule(hass, description['id'], + name=description['name'], + description=description['description'], + entity_ids=description['entity_ids'], + days=description['days']) - if rule_init is None: - _LOGGER.error('Error loading schedule rule %s', rule['type']) - return False + for event_description in description['events']: + event_type = \ + get_component('scheduler.{}'.format(event_description['type'])) + event = event_type.create(schedule, event_description) + schedule.add_event(event) + schedule.schedule() return True with open(hass.get_config_path(_SCHEDULE_FILE)) as schedule_file: @@ -48,3 +65,44 @@ def setup(hass, config): return False return True + + +class Schedule(object): + """ A Schedule """ + def __init__(self, hass, schedule_id, name=None, description=None, + entity_ids=None, days=None): + + self.hass = hass + + self.schedule_id = schedule_id + self.name = name + self.description = description + + self.entity_ids = entity_ids or [] + + self.days = days or [0, 1, 2, 3, 4, 5, 6] + + self._events = [] + + def add_event(self, event): + """ Add a event to the schedule """ + self._events.append(event) + + def schedule(self): + """ Schedule all the events in the schdule """ + for event in self._events: + event.schedule() + + +class Event(object): + """ The base Event class that the schedule uses """ + def __init__(self, schedule): + self._schedule = schedule + + def schedule(self): + """ Schedule the event """ + pass + + def execute(self): + """ execute the event """ + pass diff --git a/homeassistant/components/scheduler/sun.py b/homeassistant/components/scheduler/sun.py index 6ab66e7a36c..074f2bc0705 100644 --- a/homeassistant/components/scheduler/sun.py +++ b/homeassistant/components/scheduler/sun.py @@ -1,5 +1,7 @@ """asd""" +from homeassistant.components.scheduler import Event -def hej(): - print('wut sun wut') + +def create(schedule, description): + print('creating sun') diff --git a/homeassistant/components/scheduler/time.py b/homeassistant/components/scheduler/time.py index 348f6537bc6..14081c25a5f 100644 --- a/homeassistant/components/scheduler/time.py +++ b/homeassistant/components/scheduler/time.py @@ -1,5 +1,74 @@ -"""asd""" +""" +An event in the scheduler component that will call the service +every specified day at the time specified. +A time event need to have the type 'time', which service to call and at +which time. + +{ + "type": "time", + "service": "switch.turn_off", + "time": "22:00" +} + +""" + +from datetime import datetime, timedelta +import logging + +from homeassistant.components.scheduler import Event + +_LOGGER = logging.getLogger(__name__) -def hej(): - print('wut wut') +def create(schedule, description): + """ Create a TimeEvent based on the description """ + + service = description['service'] + (hour, minute) = [int(x) for x in description['time'].split(':')] + + return TimeEvent(schedule, service, hour, minute) + + +class TimeEvent(Event): + """ The time event that the scheduler uses """ + + def __init__(self, schedule, service, hour, minute): + Event.__init__(self, schedule) + + (self._domain, self._service) = service.split('.') + + self._hour = hour + self._minute = minute + + print(self._domain, self._service) + + def schedule(self): + """ Schedule this event so that it will be called """ + + next_time = datetime.now().replace(hour=self._hour, + minute=self._minute, + second=0, microsecond=0) + + # Calculate the next time the event should be executed. + # That is the next day that the schedule is configured to run + while next_time < datetime.now() or \ + next_time.weekday() not in self._schedule.days: + + next_time = next_time + timedelta(days=1) + + # pylint: disable=unused-argument + def execute(now): + """ Call the execute method """ + self.execute() + + self._schedule.hass.track_point_in_time(execute, next_time) + + _LOGGER.info('point in time scheduled at {} for {}' + .format(next_time, "")) + + def execute(self): + """ Call the service """ + # data = {ATTR_ENTITY_ID: self._schedule.entity_ids} + # self._schedule.hass.call_service(self._domain, self._service, data) + print("executoing time", self._domain, self._service) + self.schedule()