Exemple #1
0
class SchedulerTest1(unittest.TestCase):
    def setUp(self):
        self.groups = Groups("groups.json")
        lat = 56.045000000000002
        lon = 12.718400000000001

        self.s = Scheduler(lat=lat, lon=lon, groups=self.groups)
        self.s.parse_conf_file("schedule.json")  # Prepped schedule with 11 schedule items and 2 rules

    def test1_start_at_midnight(self):
        """ This is a normal situation, where the schedules are reloaded when it's 00:00/a new day
        """
        no = self.s.new_day("mo")
        self.assertEqual(no, 9)  # 9 items expected for Monday

        # Start at midnight
        item = self.s.get_first()
        self.assertEqual(item["time"], "06:00")  # Monday, first item should be 06:00
        self.assertEqual(item["scenario"], "Plant lights on")

        # Start later in the day, search for exact match in time
        item = self.s.get_first("08:10")
        self.assertEqual(item["time"], "08:10")
        self.assertEqual(item["device"], "2222-2222")

    def test2_start_in_evening(self):
        """ Start later in the day. The search is inexact, expecting a schedule item at a later point-in-time
        """
        self.s.new_day("mo")

        item = self.s.get_first("21:35")
        self.assertEqual(item["time"], "21:40")
        item = self.s.get_next()
        self.assertEqual(item["time"], "22:00")

    def test2b_start_with_errors(self):
        """ Start with invalid days. 0 scheduled items expected as result
        """
        no = self.s.new_day("xx")  # Needs to be "mo", "tu", etc.
        self.assertEqual(no, 0)

        no = self.s.new_day(9)  # Needs to be 1..7
        self.assertEqual(no, 0)

    def test3_new_day(self):
        """ Normal shift of day.
        """
        self.s.new_day("mo")

        self.s.schedules.list_full_day()

        # Get last item for Monday
        item = self.s.get_first("23:00")
        self.assertEqual(item["time"], "23:00")

        # This should fail, there are no more items
        self.assertIsNone(self.s.get_next())

        # It's midnight, let's shift over to a new day
        no = self.s.new_day("tu")
        self.assertEqual(no, 11)  # 11 items expected for Tuesday
        #self.s.schedules.list_full_day()

        item = self.s.get_next()
        self.assertEqual(item["time"], "06:00")  # Tuesday, first item should be 06:00

        item = self.s.get_next()
        self.assertEqual(item["time"], "06:00")  # Tuesday, second item should also be 06:00

    def test3b_new_day(self):
        """ Normal shift of day.
        """
        self.s.new_day("mo")

        # Get last item for Monday
        item = self.s.get_first("23:00")
        self.assertEqual(item["time"], "23:00")

        # This should fail, there are no more items
        self.assertIsNone(self.s.get_next())

        # It's midnight, let's shift over to a new day
        no = self.s.new_day("tu")
        self.assertEqual(no, 11)  # 11 items expected for Tuesday

        item = self.s.get_next()
        self.assertEqual(item["time"], "06:00")  # Tuesday, first item should be 06:00

        item = self.s.get_next()
        self.assertEqual(item["time"], "06:00")  # Tuesday, second item should also be 06:00

    def test4_execute_rule(self):
        """ Locate and execute a rule, use day index to locate Monday
        """
        self.s.new_day(1)
        item = self.s.get_first("00:00")
        self.assertEqual(item["time"], "06:00")

        r = item["rule"]

        self.assertFalse(r.execute())

    def test5_get_current_weekday(self):
        """ Get current weekday. Cannot be asserted
        """
        dl, d = self.s.get_weekday()
        print ("dl={}, d={}".format(dl, d))

    def test6_list_items(self):
        """ List all items for this day
        """
        self.s.new_day("mo")
        item = self.s.schedules.list_full_day(now="04:01")  # Before first
        item = self.s.schedules.list_full_day(now="09:00")  # In between
        item = self.s.schedules.list_full_day(now="23:01")  # After last
        item = self.s.schedules.list_full_day()             # Cannot be validated easily
        self.s.new_day("fr")
        item = self.s.schedules.list_full_day(now="00:00")  # Should contain 2 sunset/sunrise based times

    def test7_double_assign(self):
        self.weekday = weekday = all_days[2-1]
        self.assertEqual(self.weekday, "tu")
        self.assertEqual(weekday, "tu")


    def test8a_random_time(self):
        self.s.new_day("mo")
        item = self.s.get_first("00:00")
        print("random times")

        for i in range(1, 10):
            time = self.s.schedules.schedules[0].get_random_time("08:00", 5)
            self.assertIsNotNone(time)
            print("{}".format(time))

    def test8b_random_time(self):
        self.s.random_minutes = 10
        self.s.new_day("mo")

        item = self.s.get_first("00:00")
        item = self.s.schedules.list_full_day(now="08:00")


    def tearDown(self):
        pass
