def test_master_output_event(self): events = [] def _on_event(master_event): events.append(master_event) classic = get_classic_controller_dummy() pubsub = get_pubsub() pubsub.subscribe_master_events(PubSub.MasterTopics.OUTPUT, _on_event) classic._output_config = { 0: OutputDTO(id=0), 1: OutputDTO(id=1), 2: OutputDTO(id=2, room=3) } pubsub._publish_all_events() events = [] classic._on_master_output_event({'outputs': [(0, 0), (2, 5)]}) pubsub._publish_all_events() assert [ MasterEvent('OUTPUT_STATUS', { 'id': 0, 'status': True, 'dimmer': 0 }), MasterEvent('OUTPUT_STATUS', { 'id': 1, 'status': False }), MasterEvent('OUTPUT_STATUS', { 'id': 2, 'status': True, 'dimmer': 5 }) ] == events
def test_eeprom_events(self): """ Test read. """ controller = get_eeprom_controller_dummy({0: bytearray([0] * 256), 1: bytearray([0] * 2) + bytearray(b'hello') + bytearray([0] * 249)}) model = controller.read(Model1, 0) self.assertEqual(0, model.id) self.assertEqual('hello' + '\x00' * 95, model.name) events = [] def handle_events(master_event): events.append(master_event) get_pubsub().subscribe_master_events(PubSub.MasterTopics.EEPROM, handle_events) controller.invalidate_cache() get_pubsub()._publish_all_events() self.assertEqual([ MasterEvent(MasterEvent.Types.EEPROM_CHANGE, {}) ], events) controller.activate() get_pubsub()._publish_all_events() self.assertEqual([ MasterEvent(MasterEvent.Types.EEPROM_CHANGE, {}), MasterEvent(MasterEvent.Types.EEPROM_CHANGE, {}) ], events)
def test_master_output_event(self): events = [] def _on_event(master_event): events.append(master_event) self.pubsub.subscribe_master_events(PubSub.MasterTopics.OUTPUT, _on_event) events = [] self.controller._handle_event({'type': 0, 'device_nr': 0, 'action': 0, 'data': bytearray([255, 0, 0, 0])}) self.controller._handle_event({'type': 0, 'device_nr': 2, 'action': 1, 'data': bytearray([100, 2, 0xff, 0xfe])}) self.pubsub._publish_all_events() self.assertEqual([MasterEvent(MasterEvent.Types.OUTPUT_STATUS, {'id': 0, 'status': False, 'dimmer': 255, 'ctimer': 0}), MasterEvent(MasterEvent.Types.OUTPUT_STATUS, {'id': 2, 'status': True, 'dimmer': 100, 'ctimer': 65534})], events)
def test_subscribe_input_events(self): consumer_list = [] def new_consumer(*args): consumer = BackgroundConsumer(*args) consumer_list.append(consumer) return consumer subscriber = mock.Mock() with mock.patch.object(gateway.hal.master_controller_core, 'BackgroundConsumer', side_effect=new_consumer) as new_consumer: controller = MasterCoreController() self.pubsub.subscribe_master_events(PubSub.MasterTopics.INPUT, subscriber.callback) new_consumer.assert_called() event_data = {'type': 1, 'action': 1, 'device_nr': 2, 'data': {}} with mock.patch.object(Queue, 'get', return_value=event_data): consumer_list[0].deliver() self.pubsub._publish_all_events() expected_event = MasterEvent.deserialize({'type': 'INPUT_CHANGE', 'data': {'id': 2, 'status': True, 'location': {'room_id': 255}}}) subscriber.callback.assert_called_with(expected_event)
def test_subscribe_input_events(self): consumer_list = [] def new_consumer(*args): consumer = BackgroundConsumer(*args) consumer_list.append(consumer) return consumer subscriber = mock.Mock() with mock.patch.object(gateway.hal.master_controller_classic, 'BackgroundConsumer', side_effect=new_consumer) as new_consumer: controller = get_classic_controller_dummy() pubsub = get_pubsub() controller._register_version_depending_background_consumers() controller._input_config = {1: InputDTO(id=1)} # TODO: cleanup pubsub.subscribe_master_events(PubSub.MasterTopics.INPUT, subscriber.callback) new_consumer.assert_called() consumer_list[-2].deliver({'input': 1}) pubsub._publish_all_events() try: consumer_list[-2]._consume() except: pass # Just ensure it has at least consumed once expected_event = MasterEvent.deserialize({'type': 'INPUT_CHANGE', 'data': {'id': 1, 'status': True, 'location': {'room_id': 255}}}) subscriber.callback.assert_called_with(expected_event)
def test_refresh(self): from gateway.hal.master_controller_core import MasterCoreEvent, MasterInputState state = MasterInputState(interval=10) core_events = [ MasterCoreEvent({'type': 1, 'action': 1, 'device_nr': 1, 'data': {}}), MasterCoreEvent({'type': 1, 'action': 0, 'device_nr': 2, 'data': {}}), ] with mock.patch.object(time, 'time', return_value=30): for core_event in core_events: state.handle_event(core_event) self.assertTrue(state.should_refresh()) events = state.refresh([0b00000110]) self.assertEqual(1, len(events)) expected_event = MasterEvent(event_type=MasterEvent.Types.INPUT_CHANGE, data={'id': 2, 'status': True, 'location': {'room_id': 255}}) self.assertIn(expected_event, events) self.assertFalse(state.should_refresh()) events = state.refresh([0b00000110]) self.assertEqual([], events) with mock.patch.object(time, 'time', return_value=60): self.assertTrue(state.should_refresh())
def test_master_maintenance_event(self): controller = get_classic_controller_dummy() pubsub = get_pubsub() with mock.patch.object(controller._eeprom_controller, 'invalidate_cache') as invalidate: master_event = MasterEvent(MasterEvent.Types.MAINTENANCE_EXIT, {}) pubsub.publish_master_event(PubSub.MasterTopics.MAINTENANCE, master_event) pubsub._publish_all_events() invalidate.assert_called()
def invalidate_cache(self): # type: () -> None """ Invalidate the cache, this should happen when maintenance mode was used. """ self._eeprom_file.invalidate_cache() self.dirty = True master_event = MasterEvent(MasterEvent.Types.EEPROM_CHANGE, {}) self._pubsub.publish_master_event(PubSub.MasterTopics.EEPROM, master_event)
def test_eeprom_events(self): master_event = MasterEvent(MasterEvent.Types.EEPROM_CHANGE, {}) with mock.patch.object(self.controller, 'invalidate_cache') as handle_event: self.pubsub.publish_master_event(PubSub.MasterTopics.EEPROM, master_event) self.pubsub._publish_all_events() handle_event.assert_called()
def test_master_eeprom_event(self): controller = get_classic_controller_dummy() controller._input_last_updated = 1603178386.0 pubsub = get_pubsub() master_event = MasterEvent(MasterEvent.Types.EEPROM_CHANGE, {}) pubsub.publish_master_event(PubSub.MasterTopics.EEPROM, master_event) pubsub._publish_all_events() assert controller._input_last_updated == 0.0
def test_master_shutter_refresh(self): events = [] def _on_event(master_event): events.append(master_event) self.pubsub.subscribe_master_events(PubSub.MasterTopics.SHUTTER, _on_event) output_status = [{'device_nr': 0, 'status': False, 'dimmer': 0}, {'device_nr': 1, 'status': False, 'dimmer': 0}, {'device_nr': 10, 'status': False, 'dimmer': 0}, {'device_nr': 11, 'status': False, 'dimmer': 0}] with mock.patch.object(gateway.hal.master_controller_core, 'ShutterConfiguration', side_effect=get_core_shutter_dummy), \ mock.patch.object(self.controller, 'load_output_status', return_value=output_status): events = [] self.controller._refresh_shutter_states() self.pubsub._publish_all_events() assert [MasterEvent('SHUTTER_CHANGE', {'id': 1, 'status': 'stopped', 'location': {'room_id': 255}})] == events output_status = [{'device_nr': 0, 'status': False, 'dimmer': 0}, {'device_nr': 1, 'status': True, 'dimmer': 0}, {'device_nr': 10, 'status': True, 'dimmer': 0}, {'device_nr': 11, 'status': False, 'dimmer': 0}] with mock.patch.object(gateway.hal.master_controller_core, 'ShutterConfiguration', side_effect=get_core_shutter_dummy), \ mock.patch.object(self.controller, 'load_output_status', return_value=output_status): events = [] self.controller._refresh_shutter_states() self.pubsub._publish_all_events() assert [MasterEvent('SHUTTER_CHANGE', {'id': 1, 'status': 'going_up', 'location': {'room_id': 255}})] == events output_status = [{'device_nr': 0, 'status': False, 'dimmer': 0}, {'device_nr': 1, 'status': True, 'dimmer': 0}, {'device_nr': 10, 'status': False, 'dimmer': 0}, {'device_nr': 11, 'status': True, 'dimmer': 0}] with mock.patch.object(gateway.hal.master_controller_core, 'ShutterConfiguration', side_effect=get_core_shutter_dummy), \ mock.patch.object(self.controller, 'load_output_status', return_value=output_status): events = [] self.controller._refresh_shutter_states() self.pubsub._publish_all_events() assert [MasterEvent('SHUTTER_CHANGE', {'id': 1, 'status': 'going_down', 'location': {'room_id': 255}})] == events
def activate(self): """ Activate a change in the Eeprom. The master will read the eeprom and adjust the current settings. """ logger.info('EEPROM - Activate') self._master_communicator.do_command(activate_eeprom(), {'eep': 0}) master_event = MasterEvent(MasterEvent.Types.EEPROM_CHANGE, {}) self._pubsub.publish_master_event(PubSub.MasterTopics.EEPROM, master_event)
def test_master_output_event(self): events = [] def _on_event(master_event): events.append(master_event) self.pubsub.subscribe_master_events(PubSub.MasterTopics.OUTPUT, _on_event) events = [] self.controller._handle_event({'type': 0, 'device_nr': 0, 'action': 0, 'data': bytearray([255, 0, 0, 0])}) self.controller._handle_event({'type': 0, 'device_nr': 2, 'action': 1, 'data': bytearray([100, 2, 0xff, 0xfe])}) self.controller._handle_event({'type': 0, 'device_nr': 4, 'action': 2, 'data': bytearray([1, 0, 0, 0])}) self.controller._handle_event({'type': 0, 'device_nr': 6, 'action': 2, 'data': bytearray([0, 0, 0, 0])}) self.pubsub._publish_all_events() self.assertEqual([MasterEvent(MasterEvent.Types.OUTPUT_STATUS, {'state': OutputStateDTO(id=0, status=False, dimmer=255, ctimer=0)}), MasterEvent(MasterEvent.Types.OUTPUT_STATUS, {'state': OutputStateDTO(id=2, status=True, dimmer=100, ctimer=65534)}), MasterEvent(MasterEvent.Types.OUTPUT_STATUS, {'state': OutputStateDTO(id=4, locked=True)}), MasterEvent(MasterEvent.Types.OUTPUT_STATUS, {'state': OutputStateDTO(id=6, locked=False)})], events)
def test_master_shutter_event(self): events = [] def _on_event(master_event): events.append(master_event) self.pubsub.subscribe_master_events(PubSub.MasterTopics.SHUTTER, _on_event) self.controller._output_states = {0: OutputStateDTO(id=0, status=False), 10: OutputStateDTO(id=10, status=False), 11: OutputStateDTO(id=11, status=False)} self.controller._output_shutter_map = {10: 1, 11: 1} self.controller._shutter_status = {1: (False, False)} self.pubsub._publish_all_events() with mock.patch.object(gateway.hal.master_controller_core, 'ShutterConfiguration', side_effect=get_core_shutter_dummy): events = [] self.controller._handle_event({'type': 0, 'device_nr': 10, 'action': 0, 'data': [None, 0, 0, 0]}) self.controller._handle_event({'type': 0, 'device_nr': 11, 'action': 0, 'data': [None, 0, 0, 0]}) self.pubsub._publish_all_events() assert [] == events events = [] self.controller._handle_event({'type': 0, 'device_nr': 10, 'action': 1, 'data': [None, 0, 0, 0]}) self.pubsub._publish_all_events() assert [MasterEvent('SHUTTER_CHANGE', {'id': 1, 'status': 'going_up', 'location': {'room_id': 255}})] == events events = [] self.controller._handle_event({'type': 0, 'device_nr': 11, 'action': 1, 'data': [None, 0, 0, 0]}) self.pubsub._publish_all_events() assert [MasterEvent('SHUTTER_CHANGE', {'id': 1, 'status': 'stopped', 'location': {'room_id': 255}})] == events events = [] self.controller._handle_event({'type': 0, 'device_nr': 10, 'action': 0, 'data': [None, 0, 0, 0]}) self.pubsub._publish_all_events() assert [MasterEvent('SHUTTER_CHANGE', {'id': 1, 'status': 'going_down', 'location': {'room_id': 255}})] == events events = [] self.controller._handle_event({'type': 0, 'device_nr': 11, 'action': 0, 'data': [None, 0, 0, 0]}) self.pubsub._publish_all_events() assert [MasterEvent('SHUTTER_CHANGE', {'id': 1, 'status': 'stopped', 'location': {'room_id': 255}})] == events
def test_master_output_event(self): events = [] def _on_event(master_event): events.append(master_event) classic = get_classic_controller_dummy() pubsub = get_pubsub() pubsub.subscribe_master_events(PubSub.MasterTopics.OUTPUT, _on_event) classic._output_config = {0: OutputDTO(id=0), 1: OutputDTO(id=1), 2: OutputDTO(id=2, room=3)} pubsub._publish_all_events() events = [] classic._on_master_output_event({'outputs': [(0, 0), (2, 5)]}) pubsub._publish_all_events() self.assertEqual(events, [MasterEvent('OUTPUT_STATUS', {'state': OutputStateDTO(id=0, status=True, dimmer=0)}), MasterEvent('OUTPUT_STATUS', {'state': OutputStateDTO(id=1, status=False)}), MasterEvent('OUTPUT_STATUS', {'state': OutputStateDTO(id=2, status=True, dimmer=5)})])
def stop_address_mode(self): # type: () -> None """ Stop address mode. """ if not self.__address_mode: raise Exception("Not in address mode !") self.__address_mode_stop = True if self.__address_thread: self.__address_thread.join() self.__address_thread = None master_event = MasterEvent(MasterEvent.Types.POWER_ADDRESS_EXIT, {}) self.__pubsub.publish_master_event(PubSub.MasterTopics.POWER, master_event)
def _handle_event(self, data): # type: (Dict[str, Any]) -> None core_event = Event(data) if core_event.type == Event.Types.SYSTEM and core_event.data['type'] == Event.SystemEventTypes.EEPROM_ACTIVATE: if self._self_activated: # Ignore self-activations, since those changes are already in the EEPROM cache self._self_activated = False logger.info('Ignore EEPROM_ACTIVATE due to self-activation') else: # EEPROM might have been changed, so clear caches self.invalidate_cache() logger.info('Cache cleared: EEPROM_ACTIVATE') self._activation_event.set() master_event = MasterEvent(MasterEvent.Types.EEPROM_CHANGE, {}) self._pubsub.publish_master_event(PubSub.MasterTopics.EEPROM, master_event)
def test_config_event(self): events = [] def handle_events(gateway_event): events.append(gateway_event) self.pubsub.subscribe_gateway_events(PubSub.GatewayTopics.CONFIG, handle_events) master_event = MasterEvent(MasterEvent.Types.POWER_ADDRESS_EXIT, {}) self.pubsub.publish_master_event(PubSub.MasterTopics.POWER, master_event) self.pubsub._publish_all_events() assert GatewayEvent(GatewayEvent.Types.CONFIG_CHANGE, {'type': 'powermodule'}) in events assert len(events) == 1
def deactivate(self, join=True): # type: (bool) -> None logger.info('Deactivating maintenance mode') self._stopped = True if join and self._read_data_thread is not None: self._read_data_thread.join() self._read_data_thread = None self._master_communicator.stop_maintenance_mode() if self._maintenance_timeout_timer is not None: self._maintenance_timeout_timer.cancel() self._maintenance_timeout_timer = None if self._deactivated_sent is False: master_event = MasterEvent(MasterEvent.Types.MAINTENANCE_EXIT, {}) self._pubsub.publish_master_event(PubSub.MasterTopics.MAINTENANCE, master_event) self._deactivated_sent = True
def test_address_mode(self): """ Test the address mode. """ events = [] def handle_events(master_event): events.append(master_event) self.pubsub.subscribe_master_events(PubSub.MasterTopics.POWER, handle_events) sad = power_api.set_addressmode(power_api.POWER_MODULE) sad_p1c = power_api.set_addressmode(power_api.P1_CONCENTRATOR) self.power_data.extend([ sin(sad.create_input(power_api.BROADCAST_ADDRESS, 1, power_api.ADDRESS_MODE)), sin(sad_p1c.create_input(power_api.BROADCAST_ADDRESS, 2, power_api.ADDRESS_MODE)), sout(power_api.want_an_address(power_api.POWER_MODULE).create_output(0, 0)), sin(power_api.set_address(power_api.POWER_MODULE).create_input(0, 0, 1)), sout(power_api.want_an_address(power_api.ENERGY_MODULE).create_output(0, 0)), sin(power_api.set_address(power_api.ENERGY_MODULE).create_input(0, 0, 2)), sout(power_api.want_an_address(power_api.P1_CONCENTRATOR).create_output(0, 0)), sin(power_api.set_address(power_api.P1_CONCENTRATOR).create_input(0, 0, 3)), sout(bytearray()), # Timeout read after 1 second sin(sad.create_input(power_api.BROADCAST_ADDRESS, 3, power_api.NORMAL_MODE)), sin(sad_p1c.create_input(power_api.BROADCAST_ADDRESS, 4, power_api.NORMAL_MODE)) ]) self.serial.start() self.communicator.start() self.assertEqual(self.store.get_free_address(), 1) self.communicator.start_address_mode() self.assertTrue(self.communicator.in_address_mode()) self.pubsub._publish_all_events() time.sleep(0.5) assert [] == events self.communicator.stop_address_mode() self.pubsub._publish_all_events() assert MasterEvent(MasterEvent.Types.POWER_ADDRESS_EXIT, {}) in events assert len(events) == 1 self.assertEqual(self.store.get_free_address(), 4) self.assertFalse(self.communicator.in_address_mode())
def test_master_eeprom_event(self): master_event = MasterEvent(MasterEvent.Types.EEPROM_CHANGE, {}) self.controller._output_last_updated = 1603178386.0 self.pubsub.publish_master_event(PubSub.MasterTopics.EEPROM, master_event) self.pubsub._publish_all_events() assert self.controller._output_last_updated == 0
def test_output_master_change(self): events = [] def on_change(gateway_event): events.append(gateway_event) self.pubsub.subscribe_gateway_events(PubSub.GatewayTopics.STATE, on_change) self.controller._cache.update_outputs( [OutputDTO(id=2), OutputDTO(id=40, module_type='D', room=3)]) self.controller._handle_master_event( MasterEvent('OUTPUT_STATUS', {'state': OutputStateDTO(id=2, status=False)})) self.controller._handle_master_event( MasterEvent( 'OUTPUT_STATUS', {'state': OutputStateDTO(id=40, status=True, dimmer=100)})) self.pubsub._publish_all_events() events = [] self.controller._handle_master_event( MasterEvent('OUTPUT_STATUS', {'state': OutputStateDTO(id=2, status=True)})) self.controller._handle_master_event( MasterEvent('OUTPUT_STATUS', {'state': OutputStateDTO(id=40, status=True)})) self.pubsub._publish_all_events() assert [ GatewayEvent( 'OUTPUT_CHANGE', { 'id': 2, 'status': { 'on': True, 'locked': False }, 'location': { 'room_id': 255 } }) ] == events events = [] self.controller._handle_master_event( MasterEvent('OUTPUT_STATUS', {'state': OutputStateDTO(id=40, dimmer=50)})) self.pubsub._publish_all_events() assert [ GatewayEvent( 'OUTPUT_CHANGE', { 'id': 40, 'status': { 'on': True, 'value': 50, 'locked': False }, 'location': { 'room_id': 3 } }) ] == events