def test_validation_bits_passthrough(self): # Important note: bits are ordened per byte, so the sequence is like: # [[7, 6, 5, 4, 3, 2, 1, 0], [15, 14, 13, 12, 11, 10, 9, 8], [23, 22, ...], ...] bit_data = [0b00000010, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b01000000] def _do_command(cmd, fields): start = fields['number'] // 8 return {'data': bit_data[start:start + 11]} classic = get_classic_controller_dummy() classic._master_communicator.do_command = _do_command classic._master_version = (0, 0, 0) pubsub = get_pubsub() bits = classic.load_validation_bits() self.assertIsNone(bits) classic._master_version = (3, 143, 102) bits = classic.load_validation_bits() expected_bits = {i: False for i in range(256)} expected_bits[1] = True expected_bits[254] = True self.assertEqual(expected_bits, bits) events = [] def _on_event(master_event): if master_event.type == MasterEvent.Types.OUTPUT_STATUS: events.append(master_event.data) pubsub.subscribe_master_events(PubSub.MasterTopics.OUTPUT, _on_event) classic._validation_bits = ValidationBitStatus(on_validation_bit_change=classic._validation_bit_changed) classic._output_config = {0: OutputDTO(0, lock_bit_id=5)} pubsub._publish_all_events() classic._refresh_validation_bits() classic._on_master_validation_bit_change(5, True) classic._on_master_validation_bit_change(6, True) classic._on_master_validation_bit_change(5, False) pubsub._publish_all_events() self.assertEqual(events, [{'state': OutputStateDTO(id=0, locked=False)}, {'state': OutputStateDTO(id=0, locked=True)}, {'state': OutputStateDTO(id=0, locked=False)}])
def test_get_output_status(self): select_mock = mock.Mock() select_mock.join_from.return_value = [ Output(id=0, number=2), Output(id=1, number=40, room=Room(id=2, number=3)) ] with mock.patch.object(Output, 'select', return_value=select_mock), \ mock.patch.object(self.master_controller, 'load_output', side_effect=lambda output_id: OutputDTO(id=output_id)), \ mock.patch.object(self.master_controller, 'load_output_status', return_value=[OutputStateDTO(id=2, status=False), OutputStateDTO(id=40, status=True)]): self.controller._sync_state() status = self.controller.get_output_status(40) assert status == OutputStateDTO(id=40, status=True)
def test_get_output_statuses(self): select_mock = mock.Mock() select_mock.join_from.return_value = [ Output(id=0, number=2), Output(id=1, number=40, module_type='D', room=Room(id=2, number=3)) ] with mock.patch.object(Output, 'select', return_value=select_mock), \ mock.patch.object(self.master_controller, 'load_output', side_effect=lambda output_id: OutputDTO(id=output_id)), \ mock.patch.object(self.master_controller, 'load_output_status', return_value=[OutputStateDTO(id=2, status=False, dimmer=0), OutputStateDTO(id=40, status=True, dimmer=50)]): self.controller._sync_state() status = self.controller.get_output_statuses() assert len(status) == 2 assert OutputStateDTO(id=2, status=False) in status assert OutputStateDTO(id=40, status=True, dimmer=50) in status
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 update_outputs(self, output_dtos): # type: (List[OutputDTO]) -> None with self._lock: new_state = {} for output_dto in output_dtos: output_dto = copy.copy(output_dto) if output_dto.id in self._cache: output_dto.state = self._cache[output_dto.id].state else: output_dto.state = OutputStateDTO(output_dto.id) new_state[output_dto.id] = output_dto self._cache = new_state self._loaded = True
def deserialize(api_data): # type: (Dict) -> OutputStateDTO output_state_dto = OutputStateDTO(api_data['id']) SerializerToolbox.deserialize( dto=output_state_dto, # Referenced api_data=api_data, mapping={ 'status': ('status', bool), 'ctimer': ('ctimer', lambda x: x or 0), 'dimmer': ('dimmer', lambda x: x or 0), 'locked': ('locked', lambda x: x or False) }) return output_state_dto
def test_output_status(self): with mock.patch.object( self.output_controller, 'get_output_statuses', return_value=[OutputStateDTO(id=0, status=True)]): response = self.web.get_output_status() self.assertEqual([{ 'id': 0, 'status': 1, 'ctimer': 0, 'dimmer': 0, 'locked': False }], json.loads(response)['status'])
def deserialize(api_data): # type: (Dict) -> Tuple[OutputStateDTO, List[str]] loaded_fields = ['id'] output_state_dto = OutputStateDTO(api_data['id']) loaded_fields += SerializerToolbox.deserialize( dto=output_state_dto, # Referenced api_data=api_data, mapping={ 'status': ('status', bool), 'ctimer': ('ctimer', lambda x: x or 0), 'dimmer': ('dimmer', lambda x: x or 0), 'locked': ('locked', lambda x: x or False) }) return output_state_dto, loaded_fields
def setUp(self): self.test_db = SqliteDatabase(':memory:') self.test_db.bind(MODELS) self.test_db.connect() self.test_db.create_tables(MODELS) self._gateway_api = mock.Mock(GatewayApi) self._gateway_api.get_timezone.return_value = 'Europe/Brussels' self._gateway_api.get_sensor_temperature_status.return_value = 10.0 output_controller = mock.Mock(OutputController) output_controller.get_output_status.return_value = OutputStateDTO(id=0, status=False) SetUpTestInjections(gateway_api=self._gateway_api, output_controller=output_controller, pubsub=mock.Mock()) self._thermostat_controller = ThermostatControllerGateway() SetUpTestInjections(thermostat_controller=self._thermostat_controller) self._thermostat_group = ThermostatGroup.create(number=0, name='thermostat group', on=True, threshold_temperature=10.0, sensor=Sensor.create(number=1), mode='heating')
def test_output_sync_change(self): events = [] def on_change(gateway_event): events.append(gateway_event) self.pubsub.subscribe_gateway_events(PubSub.GatewayTopics.STATE, on_change) outputs = {2: OutputDTO(id=2), 40: OutputDTO(id=40, module_type='D')} select_mock = mock.Mock() select_mock.join_from.return_value = [ Output(id=0, number=2), Output(id=1, number=40, room=Room(id=2, number=3)) ] with mock.patch.object(Output, 'select', return_value=select_mock), \ mock.patch.object(self.master_controller, 'load_output', side_effect=lambda output_id: outputs.get(output_id)), \ mock.patch.object(self.master_controller, 'load_output_status', return_value=[OutputStateDTO(id=2, status=True), OutputStateDTO(id=40, status=True)]): self.controller._sync_state() self.pubsub._publish_all_events() assert [ GatewayEvent( 'OUTPUT_CHANGE', { 'id': 2, 'status': { 'on': True, 'locked': False }, 'location': { 'room_id': 255 } }), GatewayEvent( 'OUTPUT_CHANGE', { 'id': 40, 'status': { 'on': True, 'value': 0, 'locked': False }, 'location': { 'room_id': 3 } }) ] == events select_mock = mock.Mock() select_mock.join_from.return_value = [ Output(id=0, number=2), Output(id=1, number=40, room=Room(id=2, number=3)) ] with mock.patch.object(Output, 'select', return_value=select_mock), \ mock.patch.object(self.master_controller, 'load_output', side_effect=lambda output_id: outputs.get(output_id)), \ mock.patch.object(self.master_controller, 'load_output_status', return_value=[OutputStateDTO(id=2, status=True, dimmer=0), OutputStateDTO(id=40, status=True, dimmer=50)]): events = [] self.controller._sync_state() self.pubsub._publish_all_events() assert [ GatewayEvent( 'OUTPUT_CHANGE', { 'id': 2, 'status': { 'on': True, 'locked': False }, 'location': { 'room_id': 255 } }), GatewayEvent( 'OUTPUT_CHANGE', { 'id': 40, 'status': { 'on': True, 'value': 50, 'locked': False }, 'location': { 'room_id': 3 } }) ] == events
def test_update(self): _ = self cache = OutputStateCache() cache.update_outputs( [OutputDTO(id=0), OutputDTO(id=1), OutputDTO(id=2)]) current_state = cache.get_state() assert { 0: OutputStateDTO(id=0), 1: OutputStateDTO(id=1), 2: OutputStateDTO(id=2) } == current_state # Everything is off. assert cache.handle_change(OutputStateDTO(0, status=False))[0] is False assert cache.handle_change(OutputStateDTO(1, status=False))[0] is False assert cache.handle_change(OutputStateDTO(2, status=False))[0] is False # Turn two outputs on. assert cache.handle_change(OutputStateDTO(0, status=False))[0] is False changed, output_dto = cache.handle_change( OutputStateDTO(2, status=True)) assert output_dto.state.status is True assert changed is True changed, output_dto = cache.handle_change( OutputStateDTO(1, status=True)) assert output_dto.state.status is True assert changed is True # Turn one outputs off again. assert cache.handle_change(OutputStateDTO(0, status=False))[0] is False changed, output_dto = cache.handle_change( OutputStateDTO(1, status=False)) assert output_dto.state.status is False assert changed is True # Change dimmer value. assert cache.handle_change(OutputStateDTO(0, dimmer=0))[0] is False changed, output_dto = cache.handle_change( OutputStateDTO(1, status=True, dimmer=100)) assert output_dto.state.dimmer == 100 assert changed is True changed, output_dto = cache.handle_change(OutputStateDTO(1, dimmer=50)) assert output_dto.state.dimmer is 50 assert changed is True # Change lock. assert cache.handle_change(OutputStateDTO(0, locked=False))[0] is False changed, output_dto = cache.handle_change( OutputStateDTO(1, locked=True)) assert output_dto.state.locked is True assert changed is True
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
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 = [OutputStateDTO(id=0, status=False, dimmer=0), OutputStateDTO(id=1, status=False, dimmer=0), OutputStateDTO(id=10, status=False, dimmer=0), OutputStateDTO(id=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 = [OutputStateDTO(id=0, status=False, dimmer=0), OutputStateDTO(id=1, status=True, dimmer=0), OutputStateDTO(id=10, status=True, dimmer=0), OutputStateDTO(id=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 = [OutputStateDTO(id=0, status=False, dimmer=0), OutputStateDTO(id=1, status=True, dimmer=0), OutputStateDTO(id=10, status=False, dimmer=0), OutputStateDTO(id=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 test_get_special_methods(self): """ Test getting special methods on a plugin. """ controller = None try: PluginControllerTest._create_plugin( 'P1', """ import time from plugins.base import * class P1(OMPluginBase): name = 'P1' version = '0.1.0' interfaces = [('webui', '1.0')] def __init__(self, webservice, logger): OMPluginBase.__init__(self, webservice, logger) self._bg_running = False self._input_data = None self._input_data_version_2 = None self._output_data = None self._output_data_version_2 = None self._event_data = None @om_expose(auth=True) def html_index(self): return 'HTML' @om_expose(auth=False) def get_log(self): return {'bg_running': self._bg_running, 'input_data': self._input_data, 'input_data_version_2': self._input_data_version_2, 'output_data': self._output_data, 'output_data_version_2': self._output_data_version_2, 'event_data': self._event_data} @input_status def input(self, input_status_inst): self._input_data = input_status_inst @input_status(version=2) def input_version_2(self, input_status_inst): self._input_data_version_2 = input_status_inst @output_status def output(self, output_status_inst): self._output_data = output_status_inst @output_status(version=2) def output_version_2(self, output_status_inst): self._output_data_version_2 = output_status_inst @receive_events def recv_events(self, code): self._event_data = code @background_task def run(self): while True: self._bg_running = True time.sleep(1) """) output_controller = Mock(OutputController) output_controller.get_output_statuses = lambda: [ OutputStateDTO(id=1, status=True, dimmer=5) ] controller = PluginControllerTest._get_controller( output_controller=output_controller) controller.start() response = controller._request('P1', 'html_index') self.assertEqual(response, 'HTML') rising_input_event = { 'id': 1, 'status': True, 'location': { 'room_id': 1 } } controller.process_observer_event( GatewayEvent(event_type=GatewayEvent.Types.INPUT_CHANGE, data=rising_input_event)) falling_input_event = { 'id': 2, 'status': False, 'location': { 'room_id': 5 } } controller.process_observer_event( GatewayEvent(event_type=GatewayEvent.Types.INPUT_CHANGE, data=falling_input_event)) output_event = { 'id': 1, 'status': { 'on': True, 'value': 5, 'locked': True }, 'location': { 'room_id': 5 } } controller.process_observer_event( GatewayEvent(event_type=GatewayEvent.Types.OUTPUT_CHANGE, data=output_event)) controller.process_event(1) keys = [ 'input_data', 'input_data_version_2', 'output_data', 'output_data_version_2', 'event_data' ] start = time.time() while time.time() - start < 2: response = controller._request('P1', 'get_log') if all(response[key] is not None for key in keys): break time.sleep(0.1) self.assertEqual(response['bg_running'], True) self.assertEqual( response['input_data'], [1, None]) # only rising edges should be triggered self.assertEqual(response['output_data'], [[1, 5]]) self.assertEqual(response['output_data_version_2'], output_event) self.assertEqual(response['event_data'], 1) finally: if controller is not None: controller.stop() PluginControllerTest._destroy_plugin('P1')