def test_one_minute_schedule(self): now_offset = 1577836800 # 2020 minute = 60 fakesleep.reset(seconds=now_offset) SchedulingController.TIMEZONE = 'Europe/Brussels' schedule = ScheduleDTO(id=1, name='schedule', start=0 * minute, repeat='* * * * *', duration=None, end=now_offset + 60 * minute, action='GROUP_ACTION', arguments=1, status='ACTIVE') schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertFalse(schedule.is_due) schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertEqual(now_offset + 1 * minute, schedule.next_execution) time.sleep(1 * minute) self.assertTrue(schedule.is_due) schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertEqual(now_offset + 2 * minute, schedule.next_execution) time.sleep(1 * minute) self.assertTrue(schedule.is_due) schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertEqual(now_offset + 3 * minute, schedule.next_execution)
def test_midnight_crossover(self): now_offset = 1615939080 # 16/03/21 23:58 minute = 60 fakesleep.reset(seconds=now_offset ) # Tricks the system to be in the time we specified SchedulingController.TIMEZONE = 'Europe/Brussels' schedule = ScheduleDTO(id=1, name='schedule', start=0 * minute, repeat='* * * * *', duration=None, end=now_offset + 10 * minute, action='GROUP_ACTION', arguments=1, status='ACTIVE') schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertFalse(schedule.is_due) schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertEqual(now_offset + 1 * minute, schedule.next_execution) time.sleep(1 * minute) self.assertTrue(schedule.is_due) schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertEqual(now_offset + 2 * minute, schedule.next_execution) time.sleep(1 * minute) self.assertTrue(schedule.is_due) schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertEqual(now_offset + 3 * minute, schedule.next_execution)
def __get_controller(self, callback=None, action_timeout=60): """ Get a UserController using FILE. """ if callback == None: self.__actions = [] callback = self.__actions.append controller = SchedulingController(SchedulingControllerTest.FILE, callback, action_timeout) controller.start() return controller
def _get_controller(self): SetUpTestInjections(scheduling_db=self._db, scheduling_db_lock=Lock(), gateway_api=GatewayApi(), user_controller=None, maintenance_controller=None, message_client=None, configuration_controller=None) controller = SchedulingController() SetUpTestInjections(scheduling_controller=controller) controller.set_webinterface(WebInterface()) return controller
def test_schedule_is_due(self): now_offset = 1577836800 # 2020-01-01 offset_2018 = 1514764800 # 2018-01-01 minute = 60 hour = 60 * minute fakesleep.reset(seconds=offset_2018) SchedulingController.TIMEZONE = 'Europe/Brussels' schedule = ScheduleDTO(id=1, name='schedule', start=offset_2018, repeat='0 * * * *', duration=None, end=now_offset + 24 * hour, action='GROUP_ACTION', arguments=1, status='ACTIVE') schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertFalse(schedule.is_due) schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertEqual(SchedulingController.NO_NTP_LOWER_LIMIT + 1 * hour, schedule.next_execution) time.sleep(1 * hour) self.assertFalse(schedule.is_due) # Date is before 2019 schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertEqual(SchedulingController.NO_NTP_LOWER_LIMIT + 1 * hour, schedule.next_execution) fakesleep.reset(seconds=now_offset) self.assertFalse(schedule.is_due) # Time jump is ignored schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertEqual(now_offset + 1 * hour, schedule.next_execution) time.sleep(1 * hour) self.assertTrue(schedule.is_due) schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertEqual(now_offset + 2 * hour, schedule.next_execution)
def _get_controller(): def _do_group_action(group_action_id): SchedulingControllerTest.RETURN_DATA[ 'do_group_action'] = group_action_id return {} def _do_basic_action(action_type, action_number): SchedulingControllerTest.RETURN_DATA['do_basic_action'] = ( action_type, action_number) return {} gateway_api = Mock() gateway_api.get_timezone = lambda: 'UTC' gateway_api.do_basic_action = _do_basic_action group_action_controller = Mock() group_action_controller.do_group_action = _do_group_action SetUpTestInjections(gateway_api=gateway_api, user_controller=None, maintenance_controller=None, message_client=None, configuration_controller=None, thermostat_controller=None, ventilation_controller=Mock(VentilationController), shutter_controller=Mock(), output_controller=Mock(), room_controller=Mock(), input_controller=Mock(), sensor_controller=Mock(), pulse_counter_controller=Mock(), frontpanel_controller=Mock(), group_action_controller=group_action_controller, module_controller=Mock()) controller = SchedulingController() SetUpTestInjections(scheduling_controller=controller) controller.set_webinterface(WebInterface()) return controller
def test_edge_cases_cron(self): now_offset = 1616371020 # Date and time: Sunday, March 21, 2021 11:57:00 PM GMT minute = 60 SchedulingController.TIMEZONE = 'Europe/Brussels' fakesleep.reset(seconds=now_offset) SchedulingController.TIMEZONE = 'Europe/Brussels' schedule = ScheduleDTO( id=1, name='schedule', start=200, # Thursday, January 1, 1970 1:03:20 AM repeat='* * * * *', # every minute duration=None, end=now_offset + 10 * minute, # for 10 minuted action='GROUP_ACTION', arguments=1, status='ACTIVE') # Should be 1616371020 + 60 = 1616371080 schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertFalse(schedule.is_due) # Should still be 1616371020 + 60 = 1616371080 for i in range(1, 11): schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertEqual(now_offset + i * minute, schedule.next_execution) time.sleep(minute) self.assertTrue(schedule.is_due) # now testing end of month behaviour now_offset = 1617235020 # 2021-03-31 23:57:00 fakesleep.reset(seconds=now_offset) schedule.end = now_offset + 10 * minute # Update when the schedule should end for i in range(1, 11): schedule.next_execution = SchedulingController._get_next_execution( schedule) self.assertEqual(now_offset + i * minute, schedule.next_execution) time.sleep(minute) self.assertTrue(schedule.is_due)
def main(): """ Main function. """ config = ConfigParser() config.read(constants.get_config_file()) defaults = { 'username': config.get('OpenMotics', 'cloud_user'), 'password': config.get('OpenMotics', 'cloud_pass') } controller_serial_port = config.get('OpenMotics', 'controller_serial') passthrough_serial_port = config.get('OpenMotics', 'passthrough_serial') power_serial_port = config.get('OpenMotics', 'power_serial') gateway_uuid = config.get('OpenMotics', 'uuid') config_lock = threading.Lock() user_controller = UserController(constants.get_config_database_file(), config_lock, defaults, 3600) config_controller = ConfigurationController( constants.get_config_database_file(), config_lock) led_service = LedService() controller_serial = Serial(controller_serial_port, 115200) power_serial = RS485(Serial(power_serial_port, 115200, timeout=None)) master_communicator = MasterCommunicator(controller_serial) if passthrough_serial_port: passthrough_serial = Serial(passthrough_serial_port, 115200) passthrough_service = PassthroughService(master_communicator, passthrough_serial) passthrough_service.start() master_communicator.start( ) # A running master_communicator is required for the startup of services below power_controller = PowerController(constants.get_power_database_file()) power_communicator = PowerCommunicator(power_serial, power_controller) gateway_api = GatewayApi(master_communicator, power_communicator, power_controller) scheduling_controller = SchedulingController( constants.get_scheduling_database_file(), config_lock, gateway_api) maintenance_service = MaintenanceService( gateway_api, constants.get_ssl_private_key_file(), constants.get_ssl_certificate_file()) web_interface = WebInterface(user_controller, gateway_api, maintenance_service, led_service.in_authorized_mode, config_controller, scheduling_controller) scheduling_controller.set_webinterface(web_interface) plugin_controller = PluginController(web_interface, config_controller) web_interface.set_plugin_controller(plugin_controller) gateway_api.set_plugin_controller(plugin_controller) # Metrics metrics_cache_controller = MetricsCacheController( constants.get_metrics_database_file(), threading.Lock()) metrics_collector = MetricsCollector(gateway_api) metrics_controller = MetricsController(plugin_controller, metrics_collector, metrics_cache_controller, config_controller, gateway_uuid) metrics_collector.set_controllers(metrics_controller, plugin_controller) metrics_collector.set_plugin_intervals(plugin_controller.metric_intervals) metrics_controller.add_receiver(metrics_controller.receiver) metrics_controller.add_receiver(web_interface.distribute_metric) plugin_controller.set_metrics_controller(metrics_controller) web_interface.set_metrics_collector(metrics_collector) web_interface.set_metrics_controller(metrics_controller) web_service = WebService(web_interface, config_controller) def _on_output(*args, **kwargs): metrics_collector.on_output(*args, **kwargs) gateway_api.on_outputs(*args, **kwargs) def _on_input(*args, **kwargs): metrics_collector.on_input(*args, **kwargs) gateway_api.on_inputs(*args, **kwargs) master_communicator.register_consumer( BackgroundConsumer(master_api.output_list(), 0, _on_output, True)) master_communicator.register_consumer( BackgroundConsumer(master_api.input_list(), 0, _on_input)) power_communicator.start() plugin_controller.start_plugins() metrics_controller.start() scheduling_controller.start() metrics_collector.start() web_service.start() led_thread = threading.Thread(target=led_driver, args=(led_service, master_communicator, power_communicator)) led_thread.setName("Serial led driver thread") led_thread.daemon = True led_thread.start() def stop(signum, frame): """ This function is called on SIGTERM. """ _ = signum, frame sys.stderr.write("Shutting down") web_service.stop() metrics_collector.stop() metrics_controller.stop() plugin_controller.stop() signal(SIGTERM, stop)
def _get_controller(self): gateway_api = GatewayApi() controller = SchedulingController(self._db, Lock(), gateway_api) controller.set_webinterface(WebInterface(None, gateway_api, None, None, None, controller)) return controller
def _get_controller(self): gateway_api = GatewayApi() controller = SchedulingController(self._db, Lock(), gateway_api) controller.set_webinterface( WebInterface(None, gateway_api, None, None, None, controller)) return controller
def main(): """ Main function. """ log('Starting service...') config = ConfigParser() config.read(constants.get_config_file()) defaults = {'username': config.get('OpenMotics', 'cloud_user'), 'password': config.get('OpenMotics', 'cloud_pass')} controller_serial_port = config.get('OpenMotics', 'controller_serial') passthrough_serial_port = config.get('OpenMotics', 'passthrough_serial') power_serial_port = config.get('OpenMotics', 'power_serial') gateway_uuid = config.get('OpenMotics', 'uuid') config_lock = threading.Lock() user_controller = UserController(constants.get_config_database_file(), config_lock, defaults, 3600) config_controller = ConfigurationController(constants.get_config_database_file(), config_lock) dbus_service = DBusService('openmotics_service') controller_serial = Serial(controller_serial_port, 115200) power_serial = RS485(Serial(power_serial_port, 115200, timeout=None)) master_communicator = MasterCommunicator(controller_serial) eeprom_controller = EepromController( EepromFile(master_communicator), EepromExtension(constants.get_eeprom_extension_database_file()) ) if passthrough_serial_port: passthrough_serial = Serial(passthrough_serial_port, 115200) passthrough_service = PassthroughService(master_communicator, passthrough_serial) passthrough_service.start() power_controller = PowerController(constants.get_power_database_file()) power_communicator = PowerCommunicator(power_serial, power_controller) pulse_controller = PulseCounterController( constants.get_pulse_counter_database_file(), master_communicator, eeprom_controller ) observer = Observer(master_communicator, dbus_service) gateway_api = GatewayApi(master_communicator, power_communicator, power_controller, eeprom_controller, pulse_controller, dbus_service, observer, config_controller) observer.set_gateway_api(gateway_api) scheduling_controller = SchedulingController(constants.get_scheduling_database_file(), config_lock, gateway_api) maintenance_service = MaintenanceService(gateway_api, constants.get_ssl_private_key_file(), constants.get_ssl_certificate_file()) web_interface = WebInterface(user_controller, gateway_api, maintenance_service, dbus_service, config_controller, scheduling_controller) scheduling_controller.set_webinterface(web_interface) # Plugins plugin_controller = PluginController(web_interface, config_controller) web_interface.set_plugin_controller(plugin_controller) gateway_api.set_plugin_controller(plugin_controller) # Metrics metrics_cache_controller = MetricsCacheController(constants.get_metrics_database_file(), threading.Lock()) metrics_collector = MetricsCollector(gateway_api, pulse_controller) metrics_controller = MetricsController(plugin_controller, metrics_collector, metrics_cache_controller, config_controller, gateway_uuid) metrics_collector.set_controllers(metrics_controller, plugin_controller) metrics_controller.add_receiver(metrics_controller.receiver) metrics_controller.add_receiver(web_interface.distribute_metric) plugin_controller.set_metrics_controller(metrics_controller) plugin_controller.set_metrics_collector(metrics_collector) web_interface.set_metrics_collector(metrics_collector) web_interface.set_metrics_controller(metrics_controller) web_service = WebService(web_interface, config_controller) plugin_controller.set_webservice(web_service) observer.subscribe_master(Observer.MasterEvents.INPUT_TRIGGER, metrics_collector.on_input) observer.subscribe_master(Observer.MasterEvents.INPUT_TRIGGER, plugin_controller.process_input_status) observer.subscribe_master(Observer.MasterEvents.ON_OUTPUTS, metrics_collector.on_output) observer.subscribe_master(Observer.MasterEvents.ON_OUTPUTS, plugin_controller.process_output_status) observer.subscribe_master(Observer.MasterEvents.ON_SHUTTER_UPDATE, plugin_controller.process_shutter_status) observer.subscribe_events(web_interface.process_observer_event) led_thread = threading.Thread(target=led_driver, args=(dbus_service, master_communicator, power_communicator)) led_thread.setName("Serial led driver thread") led_thread.daemon = True led_thread.start() master_communicator.start() observer.start() power_communicator.start() metrics_controller.start() scheduling_controller.start() metrics_collector.start() web_service.start() gateway_api.start() plugin_controller.start() signal_request = {'stop': False} def stop(signum, frame): """ This function is called on SIGTERM. """ _ = signum, frame log('Stopping service...') web_service.stop() metrics_collector.stop() metrics_controller.stop() plugin_controller.stop() log('Stopping service... Done') signal_request['stop'] = True signal(SIGTERM, stop) log('Starting service... Done') while not signal_request['stop']: time.sleep(1)