示例#1
0
class ThermostatControllerMasterTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        SetTestMode()

    def setUp(self):
        self.pubsub = PubSub()
        SetUpTestInjections(
            pubsub=self.pubsub,
            master_controller=mock.Mock(MasterClassicController),
            output_controller=mock.Mock(OutputController))
        self.controller = ThermostatControllerMaster()

    def test_thermostat_change_events(self):
        events = []

        def handle_event(gateway_event):
            events.append(gateway_event)

        self.pubsub.subscribe_gateway_events(PubSub.GatewayTopics.STATE,
                                             handle_event)

        with mock.patch.object(self.controller,
                               'invalidate_cache') as handle_event:
            status = {
                'act': None,
                'csetp': None,
                'setpoint': None,
                'output0': None,
                'output1': None
            }
            self.controller._thermostats_config = {1: ThermostatDTO(1)}
            self.controller._thermostat_status._report_change(1, status)
            self.pubsub._publish_all_events()
            event_data = {
                'id': 1,
                'status': {
                    'preset': 'AUTO',
                    'current_setpoint': None,
                    'actual_temperature': None,
                    'output_0': None,
                    'output_1': None
                },
                'location': {
                    'room_id': 255
                }
            }
            assert GatewayEvent(GatewayEvent.Types.THERMOSTAT_CHANGE,
                                event_data) in events

    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()
示例#2
0
class PowerControllerTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        SetTestMode()

    def setUp(self):
        self.pubsub = PubSub()
        SetUpTestInjections(pubsub=self.pubsub)
        self.power_communicator = mock.Mock()
        SetUpTestInjections(power_communicator=self.power_communicator,
                            power_store=mock.Mock())
        self.controller = PowerController()

    def test_get_module_current(self):
        with mock.patch.object(self.power_communicator, 'do_command') as cmd:
            self.controller.get_module_current({
                'version': POWER_MODULE,
                'address': '11.0'
            })
            assert cmd.call_args_list == [
                mock.call(
                    '11.0',
                    PowerCommand('G',
                                 'CUR',
                                 '',
                                 '8f',
                                 module_type=bytearray(b'E')))
            ]

    def test_get_module_frequency(self):
        with mock.patch.object(self.power_communicator, 'do_command') as cmd:
            self.controller.get_module_frequency({
                'version': POWER_MODULE,
                'address': '11.0'
            })
            assert cmd.call_args_list == [
                mock.call(
                    '11.0',
                    PowerCommand('G',
                                 'FRE',
                                 '',
                                 'f',
                                 module_type=bytearray(b'E')))
            ]

    def test_get_module_power(self):
        with mock.patch.object(self.power_communicator, 'do_command') as cmd:
            self.controller.get_module_power({
                'version': POWER_MODULE,
                'address': '11.0'
            })
            assert cmd.call_args_list == [
                mock.call(
                    '11.0',
                    PowerCommand('G',
                                 'POW',
                                 '',
                                 '8f',
                                 module_type=bytearray(b'E')))
            ]

    def test_get_module_voltage(self):
        with mock.patch.object(self.power_communicator, 'do_command') as cmd:
            self.controller.get_module_voltage({
                'version': POWER_MODULE,
                'address': '11.0'
            })
            assert cmd.call_args_list == [
                mock.call(
                    '11.0',
                    PowerCommand('G',
                                 'VOL',
                                 '',
                                 'f',
                                 module_type=bytearray(b'E')))
            ]

    def test_get_module_day_energy(self):
        with mock.patch.object(self.power_communicator, 'do_command') as cmd:
            self.controller.get_module_day_energy({
                'version': POWER_MODULE,
                'address': '11.0'
            })
            assert cmd.call_args_list == [
                mock.call(
                    '11.0',
                    PowerCommand('G',
                                 'EDA',
                                 '',
                                 '8L',
                                 module_type=bytearray(b'E')))
            ]

    def test_get_module_night_energy(self):
        with mock.patch.object(self.power_communicator, 'do_command') as cmd:
            self.controller.get_module_night_energy({
                'version': POWER_MODULE,
                'address': '11.0'
            })
            assert cmd.call_args_list == [
                mock.call(
                    '11.0',
                    PowerCommand('G',
                                 'ENI',
                                 '',
                                 '8L',
                                 module_type=bytearray(b'E')))
            ]

    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
