async def periodical_tasks(context): """ Periodical tasks, started from webswitch.WebServer.feed_watchdog """ if context.ntp_last_sync_epoch > 0: # A NTP sync was successful in the past # Sets relay switch on/off on schedule and manual override: from power_timer import update_power_timer update_power_timer(context) del update_power_timer del sys.modules['power_timer'] gc.collect() # Ensure that the device is connected to the WiFi: from wifi import ensure_connection is_connected = ensure_connection(context) del ensure_connection del sys.modules['wifi'] gc.collect() if is_connected: # Sync the RTC time via NTP: from ntp import ntp_sync ntp_sync(context) del ntp_sync del sys.modules['ntp'] gc.collect()
def test_update_relay_switch_without_timers(self): with mock_py_config_context(): assert restore_timers() == () update_power_timer(self.context) print(get_info_text(self.context)) self.assertEqual(get_current_timer(self.context), (None, None, None))
async def get_request(self, request_line): update_power_timer(self.context) reader = asynctest.mock.Mock(StreamReader) writer = StreamWriter() reader.readline.return_value = request_line await self.web_server.request_handler(reader, writer) return writer.get_response()
def assert_current_timer(reference, context): # Load timers: context.power_timer_timers = None update_power_timer(context) previous_epoch, turn_on, next_epoch = get_current_timer(context) assert next_epoch is not None, 'No timers?!?' text = '%i %s %02i:%02i %s -> %i %s %02i:%02i %s -> %s' % ( (previous_epoch, ) + epoch_info(previous_epoch) + (next_epoch, ) + epoch_info(next_epoch) + ('ON' if turn_on else 'OFF', )) assert text == reference
async def feed_watchdog(self): """ Start some periodical tasks and feed the watchdog """ while True: gc.collect() from power_timer import update_power_timer if update_power_timer(self.context) is not True: from reset import ResetDevice ResetDevice(reason='Update power timer error').reset() del update_power_timer del sys.modules['power_timer'] gc.collect() from ntp import ntp_sync if ntp_sync(self.context) is not True: from reset import ResetDevice ResetDevice(reason='NTP sync error').reset() del ntp_sync del sys.modules['ntp'] gc.collect() self.context.watchdog.feed() gc.collect() await uasyncio.sleep(constants.WATCHDOG_TIMEOUT)
def test_update_relay_switch_in_1min(self): machine.RTC().deinit() # start time from 1.1.2000 00:00 with mock_py_config_context(): save_timers((((0, 1), (1, 0)), )) save_active_days((0, 1, 2, 3, 4, 5, 6)) assert machine.RTC().datetime((2000, 1, 1, 6, 0, 0, 0, 0)) assert localtime_isoformat(sep=' ') == '2000-01-01 00:00:00' timers = restore_timers() assert pformat_timers(timers) == '00:01 - 01:00' assert list(iter_times(timers)) == [(True, (0, 1, 0)), (False, (1, 0, 0))] update_power_timer(self.context) self.assertEqual(get_info_text(self.context), 'Switch on in 1 min at 00:01 h.')
def test_update_relay_switch_today_not_active(self): machine.RTC().deinit() # start time from 1.1.2000 00:00 with mock_py_config_context(): save_timers((((1, 0), (2, 0)), )) save_active_days((0, 1, 2, 3, 4, 6)) # <- day 5 is missing assert machine.RTC().datetime((2000, 1, 1, 5, 0, 0, 0, 0)) assert localtime_isoformat(sep=' ') == '2000-01-01 00:00:00' update_power_timer(self.context) print(get_info_text(self.context)) assert active_today() is False assert self.context.power_timer_today_active is False self.assertEqual(get_info_text(self.context), 'Power timer is not active today.')
async def _switch(server, writer, turn_on): """ We only save the 'manual overwrite' information to RTC RAM and set the 'message'. The update_relay_switch() will turn on/off the relay switch """ server.message = 'power %s' % ('on' if turn_on else 'off') from rtc import update_rtc_dict update_rtc_dict({ constants.RTC_KEY_MANUAL_OVERWRITE: utime.time(), constants.RTC_KEY_MANUAL_OVERWRITE_TYPE: turn_on }) from power_timer import update_power_timer update_power_timer(context=server.context) from http_utils import send_redirect await send_redirect(writer)
def test_get_current_timer(self): with mock_py_config_context(): save_timers(( ((0, 0), (0, 1)), ((0, 2), (0, 3)), )) update_power_timer(self.context) rtc = machine.RTC() rtc.datetime((2000, 1, 1, 5, 0, 0, 0, 0)) # 00:00 assert get_current_timer(self.context) == (0, False, 60) rtc.datetime((2000, 1, 1, 5, 0, 1, 0, 0)) # 00:01 assert get_current_timer(self.context) == (60, True, 120) rtc.datetime((2000, 1, 1, 5, 0, 2, 0, 0)) # 00:02 assert get_current_timer(self.context) == (120, False, 180) rtc.datetime((2000, 1, 1, 5, 0, 3, 0, 0)) # 00:03 -> next timer is on next day! assert get_current_timer(self.context) == (180, True, 86400)
def run_all_times_utils_tests(): print('test parse_timers()...', end=' ') results = tuple( parse_timers(''' 0:00 - 1:00 1:23 - 4:56 19:00 - 20:00 22:01 - 22:30 23:12 - 23:59 ''')) assert results == (((0, 0), (1, 0)), ((1, 23), (4, 56)), ((19, 0), (20, 0)), ((22, 1), (22, 30)), ((23, 12), (23, 59))), results print('OK\n') print('test not existing "timers.txt"...', end=' ') try: uos.remove('_config_timers.py') except OSError: pass results = tuple(restore_timers()) assert results == (), results print('OK\n') print('test not existing "timer_days.txt"...', end=' ') try: uos.remove('_config_timer_days.py') except OSError: pass results = tuple(get_active_days()) assert results == (0, 1, 2, 3, 4, 5, 6), results print('OK\n') print('test save_active_days()...', end=' ') save_active_days(active_days=(0, 1, 2, 3, 4)) results = tuple(get_active_days()) assert results == (0, 1, 2, 3, 4), results print('OK\n') context = Context() save_timers([]) results = tuple(restore_timers()) assert results == (), results update_power_timer(context) assert get_current_timer(context) == (None, None, None) save_timers([ ((6, 0), (7, 0)), ]) results = tuple(restore_timers()) assert results == (((6, 0), (7, 0)), ), results rtc = machine.RTC() rtc.datetime( (2000, 1, 2, 6, 0, 0, 0, 0)) # set RTC time: 2.1.2000 00:00:00 assert_current_timer( # Turn ON at 06:00 '25200 -17 h 07:00 2000-01-01T07:00:00 -> 108000 6 h 06:00 2000-01-02T06:00:00 -> ON', context) rtc.datetime( (2000, 1, 2, 6, 5, 59, 59, 0)) # set RTC time: 2.1.2000 05:59:59 assert_current_timer( # Turn ON at 06:00 '25200 -22 h 07:00 2000-01-01T07:00:00 -> 108000 1 sec 06:00 2000-01-02T06:00:00 -> ON', context) rtc.datetime( (2000, 1, 2, 6, 6, 0, 0, 0)) # set RTC time: 2.1.2000 06:00:00 assert_current_timer( # Turn ON at 06:00 '108000 0 sec 06:00 2000-01-02T06:00:00 -> 111600 60 min 07:00 2000-01-02T07:00:00 -> OFF', context) rtc.datetime( (2000, 1, 2, 6, 6, 59, 59, 0)) # set RTC time: 2.1.2000 06:59:59 assert_current_timer( # Turn OFF at 07:00 '108000 -59 min 06:00 2000-01-02T06:00:00 -> 111600 1 sec 07:00 2000-01-02T07:00:00 -> OFF', context) rtc.datetime( (2000, 1, 2, 6, 7, 0, 0, 0)) # set RTC time: 2.1.2000 07:00:00 assert_current_timer( # Turn ON next day at 06:00 '111600 0 sec 07:00 2000-01-02T07:00:00 -> 194400 23 h 06:00 2000-01-03T06:00:00 -> ON', context) save_timers([ ((6, 0), (7, 0)), ((19, 30), (22, 30)), ]) rtc.datetime( (2000, 1, 2, 6, 0, 0, 0, 0)) # set RTC time: 2.1.2000 00:00:00 assert_current_timer( # Turn ON at 06:00 '81000 -90 min 22:30 2000-01-01T22:30:00 -> 108000 6 h 06:00 2000-01-02T06:00:00 -> ON', context) rtc.datetime( (2000, 1, 2, 6, 7, 0, 1, 0)) # set RTC time: 2.1.2000 07:00:01 assert_current_timer( # Turn ON at 19:30 '111600 -1 sec 07:00 2000-01-02T07:00:00 -> 156600 12 h 19:30 2000-01-02T19:30:00 -> ON', context) rtc.datetime( (2000, 1, 2, 6, 20, 12, 0, 0)) # set RTC time: 2.1.2000 20:12:00 assert_current_timer( # Turn OFF at 22:30 '156600 -42 min 19:30 2000-01-02T19:30:00 -> 167400 2 h 22:30 2000-01-02T22:30:00 -> OFF', context) rtc.datetime( (2000, 1, 2, 6, 22, 30, 1, 0)) # set RTC time: 2.1.2000 22:30:01 assert_current_timer( # Turn ON next day at 06:00 '167400 -1 sec 22:30 2000-01-02T22:30:00 -> 194400 7 h 06:00 2000-01-03T06:00:00 -> ON', context)
def test_relay_switch_timers_and_overwrite(self): rtc = machine.RTC() with mock_py_config_context(): save_timers((((10, 0), (20, 0)), )) timers = restore_timers() assert pformat_timers(timers) == '10:00 - 20:00' assert list(iter_times(timers)) == [(True, (10, 0, 0)), (False, (20, 0, 0))] save_active_days((0, 1, 2, 3, 4, 5, 6)) assert get_active_days() == (0, 1, 2, 3, 4, 5, 6) rtc.datetime( (2000, 1, 2, 6, 0, 0, 0, 0)) # set RTC time: 2.1.2000 00:00:00 assert localtime_isoformat(sep=' ') == '2000-01-02 00:00:00' assert_current_timer( # Turn ON at 10:00 '72000 -4 h 20:00 2000-01-01T20:00:00' ' -> 122400 10 h 10:00 2000-01-02T10:00:00 -> ON', self.context) # init relay in state 'OFF' Pins.relay.off() assert Pins.relay.state == 'OFF' # No manual overwrite and ON timer not yet reached -> OFF and turn ON at 10:00 update_power_timer(self.context) assert active_today() is True assert self.context.power_timer_today_active is True assert Pins.relay.state == 'OFF' self.assertEqual(get_info_text(self.context), 'Switch on in 10 h at 10:00 h.') # 2000-01-01 09:59:59 - timer not yet reached rtc.datetime((2000, 1, 2, 6, 9, 59, 59, 0)) update_power_timer(self.context) assert Pins.relay.state == 'OFF' self.assertEqual(get_info_text(self.context), 'Switch on in 1 sec at 10:00 h.') # 2000-01-01 10:00:00 - turn ON by timer rtc.datetime((2000, 1, 2, 6, 10, 0, 0, 0)) update_power_timer(self.context) assert Pins.relay.state == 'ON' self.assertEqual(get_info_text(self.context), 'Switch off in 10 h at 20:00 h.') # 2000-01-01 20:00:00 - turn OFF by timer rtc.datetime((2000, 1, 2, 6, 20, 0, 0, 0)) update_power_timer(self.context) assert Pins.relay.state == 'OFF' self.assertEqual(get_info_text(self.context), 'Switch on in 14 h at 10:00 h.') # 2000-01-02 09:00:00 - manual overwrite rtc.datetime((2000, 1, 2, 6, 9, 0, 0, 0)) update_rtc_dict({ constants.RTC_KEY_MANUAL_OVERWRITE: utime.time(), constants.RTC_KEY_MANUAL_OVERWRITE_TYPE: True # -> turn ON }) update_power_timer(self.context) assert Pins.relay.state == 'ON' self.assertEqual(get_info_text(self.context), 'Switch on in 60 min at 10:00 h.') # 2000-01-02 09:59:59 - manual overwrite is still active rtc.datetime((2000, 1, 2, 6, 9, 59, 59, 0)) update_power_timer(self.context) assert Pins.relay.state == 'ON' self.assertEqual(get_info_text(self.context), 'Switch on in 1 sec at 10:00 h.') # 2000-01-02 12:00:00 - Normal timer mode, still ON rtc.datetime((2000, 1, 2, 6, 12, 0, 0, 0)) update_power_timer(self.context) assert Pins.relay.state == 'ON' self.assertEqual(get_info_text(self.context), 'Switch off in 8 h at 20:00 h.') # manual overwrite update_rtc_dict({ constants.RTC_KEY_MANUAL_OVERWRITE: utime.time(), constants.RTC_KEY_MANUAL_OVERWRITE_TYPE: False # -> turn OFF }) update_power_timer(self.context) assert Pins.relay.state == 'OFF' self.assertEqual(get_info_text(self.context), 'Switch off in 8 h at 20:00 h.') # 2000-01-02 20:00:00 - Normal timer mode -> switch OFF rtc.datetime((2000, 1, 2, 6, 20, 0, 0, 0)) update_power_timer(self.context) assert Pins.relay.state == 'OFF' self.assertEqual(get_info_text(self.context), 'Switch on in 14 h at 10:00 h.') # manual overwrite update_rtc_dict({ constants.RTC_KEY_MANUAL_OVERWRITE: utime.time(), constants.RTC_KEY_MANUAL_OVERWRITE_TYPE: True # -> turn ON }) update_power_timer(self.context) assert Pins.relay.state == 'ON' self.assertEqual(get_info_text(self.context), 'Switch on in 14 h at 10:00 h.') # 2000-01-01 09:59:59 - timer not yet reached rtc.datetime((2000, 1, 2, 6, 9, 59, 59, 0)) update_power_timer(self.context) assert Pins.relay.state == 'ON' self.assertEqual(get_info_text(self.context), 'Switch on in 1 sec at 10:00 h.')
async def get_submit(server, reader, writer, querystring, body): """ Note: POST request doesn't work: https://forum.micropython.org/viewtopic.php?f=2&t=7432 """ from urllib_parse import request_query2dict data = request_query2dict(querystring) del request_query2dict gc.collect() import times_utils try: timers = tuple(times_utils.parse_timers(data['timers'])) gc.collect() except ValueError as e: gc.collect() server.message = 'Timers error: %s' % e else: print('Save timers:', timers) # Save timers to flash: from config_files import save_py_config save_py_config(module_name=constants.TIMERS_PY_CFG_NAME, value=timers) save_py_config(module_name=constants.ACTIVE_DAYS_PY_CFG_NAME, value=tuple( [no for no in range(7) if 'd%i' % no in data])) del save_py_config del sys.modules['config_files'] gc.collect() power_timer_active = data.get('active') == 'on' del data # can be collected gc.collect() from rtc import update_rtc_dict update_rtc_dict( data={ constants.POWER_TIMER_ACTIVE_KEY: power_timer_active, # # Deactivate manual overwrite, so that timers are used: constants.RTC_KEY_MANUAL_OVERWRITE_TYPE: None, }) del update_rtc_dict del sys.modules['rtc'] gc.collect() # Update power timer: if power_timer_active: server.message = 'Timers saved and activated.' else: server.message = 'Timers saved and deactivated.' # Force set values by update_power_timer(): server.context.power_timer_active = None server.context.power_timer_today_active = None from power_timer import update_power_timer update_power_timer(context=server.context) gc.collect() from http_utils import send_redirect await send_redirect(writer, url='/set_timer/form/')