def test_mock_py_config_context_with_timers(self): with mock_py_config_context(): save_timers((((1, 2), (3, 4)), )) assert restore_timers() == (((1, 2), (3, 4)), ) save_timers((((5, 6), (7, 8)), )) assert restore_timers() == (((5, 6), (7, 8)), )
async def get_form(server, reader, writer, querystring, body): from times_utils import restore_timers, pformat_timers, get_active_days timers = pformat_timers(restore_timers()) active_days = get_active_days() del restore_timers del pformat_timers del get_active_days del sys.modules['times_utils'] gc.collect() context = { 'timers': timers, 'on_selected': 'selected' if server.context.power_timer_active else '', 'off_selected': '' if server.context.power_timer_active else 'selected', } for day_no in range(7): context['d%i' % day_no] = 'checked' if day_no in active_days else '' from template import render await server.send_html_page( writer, filename='webswitch.html', content_iterator=render(filename='http_set_timer.html', context=context, content_iterator=None), )
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 test_sort_timers(self): # send not ordered timer list: # 21:30 - 22:45 # 07:00 - 08:00 response = await self.get_request( request_line=(b"GET" b" /set_timer/submit/" b"?timers=21%3A30+-+22%3A45%0D%0A07%3A00+-+08%3A00" b" HTTP/1.1")) assert response == b'HTTP/1.0 303 Moved\r\nLocation: /set_timer/form/\r\n\r\n' assert self.web_server.message == 'Timers saved and deactivated.' timers = pformat_timers(restore_timers()) assert timers == '07:00 - 08:00\n21:30 - 22:45'
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.')
async def test_set_timer(self): # Set timer: response = await self.get_request(request_line=( b"GET" b" /set_timer/submit/" b"?timers=07%3A00+-+08%3A00%0D%0A20%3A00+-+22%3A35" b"&d0=on&d1=on&d2=on&d3=on&d4=on" # only MO-FR, not SA+SU b"&active=on" b" HTTP/1.1")) assert response == b'HTTP/1.0 303 Moved\r\nLocation: /set_timer/form/\r\n\r\n' assert self.web_server.message == 'Timers saved and activated.' timers = pformat_timers(restore_timers()) assert timers == '07:00 - 08:00\n20:00 - 22:35' active_days = tuple(get_active_days()) assert active_days == (0, 1, 2, 3, 4) # only MO-FR, not SA+SU assert get_dict_from_rtc() == {'active': True, 'manual-type': None} assert active_today() is True # Request the form: response = await self.get_request( request_line=b"GET /set_timer/form/ HTTP/1.1") self.assert_response_parts( response, parts=('HTTP/1.0 200 OK', '<html>', '<title>network name-04030201 - OFF</title>', '<p>Power switch state: <strong>OFF</strong></p>', '<p><strong>Switch on in 6 h at 20:00 h.</strong></p>', '<p>Timers saved and activated.</p>', '<textarea name="timers" rows="6" cols="13">07:00 - 08:00', '20:00 - 22:35</textarea>', '<option value="on" selected>ON</option>', 'RAM total: 1.95 KB, used: 0.98 KB, free: 0.98 KB<br>', 'Server local time: 2019-05-01 13:12:11', '</html>')) assert self.web_server.message == 'Timers saved and activated.'
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)
'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) if __name__ == '__main__': print('Run tests on device...') import sys sys.modules.clear() import gc gc.collect() timers = restore_timers() active_days = tuple(get_active_days()) try: run_all_times_utils_tests() finally: if timers is not None: save_timers(timers) if active_days is None: save_active_days(active_days) print('OK\n')
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.')
def update_power_timer(context): """ Sets relay switch on/off on schedule and manual override. Called from tasks.periodical_tasks() """ gc.collect() if __debug__: print('Update power timer:', utime.time()) from times_utils import restore_timers context.power_timer_timers = restore_timers() del restore_timers del sys.modules['times_utils'] gc.collect() from rtc import get_dict_from_rtc rtc_memory_dict = get_dict_from_rtc() context.power_timer_active = rtc_memory_dict.get( constants.POWER_TIMER_ACTIVE_KEY, True) manual_overwrite = rtc_memory_dict.get(constants.RTC_KEY_MANUAL_OVERWRITE, 0) current_state = rtc_memory_dict.get( constants.RTC_KEY_MANUAL_OVERWRITE_TYPE) if __debug__ and current_state: print('manual overwrite:', repr(current_state)) del rtc_memory_dict del sys.modules['rtc'] gc.collect() context.power_timer_today_active = active_today() if context.power_timer_active and context.power_timer_today_active: if __debug__: print('Update power timer state') from times_utils import get_current_timer last_timer_epoch, turn_on, context.power_timer_next_timer_epoch = get_current_timer( context) del get_current_timer del sys.modules['times_utils'] gc.collect() context.power_timer_turn_on = turn_on if last_timer_epoch is None: if __debug__: print('No timer scheduled') else: if current_state is None or manual_overwrite < last_timer_epoch: if __debug__: print('Set state from timer') # Note: # The current power state is the **opposite** of the next one. # In other words: If the **next** timer will "turn on" (==True) then we are # now in a "OFF" phase ;) current_state = not turn_on if current_state is None: if __debug__: print('No timer to scheduled and no manual overwrite') elif current_state: if __debug__: print('Switch on') Pins.relay.on() else: if __debug__: print('Switch off') Pins.relay.off() gc.collect()