Exemple #2
0
class AgoScheduler(agoclient.AgoApp):

    def __init__(self):
        agoclient.AgoApp.__init__(self)
        self.weekdayno = None
        self.weekday = None
        self.nexttime = None
        self.next_item = None
        self.groups = None
        self.scheduler = None
        self.scenario_controllerUUID = None
        self.mapfile = None
        self.print_schedule = False

    def event_handler(self, subject, content):
        """event handler - Processes incoming events and looks if they are of a relevant kind
                         - For now, it's only time event that are of interest
        """
        self.log.trace("event_handler start")

        if "event.environment.timechanged" in subject:
            self.log.trace("subject=%s content=%s", subject, content)

            js = json.loads(str(content).replace("u\'", '\"').replace("\'", '\"'))  # TODO: check if replacement is necessary
            t_now = self.scheduler.now()
            self.log.trace("now={} - waiting for {}".format(t_now, self.nexttime))

            if self.nexttime is not None and t_now == self.nexttime:
                while True:  # Loop through all items with same time
                    self.log.debug("Action to be triggered: {}".format(self.next_item))
                    try:
                        self.send_message(self.next_item)
                    except NameError as e:
                        self.log.error("Oops, could not send message. Msg={}".format(e))
                    self.next_item = self.scheduler.get_next()
                    if self.next_item is None:
                        self.nexttime = None
                        break
                    if t_now != self.next_item["time"]:
                        self.nexttime = self.next_item["time"]
                        break
                if self.nexttime is not None:
                    self.log.debug("Next item scheduled for {}".format(self.nexttime))
                else:
                    self.log.debug("No more scheduled items for today")

            if self.weekdayno != int(js["weekday"]):
                # TODO: Check config if a new schedule file is to be loaded
                self.weekdayno = int(js["weekday"])
                self.new_day(self.weekdayno)
                self.next_item = self.scheduler.get_first("00:00")
                if self.next_item is not None:
                    self.nexttime = self.next_item["time"]
                else:
                    self.nexttime = None
                self.log.debug("First item scheduled for {}".format(self.nexttime))

        # TODO: Event handler for "reload" event

    def device_msg(self, uuid, action, level=None):
        content = {"uuid": uuid,  # TODO: Check unicode encoded strings
                   "action": action}
        if action == "setlevel":
            content["level"] = level
        elif action == "fade":
            pass

        if action in {"on", "off", "setlevel"}:
            msg = "event.device.statechanged"

            self.log.debug("About to set device content={}".format(content))
            self.connection.send_message(msg, content)

    def send_message(self, item):
        self.log.debug(("In send_message. item={}".format(item)))
        if item["device"] is not None:
            if item["action"] in {"on", "off"}:
                self.device_msg(item["device"], item["action"])
            elif item["action"] in {"setlevel"}:
                self.device_msg(item["device"], item["action"], item["level"])
            # todo: aDD ACTION SPECIFIC FIELDS

        if item["scenario"] is not None:
            content = {"uuid": item["scenario"],
                       "command": "run"}
            self.log.debug("About to execute scenario content={}".format(content))
            self.connection.send_message(None, content)

        if item["group"] is not None:
            self.log.info(("About to send message to device group {}".format(item["group"])))
            grp = self.groups.find(item["group"])
            if grp is not None:
                for dev in grp.devices:
                    if dev is not None:
                        if item["action"] in {"on", "off"}:
                            self.device_msg(dev, item["action"])
                        elif item["action"] in {"setlevel"}:
                            self.device_msg(dev, item["action"], item["level"])

    def get_scenario_controller_uuid(self):
        """Get UUID for the scenario controller"""
        inventory = self.connection.get_inventory()

        for uuid in inventory['devices']:
            if inventory['devices'][uuid]['devicetype'] == 'scenariocontroller':
                self.log.debug("Found Scenario Controller {}".format(uuid))
                return uuid

        return None

    def new_day(self, weekdayno):
        """ Load schedules for a new day

        @param weekdayno: 1-7
        @return: nothing
        """
        self.weekday = weekday = all_days[weekdayno - 1]
        self.log.trace("new_day() weekday={}".format(weekday))
        no_activities = self.scheduler.new_day(weekday)
        self.next_item = self.scheduler.get_first("00:00")
        self.weekdayno = weekdayno

        if self.print_schedule:
            self.scheduler.schedules.list_full_day()
        self.log.info("New day: {}. Loaded {} schedule items for today.".format(weekday, no_activities))

    def setup_app(self):
        self.log.trace("setup_app start")
        self.connection.add_event_handler(self.event_handler)
        app = "scheduler"

        self.scenario_controllerUUID = self.get_scenario_controller_uuid()
        if self.scenario_controllerUUID is None:
            self.log.error("Scenario Controller not found.")

        mapfile = self.get_config_option('schedule', None, section=app, app=app)
        self.print_schedule = self.get_config_option('print_daily_schedule', "Yes", section=app, app=app) == "Yes"
        self.log.info("Print daily schedule? {}".format(self.print_schedule))

        if mapfile is None:
            self.mapfile = None
            self.log.error("No Schedule file found in config file. Idling.")  # TODO: Follow up - set flag to avoid processing!
        else:
            self.mapfile = agoclient.config.CONFDIR + '/conf.d/' + mapfile
            self.log.info("Reading schedules from {}".format(self.mapfile))

        self.groups = Groups(agoclient.config.CONFDIR + '/conf.d/' + 'groups.json')  # TODO: Change to proper file

        lat = self.get_config_option("lat", "47.07", "system")
        lon = self.get_config_option("lon", "15.42", "system")

        self.log.info("Getting position. lat={} lon={}".format(lat, lon))
        self.scheduler = Scheduler(lat=float(lat), lon=float(lon), log=self.log, groups=self.groups)

        self.scheduler.parse_conf_file(self.mapfile)
        dl, day_no = self.scheduler.get_weekday()
        self.scheduler.weekday = dl
        self.log.trace("day_no={}".format(day_no))
        self.new_day(day_no)

        self.next_item = self.scheduler.get_first(self.scheduler.now())
        if self.next_item is not None:
            self.nexttime = self.next_item["time"]
        else:
            self.nexttime = None
        self.log.debug("First item scheduled for {}".format(self.nexttime))