class MasterCoreControllerTest(unittest.TestCase):
    """ Tests for MasterCoreController. """

    @classmethod
    def setUpClass(cls):
        SetTestMode()

    def setUp(self):
        self.memory = {}
        self.return_data = {}

        def _do_command(command, fields, timeout=None):
            _ = timeout
            instruction = ''.join(str(chr(c)) for c in command.instruction)
            if instruction == 'MR':
                page = fields['page']
                start = fields['start']
                length = fields['length']
                return {'data': self.memory.get(page, bytearray([255] * 256))[start:start + length]}
            elif instruction == 'MW':
                page = fields['page']
                start = fields['start']
                page_data = self.memory.setdefault(page, bytearray([255] * 256))
                for index, data_byte in enumerate(fields['data']):
                    page_data[start + index] = data_byte
            elif instruction in self.return_data:
                return self.return_data[instruction]
            else:
                raise AssertionError('unexpected instruction: {0}'.format(instruction))

        def _do_basic_action(action_type, action, device_nr=0, extra_parameter=0, timeout=2, log=True):
            _ = device_nr, extra_parameter, timeout, log
            if action_type == 200 and action == 1:
                # Send EEPROM_ACTIVATE event
                eeprom_file._handle_event({'type': 254, 'action': 0, 'device_nr': 0, 'data': 0})

        self.communicator = mock.Mock(CoreCommunicator)
        self.communicator.do_command = _do_command
        self.communicator.do_basic_action = _do_basic_action
        self.pubsub = PubSub()
        SetUpTestInjections(master_communicator=self.communicator,
                            pubsub=self.pubsub)

        eeprom_file = MemoryFile(MemoryTypes.EEPROM)
        eeprom_file._cache = self.memory
        SetUpTestInjections(memory_files={MemoryTypes.EEPROM: eeprom_file,
                                          MemoryTypes.FRAM: MemoryFile(MemoryTypes.FRAM)},
                            ucan_communicator=UCANCommunicator(),
                            slave_communicator=SlaveCommunicator())
        self.controller = MasterCoreController()

        # For testing purposes, remove read-only flag from certain properties
        for field_name in ['device_type', 'address', 'firmware_version']:
            for model_type in [OutputModuleConfiguration, InputModuleConfiguration, SensorModuleConfiguration]:
                if hasattr(model_type, '_{0}'.format(field_name)):
                    getattr(model_type, '_{0}'.format(field_name))._read_only = False
                else:
                    getattr(model_type, field_name)._read_only = False

    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_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_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 test_input_module_type(self):
        with mock.patch.object(gateway.hal.master_controller_core, 'InputConfiguration',
                               return_value=get_core_input_dummy(1)):
            data = self.controller.get_input_module_type(1)
            self.assertEqual('I', data)

    def test_load_input(self):
        data = self.controller.load_input(1)
        self.assertEqual(data.id, 1)

    def test_load_inputs(self):
        input_modules = list(map(get_core_input_dummy, range(1, 17)))
        self.return_data['GC'] = {'input': 2}
        with mock.patch.object(gateway.hal.master_controller_core, 'InputConfiguration',
                               side_effect=input_modules):
            inputs = self.controller.load_inputs()
            self.assertEqual([x.id for x in inputs], list(range(1, 17)))

    def test_save_inputs(self):
        data = [(InputDTO(id=1, name='foo', module_type='I'), ['id', 'name', 'module_type']),
                (InputDTO(id=2, name='bar', module_type='I'), ['id', 'name', 'module_type'])]
        input_mock = mock.Mock(InputConfiguration)
        with mock.patch.object(InputConfiguration, 'deserialize', return_value=input_mock) as deserialize, \
                mock.patch.object(input_mock, 'save', return_value=None) as save:
            self.controller.save_inputs(data)
            self.assertIn(mock.call({'id': 1, 'name': 'foo'}), deserialize.call_args_list)
            self.assertIn(mock.call({'id': 2, 'name': 'bar'}), deserialize.call_args_list)
            save.assert_called_with()

    def test_inputs_with_status(self):
        from gateway.hal.master_controller_core import MasterInputState
        with mock.patch.object(MasterInputState, 'get_inputs', return_value=[]) as get:
            self.controller.get_inputs_with_status()
            get.assert_called_with()

    def test_recent_inputs(self):
        from gateway.hal.master_controller_core import MasterInputState
        with mock.patch.object(MasterInputState, 'get_recent', return_value=[]) as get:
            self.controller.get_recent_inputs()
            get.assert_called_with()

    def test_event_consumer(self):
        with mock.patch.object(gateway.hal.master_controller_core, 'BackgroundConsumer',
                               return_value=None) as new_consumer:
            controller = MasterCoreController()
            expected_call = mock.call(CoreAPI.event_information(), 0, mock.ANY)
            self.assertIn(expected_call, new_consumer.call_args_list)

    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_get_modules(self):
        from master.core.memory_models import (
            InputModuleConfiguration, OutputModuleConfiguration, SensorModuleConfiguration,
            GlobalConfiguration
        )
        global_configuration = GlobalConfiguration()
        global_configuration.number_of_output_modules = 5
        global_configuration.number_of_input_modules = 4
        global_configuration.number_of_sensor_modules = 2
        global_configuration.number_of_can_control_modules = 2
        global_configuration.save()
        for module_id, module_class, device_type, address in [(0, InputModuleConfiguration, 'I', '{0}.123.123.123'.format(ord('I'))),
                                                              (1, InputModuleConfiguration, 'i', '{0}.123.123.123'.format(ord('i'))),
                                                              (2, InputModuleConfiguration, 'i', '{0}.000.000.000'.format(ord('i'))),
                                                              (3, InputModuleConfiguration, 'b', '{0}.123.132.123'.format(ord('b'))),
                                                              (0, OutputModuleConfiguration, 'o', '{0}.000.000.000'.format(ord('o'))),
                                                              (1, OutputModuleConfiguration, 'o', '{0}.000.000.001'.format(ord('o'))),
                                                              (2, OutputModuleConfiguration, 'o', '{0}.000.000.002'.format(ord('o'))),
                                                              (3, OutputModuleConfiguration, 'o', '{0}.123.123.123'.format(ord('o'))),
                                                              (4, OutputModuleConfiguration, 'O', '{0}.123.123.123'.format(ord('O'))),
                                                              (0, SensorModuleConfiguration, 's', '{0}.123.123.123'.format(ord('s'))),
                                                              (1, SensorModuleConfiguration, 'T', '{0}.123.123.123'.format(ord('T')))]:
            instance = module_class(module_id)
            instance.device_type = device_type
            instance.address = address
            instance.save()

        self.assertEqual({'can_inputs': ['I', 'T', 'C', 'E'],
                          'inputs': ['I', 'i', 'J', 'T'],
                          'outputs': ['P', 'P', 'P', 'o', 'O'],
                          'shutters': []}, self.controller.get_modules())

    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