def trigger(self, *args, **kwargs): commands = kwargs.get(Attribute.COMMAND, None) sources = kwargs.get(Attribute.SOURCE, None) mapped = kwargs.get(Attribute.MAPPED, None) secs = kwargs.get(Attribute.SECS, None) start = kwargs.get(Attribute.START, None) end = kwargs.get(Attribute.END, None) if not isinstance(commands, tuple): commands = (commands, ) if not isinstance(sources, tuple): sources = (sources, ) for command in commands: for source in sources: m = None if not mapped: m = command else: m = mapped self._triggers.update({(command, source): {Attribute.SECS: secs, Attribute.MAPPED: m, Attribute.START: CronTimer.to_cron(start), Attribute.END: CronTimer.to_cron(end), }})
def restriction(self, *args, **kwargs): states = kwargs.get(Attribute.STATE, None) sources = kwargs.get(Attribute.SOURCE, None) targets = kwargs.get(Attribute.TARGET, None) start = kwargs.get(Attribute.START, None) end = kwargs.get(Attribute.END, None) if not isinstance(states, tuple): states = (states, ) if not isinstance(sources, tuple): sources = (sources, ) if not isinstance(targets, tuple): targets = (targets, ) for state in states: for source in sources: for target in targets: self._restrictions.update({ (state, source, target): { Attribute.START: CronTimer.to_cron(start), Attribute.END: CronTimer.to_cron(end), } }) self._logger.debug("{name} add restriction for {state} from {source} on {target}".format( name=self.name, state=state, target=target, source=source.name if source else None, ));
def _recalc(self): self.obs.horizon = self._horizon # midnight = self.tz.localize(local_time.replace(hour=12, minute=0, second=0, microsecond=0, tzinfo=None), # is_dst=None) # self.obs.date = midnight.astimezone(pytz.utc) self.obs.date = self.local_time.astimezone(pytz.utc) prev_rising = self._utc2tz( self.obs.previous_rising(self.sun, use_center=True).datetime()) prev_setting = self._utc2tz( self.obs.previous_setting(self.sun, use_center=True).datetime()) self._sunrise = self._utc2tz( self.obs.next_rising(self.sun, use_center=True).datetime()) self._sunset = self._utc2tz( self.obs.next_setting(self.sun, use_center=True).datetime()) self._sunrise = self._sunrise.replace(second=0, microsecond=0) self._sunset = self._sunset.replace(second=0, microsecond=0) self._logger.info( '{name} Location sunset: {sunset} sunrise: {sunrise}'.format( name=self.name, sunset=str(self._sunset), sunrise=str(self._sunrise), )) time_now = self.local_time.replace(second=0, microsecond=0) if (self._sunrise > self._sunset and self._sunset != time_now) or \ self._sunrise == time_now: if self.state != Command.LIGHT: self.light() else: self._logger.info( "{name} Location did not flip state as it already is light" .format(name=self.name)) else: if self.state != Command.DARK: self.dark() else: self._logger.info( "{name} Location did not flip state as it already is dark". format(name=self.name)) # Setup trigger for next transition self._sunset_timer.interval( *CronTimer.to_cron(strftime("%H:%M:%S", self.sunset.timetuple()))) self._sunset_timer.action(self._recalc) self._sunset_timer.start() self._sunrise_timer.interval( *CronTimer.to_cron(strftime("%H:%M:%S", self.sunrise.timetuple()))) self._sunrise_timer.action(self._recalc) self._sunrise_timer.start()
def _recalc(self): self.obs.horizon = self._horizon # midnight = self.tz.localize(local_time.replace(hour=12, minute=0, second=0, microsecond=0, tzinfo=None), # is_dst=None) # self.obs.date = midnight.astimezone(pytz.utc) self.obs.date = self.local_time.astimezone(pytz.utc) prev_rising = self._utc2tz( self.obs.previous_rising(self.sun, use_center=True).datetime()) prev_setting = self._utc2tz( self.obs.previous_setting(self.sun, use_center=True).datetime()) self._sunrise = self._utc2tz( self.obs.next_rising(self.sun, use_center=True).datetime()) self._sunset = self._utc2tz( self.obs.next_setting(self.sun, use_center=True).datetime()) self._sunrise = self._sunrise.replace(second=0, microsecond=0) self._sunset = self._sunset.replace(second=0, microsecond=0) self._logger.info('{name} Location sunset: {sunset} sunrise: {sunrise}'.format( name=self.name, sunset=str(self._sunset), sunrise=str(self._sunrise), )) time_now = self.local_time.replace(second=0, microsecond=0) if (self._sunrise > self._sunset and self._sunset != time_now) or \ self._sunrise == time_now: if self.state <> Command.LIGHT: self.light() else: self._logger.info("{name} Location did not flip state as it already is light".format( name=self.name )) else: if self.state <> Command.DARK: self.dark() else: self._logger.info("{name} Location did not flip state as it already is dark".format( name=self.name )) # Setup trigger for next transition self._sunset_timer.interval(*CronTimer.to_cron(strftime("%H:%M:%S", self.sunset.timetuple()))) self._sunset_timer.action(self._recalc) self._sunset_timer.start() self._sunrise_timer.interval(*CronTimer.to_cron(strftime("%H:%M:%S", self.sunrise.timetuple()))) self._sunrise_timer.action(self._recalc) self._sunrise_timer.start()
def __init__(self, latitude, longitude, tz='US/Eastern', mode=MODE.STANDARD, is_dst=True, *args, **kwargs): super(Location, self).__init__(*args, **kwargs) self.obs = ephem.Observer() self.obs.lat = latitude self.obs.long = longitude self.tz = pytz.timezone(tz) self.is_dst = is_dst self.sun = ephem.Sun(self.obs) self._horizon = mode self._sunset_timer = CronTimer() self._sunrise_timer = CronTimer() self._local_time = None self._recalc()
def ignore(self, *args, **kwargs): commands = kwargs.get('command', None) sources = kwargs.get('source', None) start = kwargs.get(Attribute.START, None) end = kwargs.get(Attribute.END, None) if not isinstance(commands, tuple): commands = (commands, ) if not isinstance(sources, tuple): sources = (sources, ) for command in commands: for source in sources: self._ignores.update({ (command, source): { Attribute.START: CronTimer.to_cron(start), Attribute.END: CronTimer.to_cron(end), } }) self._logger.debug("{name} add ignore for {command} from {source}".format( name=self.name, command=command, source=source.name if source else None, ));
def test_datetime_to_cron(self): cron = CronTimer.to_cron('5:34pm') self.assertEqual(cron[0], 0) self.assertEqual(cron[1], 34) self.assertEqual(cron[2], 17) self.assertEqual(cron[4], AllMatch()) cron = CronTimer.to_cron('6:52 pm') self.assertEqual(cron[0], 0) self.assertEqual(cron[1], 52) self.assertEqual(cron[2], 18) self.assertEqual(cron[4], AllMatch()) cron = CronTimer.to_cron('5:13 AM') self.assertEqual(cron[0], 0) self.assertEqual(cron[1], 13) self.assertEqual(cron[2], 5) self.assertEqual(cron[4], AllMatch()) cron = CronTimer.to_cron('5:13:34 AM') self.assertEqual(cron[0], 34) self.assertEqual(cron[1], 13) self.assertEqual(cron[2], 5) self.assertEqual(cron[4], AllMatch()) cron = CronTimer.to_cron('3:14') self.assertEqual(cron[0], 0) self.assertEqual(cron[1], 14) self.assertEqual(cron[2], 3) self.assertEqual(cron[4], AllMatch()) cron = CronTimer.to_cron('18:42') self.assertEqual(cron[0], 0) self.assertEqual(cron[1], 42) self.assertEqual(cron[2], 18) self.assertEqual(cron[4], AllMatch())
class CronTimerTests(TestCase): def setUp(self): self.called = False self.ct = CronTimer() def test_2_sec_callback(self): m = Mock() t = datetime.now().timetuple()[5] t += 2 self.ct.interval(secs=t) self.ct.action(m.action, ()) self.ct.start() time.sleep(4) self.ct.stop() self.assertEqual(m.action.called, True, "Callback was not called") def test_2_sec_intervals(self): self.called = False t = datetime.now().timetuple()[5] self.ct.interval(secs=(t + 2 % 60, t + 4 % 60)) self.ct.action(self.callback, ()) self.ct.start() time.sleep(3) self.assertEqual(self.called, True, "Callback was not called - 1st iteration") self.called = False time.sleep(3) self.assertEqual(self.called, True, "Callback was not called - 2nd iteration") self.ct.stop() def test_datetime_to_cron(self): cron = CronTimer.to_cron('5:34pm') self.assertEqual(cron[0], 0) self.assertEqual(cron[1], 34) self.assertEqual(cron[2], 17) self.assertEqual(cron[4], AllMatch()) cron = CronTimer.to_cron('6:52 pm') self.assertEqual(cron[0], 0) self.assertEqual(cron[1], 52) self.assertEqual(cron[2], 18) self.assertEqual(cron[4], AllMatch()) cron = CronTimer.to_cron('5:13 AM') self.assertEqual(cron[0], 0) self.assertEqual(cron[1], 13) self.assertEqual(cron[2], 5) self.assertEqual(cron[4], AllMatch()) cron = CronTimer.to_cron('5:13:34 AM') self.assertEqual(cron[0], 34) self.assertEqual(cron[1], 13) self.assertEqual(cron[2], 5) self.assertEqual(cron[4], AllMatch()) cron = CronTimer.to_cron('3:14') self.assertEqual(cron[0], 0) self.assertEqual(cron[1], 14) self.assertEqual(cron[2], 3) self.assertEqual(cron[4], AllMatch()) cron = CronTimer.to_cron('18:42') self.assertEqual(cron[0], 0) self.assertEqual(cron[1], 42) self.assertEqual(cron[2], 18) self.assertEqual(cron[4], AllMatch()) def callback(self): self.called = True
def setUp(self): self.called = False self.ct = CronTimer()
def test_timefuncs_out_range_flip(self): start = CronTimer.to_cron("10:03pm") end = CronTimer.to_cron("4:55am") now = CronTimer.to_cron("2:54pm") self.assertFalse(crontime_in_range(now, start, end))
def test_timefuncs_in_range(self): start = CronTimer.to_cron("4:52pm") end = CronTimer.to_cron("4:55pm") now = CronTimer.to_cron("4:54pm") self.assertTrue(crontime_in_range(now, start, end))
def test_timefuncs_out_range2(self): start = CronTimer.to_cron("12:01am") end = CronTimer.to_cron("8:00am") now = CronTimer.to_cron("5:54pm") self.assertFalse(crontime_in_range(now, start, end))
class Location(StateDevice): STATES = [State.LIGHT, State.DARK] COMMANDS = [Command.LIGHT, Command.DARK, Command.INITIAL, Command.TOGGLE, Command.PREVIOUS] class MODE(): STANDARD = '0' CIVIL = '-6' NAUTICAL = '-12' ASTRONOMICAL = '-18' def __init__(self, latitude, longitude, tz='US/Eastern', mode=MODE.STANDARD, is_dst=True, *args, **kwargs): super(Location, self).__init__(*args, **kwargs) self.obs = ephem.Observer() self.obs.lat = latitude self.obs.long = longitude self.tz = pytz.timezone(tz) self.is_dst = is_dst self.sun = ephem.Sun(self.obs) self._horizon = mode self._sunset_timer = CronTimer() self._sunrise_timer = CronTimer() self._local_time = None self._recalc() @property def mode(self): return self._horizon @mode.setter def mode(self, value): self._horizon = value self._recalc() @property def local_time(self): if not self._local_time: return self.tz.localize(datetime.now(), is_dst=self.is_dst) else: return self.tz.localize(self._local_time, is_dst=self.is_dst) @local_time.setter def local_time(self, value): self._local_time = value self._recalc() def _recalc(self): self.obs.horizon = self._horizon # midnight = self.tz.localize(local_time.replace(hour=12, minute=0, second=0, microsecond=0, tzinfo=None), # is_dst=None) # self.obs.date = midnight.astimezone(pytz.utc) self.obs.date = self.local_time.astimezone(pytz.utc) prev_rising = self._utc2tz( self.obs.previous_rising(self.sun, use_center=True).datetime()) prev_setting = self._utc2tz( self.obs.previous_setting(self.sun, use_center=True).datetime()) self._sunrise = self._utc2tz( self.obs.next_rising(self.sun, use_center=True).datetime()) self._sunset = self._utc2tz( self.obs.next_setting(self.sun, use_center=True).datetime()) self._sunrise = self._sunrise.replace(second=0, microsecond=0) self._sunset = self._sunset.replace(second=0, microsecond=0) self._logger.info('{name} Location sunset: {sunset} sunrise: {sunrise}'.format( name=self.name, sunset=str(self._sunset), sunrise=str(self._sunrise), )) time_now = self.local_time.replace(second=0, microsecond=0) if (self._sunrise > self._sunset and self._sunset != time_now) or \ self._sunrise == time_now: # self.state = State.LIGHT # self._set_state(State.LIGHT, self.state, self) if self.state <> Command.LIGHT: # self.command(Command.LIGHT, source=self) self.light() else: # self.state = State.DARK # self._set_state(State.DARK, self.state, self) if self.state <> Command.DARK: # self.command(Command.DARK, source=self) self.dark() # Setup trigger for next transition sunset_t = self._sunset_timer # sunset_t.stop() sunset_t.interval(*CronTimer.to_cron(strftime("%H:%M:%S", self.sunset.timetuple()))) sunset_t.action(self._recalc) sunset_t.start() # self._sunrise_timer.stop() self._sunrise_timer.interval(*CronTimer.to_cron(strftime("%H:%M:%S", self.sunrise.timetuple()))) self._sunrise_timer.action(self._recalc, ()) self._sunrise_timer.start() @property def sunset(self): return self._sunset @sunset.setter def sunset(self, value): self._sunset = value self._recalc() return self._sunset @property def sunrise(self): return self._sunrise @sunrise.setter def sunrise(self, value): self._sunrise = value self._recalc() return self._sunrise def _utc2tz(self, value): return pytz.utc.localize(value, is_dst=self.is_dst).astimezone(self.tz) def _command_state_map(self, command, *args, **kwargs): (m_state, m_command) = super(Location, self)._command_state_map(command, *args, **kwargs) if m_command == Command.OFF: m_state = State.DARK elif m_command == Command.ON: m_state = State.LIGHT return (m_state, m_command)
class Location(StateDevice): STATES = [State.LIGHT, State.DARK] COMMANDS = [ Command.LIGHT, Command.DARK, Command.INITIAL, Command.TOGGLE, Command.PREVIOUS ] class MODE(): STANDARD = '0' CIVIL = '-6' NAUTICAL = '-12' ASTRONOMICAL = '-18' def __init__(self, latitude, longitude, tz='US/Eastern', mode=MODE.STANDARD, is_dst=True, *args, **kwargs): super(Location, self).__init__(*args, **kwargs) self.obs = ephem.Observer() self.obs.lat = latitude self.obs.long = longitude self.tz = pytz.timezone(tz) self.is_dst = is_dst self.sun = ephem.Sun(self.obs) self._horizon = mode self._sunset_timer = CronTimer() self._sunrise_timer = CronTimer() self._local_time = None self._recalc() @property def mode(self): return self._horizon @mode.setter def mode(self, value): self._horizon = value self._recalc() @property def local_time(self): if not self._local_time: return self.tz.localize(datetime.now(), is_dst=self.is_dst) else: return self.tz.localize(self._local_time, is_dst=self.is_dst) @local_time.setter def local_time(self, value): self._local_time = value self._recalc() def _recalc(self): self.obs.horizon = self._horizon # midnight = self.tz.localize(local_time.replace(hour=12, minute=0, second=0, microsecond=0, tzinfo=None), # is_dst=None) # self.obs.date = midnight.astimezone(pytz.utc) self.obs.date = self.local_time.astimezone(pytz.utc) prev_rising = self._utc2tz( self.obs.previous_rising(self.sun, use_center=True).datetime()) prev_setting = self._utc2tz( self.obs.previous_setting(self.sun, use_center=True).datetime()) self._sunrise = self._utc2tz( self.obs.next_rising(self.sun, use_center=True).datetime()) self._sunset = self._utc2tz( self.obs.next_setting(self.sun, use_center=True).datetime()) self._sunrise = self._sunrise.replace(second=0, microsecond=0) self._sunset = self._sunset.replace(second=0, microsecond=0) self._logger.info( '{name} Location sunset: {sunset} sunrise: {sunrise}'.format( name=self.name, sunset=str(self._sunset), sunrise=str(self._sunrise), )) time_now = self.local_time.replace(second=0, microsecond=0) if (self._sunrise > self._sunset and self._sunset != time_now) or \ self._sunrise == time_now: if self.state != Command.LIGHT: self.light() else: self._logger.info( "{name} Location did not flip state as it already is light" .format(name=self.name)) else: if self.state != Command.DARK: self.dark() else: self._logger.info( "{name} Location did not flip state as it already is dark". format(name=self.name)) # Setup trigger for next transition self._sunset_timer.interval( *CronTimer.to_cron(strftime("%H:%M:%S", self.sunset.timetuple()))) self._sunset_timer.action(self._recalc) self._sunset_timer.start() self._sunrise_timer.interval( *CronTimer.to_cron(strftime("%H:%M:%S", self.sunrise.timetuple()))) self._sunrise_timer.action(self._recalc) self._sunrise_timer.start() @property def sunset(self): return self._sunset @sunset.setter def sunset(self, value): self._sunset = value self._recalc() return self._sunset @property def sunrise(self): return self._sunrise @sunrise.setter def sunrise(self, value): self._sunrise = value self._recalc() return self._sunrise def _utc2tz(self, value): return pytz.utc.localize(value, is_dst=self.is_dst).astimezone(self.tz) def _command_state_map(self, command, *args, **kwargs): (m_state, m_command) = super(Location, self)._command_state_map(command, *args, **kwargs) if m_command == Command.OFF: m_state = State.DARK elif m_command == Command.ON: m_state = State.LIGHT return (m_state, m_command)
def time(self, *args, **kwargs): # time, command times = kwargs.get('time', None) command = kwargs.get('command', State.UNKNOWN) if times: if not isinstance( times, tuple) or (isinstance(times, tuple) and isinstance(times[0], int)): times = (times, ) for time in times: timer = CronTimer() if isinstance(time, tuple): timer.interval(*time) else: timer.interval(*CronTimer.to_cron(time)) timer.action(self.command, (command)) timer.start() self._times.append((command, timer))