Exemple #3
0
class SchedulerTest2(unittest.TestCase):
    def setUp(self):
        self.groups = Groups("groups.json")
        self.s = Scheduler(12.7, 56.6, self.groups)  # Coords for south of Sweden
        self.s.parse_conf_file("winter.json")  # Prepped schedule with 9 schedule items and 2 rules

    def test1_start_at_midnight(self):
        """ This is a normal situation, where the schedules are reloaded when it's 00:00/a new day
        """
        no = self.s.new_day("mo")
        self.assertEqual(no, 7)  # 7 items expected for Monday

        # Start at midnight
        item = self.s.get_first()
        self.assertEqual(item["time"], "06:15")  # Monday, first item should be 06:15
        self.assertEqual(item["scenario"], "ce52eea8-8889-4dc6-b578-7d049b5a64ab")   # Plant lights on"

        # Start later in the day, search for exact match in time
        item = self.s.get_first("08:10")
        self.assertEqual(item["time"], "15:00")
        self.assertEqual(item["group"], "5555-5555")

    def test2_start_in_evening(self):
        """ Start later in the day. The search is inexact, expecting a schedule item at a later point-in-time
        """
        self.s.new_day("mo")

        item = self.s.get_first("21:35")
        self.assertEqual(item["time"], "21:45")
        item = self.s.get_next()
        self.assertEqual(item["time"], "21:59")

    def test2b_start_with_errors(self):
        """ Start with invalid days. 0 scheduled items expected as result
        """
        no = self.s.new_day("xx")  # Needs to be "mo", "tu", etc.
        self.assertEqual(no, 0)

        no = self.s.new_day(9)  # Needs to be 1..7
        self.assertEqual(no, 0)

    def test3_new_day(self):
        """ Normal shift of day.
        """
        self.s.new_day("mo")

        # Get last item for Monday
        item = self.s.get_first("22:00")
        self.assertEqual(item["time"], "22:00")

        # This should fail, there are no more items
        self.assertIsNone(self.s.get_next())

        # It's midnight, let's shift over to a new day
        no = self.s.new_day("tu")
        self.assertEqual(no, 10)  # 10 items expected for Tuesday

        item = self.s.get_next()
        self.assertEqual(item["time"], "06:00")  # Tuesday, first item should be 06:00

        item = self.s.get_next()
        self.assertEqual(item["time"], "06:00")  # Tuesday, second item should also be 06:00

    def test3_new_day2(self):
        """ Normal shift of day.
        """
        self.s.new_day("we")

        # Get last item for Wednesday
        item = self.s.get_first("22:00")
        self.assertEqual(item["time"], "22:00")

        # This should fail, there are no more items
        self.assertIsNone(self.s.get_next())

        # It's midnight, let's shift over to a new day
        no = self.s.new_day("th")
        self.assertEqual(no, 7)  # 10 items expected for Thursday

        item = self.s.get_next()
        self.assertEqual(item["time"], "06:25")  # Thursday, first item should be 06:25

        item = self.s.get_next()
        self.assertEqual(item["time"], "15:00")  # Thursday, second item should also be 15:00

    def test4_list(self):
        """ List full day, incl sunrise/sunset calculation"""
        self.s.schedules.list_full_day()

    def test5_sunrise(self):
        """ Test sunrise calculation"""
        now = datetime.now()
        then = now.replace(year=2017, month=02, day=14)
        self.assertEqual(self.s.calc_sunrise(then), "07:40")

        then = now.replace(year=2017, month=07, day=22)
        self.assertEqual(self.s.calc_sunrise(then), "03:51")

    def tearDown(self):
        pass