def __init__(self, master_communicator=INJECTED, ucan_communicator=INJECTED, memory_files=INJECTED):
        """
        :type master_communicator: master_core.core_communicator.CoreCommunicator
        :type ucan_communicator: master_core.ucan_communicator.UCANCommunicator
        :type memory_files: dict[master_core.memory_file.MemoryTypes, master_core.memory_file.MemoryFile]
        """
        super(MasterCoreController, self).__init__(master_communicator)
        self._ucan_communicator = ucan_communicator
        self._memory_files = memory_files
        self._synchronization_thread = Thread(target=self._synchronize, name='CoreMasterSynchronization')
        self._master_online = False
        self._input_state = MasterInputState()
        self._output_interval = 600
        self._output_last_updated = 0
        self._output_states = {}
        self._sensor_interval = 300
        self._sensor_last_updated = 0
        self._sensor_states = {}

        self._master_communicator.register_consumer(
            BackgroundConsumer(CoreAPI.event_information(), 0, self._handle_event)
        )
        self._master_communicator.register_consumer(
            BackgroundConsumer(CoreAPI.error_information(), 0, lambda e: logger.info('Got master error: {0}'.format(Error(e))))
        )
        self._master_communicator.register_consumer(
            BackgroundConsumer(CoreAPI.ucan_module_information(), 0, lambda i: logger.info('Got ucan module information: {0}'.format(i)))
        )
 def _refresh_output_states(self):
     amount_output_modules = self._master_communicator.do_command(CoreAPI.general_configuration_number_of_modules(), {})['output']
     for i in xrange(amount_output_modules * 8):
         state = self._master_communicator.do_command(CoreAPI.output_detail(), {'device_nr': i})
         # TODO: also trigger callback when status changed without an event.
         self._output_states[i] = {'id': i,
                                   'status': state['status'],  # 1 or 0
                                   'ctimer': state['timer'],
                                   'dimmer': state['dimmer']}
     self._output_last_updated = time.time()
 def _refresh_sensor_states(self):
     amount_sensor_modules = self._master_communicator.do_command(CoreAPI.general_configuration_number_of_modules(), {})['sensor']
     for module_nr in xrange(amount_sensor_modules):
         temperature_values = self._master_communicator.do_command(CoreAPI.sensor_temperature_values(), {'module_nr': module_nr})['values']
         brightness_values = self._master_communicator.do_command(CoreAPI.sensor_brightness_values(), {'module_nr': module_nr})['values']
         humidity_values = self._master_communicator.do_command(CoreAPI.sensor_humidity_values(), {'module_nr': module_nr})['values']
         for i in xrange(8):
             sensor_id = module_nr * 8 + i
             self._sensor_states[sensor_id] = {'TEMPERATURE': temperature_values[i],
                                               'BRIGHTNESS': brightness_values[i],
                                               'HUMIDITY': humidity_values[i]}
     self._sensor_last_updated = time.time()
 def set_output(self, output_id, state, dimmer=None, timer=None):
     # TODO: Use `dimmer` and `timer`
     _ = dimmer, timer
     action = 1 if state else 0
     self._master_communicator.do_command(CoreAPI.basic_action(), {'type': 0, 'action': action,
                                                                   'device_nr': output_id,
                                                                   'extra_parameter': 0})
    def _log_stats(self):
        def _default_if_255(value, default):
            return value if value != 255 else default

        max_specs = self._master_communicator.do_command(CoreAPI.general_configuration_max_specs(), {})
        general_configuration = GlobalConfiguration()
        logger.info('General core information:')
        logger.info('* Modules:')
        logger.info('  * Output: {0}/{1}'.format(_default_if_255(general_configuration.number_of_output_modules, 0),
                                                 max_specs['output']))
        logger.info('  * Input: {0}/{1}'.format(_default_if_255(general_configuration.number_of_input_modules, 0),
                                                max_specs['input']))
        logger.info('  * Sensor: {0}/{1}'.format(_default_if_255(general_configuration.number_of_sensor_modules, 0),
                                                 max_specs['sensor']))
        logger.info('  * uCAN: {0}/{1}'.format(_default_if_255(general_configuration.number_of_ucan_modules, 0),
                                               max_specs['ucan']))
        logger.info('  * CAN Control: {0}'.format(_default_if_255(general_configuration.number_of_can_control_modules, 0)))
        logger.info('* CAN:')
        logger.info('  * Inputs: {0}'.format(general_configuration.number_of_can_inputs))
        logger.info('  * Sensors: {0}'.format(general_configuration.number_of_can_sensors))
        logger.info('* Scan times:')
        logger.info('  * General bus: {0}ms'.format(_default_if_255(general_configuration.scan_time_rs485_bus, 8)))
        logger.info('  * Sensor modules: {0}ms'.format(_default_if_255(general_configuration.scan_time_rs485_sensor_modules, 50) * 100))
        logger.info('  * CAN Control modules: {0}ms'.format(_default_if_255(general_configuration.scan_time_rs485_can_control_modules, 50) * 100))
        logger.info('* Runtime stats:')
        logger.info('  * Uptime: {0}d {1}h'.format(general_configuration.uptime_hours / 24,
                                                   general_configuration.uptime_hours % 24))
        # noinspection PyStringFormat
        logger.info('  * Started at 20{0}/{1}/{2} {3}:{4}:{5}'.format(*(list(reversed(general_configuration.startup_date)) +
                                                                        general_configuration.startup_time)))
示例#6
0
 def do_basic_action(self,
                     action_type,
                     action,
                     device_nr,
                     extra_parameter=0):
     """
     Sends a basic action to the Core with the given action type and action number
     :param action_type: The action type to execute
     :type action_type: int
     :param action: The action number to execute
     :type action: int
     :param device_nr: Device number
     :type device_nr: int
     :param extra_parameter: Optional extra argument
     :type extra_parameter: int
     :raises: :class`CommunicationTimedOutException` if Core did not respond in time
     :returns: dict containing the output fields of the command
     """
     logger.info('BA: Execute {0} {1} {2} {3}'.format(
         action_type, action, device_nr, extra_parameter))
     return self.do_command(
         CoreAPI.basic_action(), {
             'type': action_type,
             'action': action,
             'device_nr': device_nr,
             'extra_parameter': extra_parameter
         })
示例#7
0
 def shutter_stop(self, shutter_id):
     self._master_communicator.do_command(CoreAPI.basic_action(), {
         'type': 10,
         'action': 0,
         'device_nr': shutter_id,
         'extra_parameter': 0
     })
示例#8
0
 def load_outputs(self, fields=None):
     amount_output_modules = self._master_communicator.do_command(
         CoreAPI.general_configuration_number_of_modules(), {})['output']
     outputs = []
     for i in xrange(amount_output_modules * 8):
         outputs.append(self.load_output(i, fields))
     return outputs
示例#9
0
 def toggle_output(self, output_id):
     self._master_communicator.do_command(CoreAPI.basic_action(), {
         'type': 0,
         'action': 16,
         'device_nr': output_id,
         'extra_parameter': 0
     })
 def _refresh_input_states(self):
     # type: () -> bool
     refresh = self._input_state.should_refresh()
     if refresh:
         cmd = CoreAPI.device_information_list_inputs()
         data = self._master_communicator.do_command(cmd, {})
         for event in self._input_state.refresh(data['information']):
             for callback in self._event_callbacks:
                 callback(event)
     return refresh
示例#11
0
 def _read_page():
     page_data = []
     for i in xrange(self._page_length / 32):
         page_data += self._core_communicator.do_command(
             CoreAPI.memory_read(), {
                 'type': self.type,
                 'page': page,
                 'start': i * 32,
                 'length': 32
             })['data']
     return page_data
示例#12
0
    def do_command(self, cc_address, command, identity, fields, timeout=2):
        """
        Send a uCAN command over the Communicator and block until an answer is received.
        If the Core does not respond within the timeout period, a CommunicationTimedOutException is raised

        :param cc_address: An address of the CC connected to the uCAN
        :type cc_address: str
        :param command: specification of the command to execute
        :type command: master_core.ucan_command.UCANCommandSpec
        :param identity: The identity
        :type identity: str
        :param fields: A dictionary with the command input field values
        :type fields dict
        :param timeout: maximum allowed time before a CommunicationTimedOutException is raised
        :type timeout: int or None
        :raises: serial_utils.CommunicationTimedOutException
        :returns: dict containing the output fields of the command
        """
        if self._cc_pallet_mode.get(cc_address, False) is True:
            raise BootloadingException('CC {0} is currently bootloading'.format(cc_address))

        command.set_identity(identity)

        if command.sid == SID.BOOTLOADER_PALLET:
            consumer = PalletConsumer(cc_address, command, self._release_pallet_mode)
            self._cc_pallet_mode[cc_address] = True
        else:
            consumer = Consumer(cc_address, command)
        self.register_consumer(consumer)

        master_timeout = False
        for payload in command.create_request_payloads(identity, fields):
            if self._verbose:
                logger.info('Writing to uCAN transport:   CC {0} - SID {1} - Data: {2}'.format(cc_address, command.sid, printable(payload)))
            try:
                self._communicator.do_command(command=CoreAPI.ucan_tx_transport_message(),
                                              fields={'cc_address': cc_address,
                                                      'nr_can_bytes': len(payload),
                                                      'sid': command.sid,
                                                      'payload': payload + [0] * (8 - len(payload))},
                                              timeout=timeout)
            except CommunicationTimedOutException as ex:
                logger.error('Internal timeout during uCAN transport to CC {0}: {1}'.format(cc_address, ex))
                master_timeout = True
                break

        consumer.check_send_only()
        if master_timeout:
            # When there's a communication timeout with the master, catch this exception and timeout the consumer
            # so it uses a flow expected by the caller
            return consumer.get(0)
        if timeout is not None:
            return consumer.get(timeout)
示例#13
0
 def write_page(self, page, data):
     self._cache[page] = data
     length = 32
     for i in xrange(self._page_length / length):
         start = i * length
         self._core_communicator.do_command(
             CoreAPI.memory_write(length), {
                 'type': self.type,
                 'page': page,
                 'start': start,
                 'data': data[start:start + length]
             })
示例#14
0
 def read_page(self, page):
     if page not in self._cache:
         page_data = []
         for i in xrange(self._page_length / 32):
             page_data += self._core_communicator.do_command(
                 CoreAPI.memory_read(), {
                     'type': self.type,
                     'page': page,
                     'start': i * 32,
                     'length': 32
                 })['data']
         self._cache[page] = page_data
     return self._cache[page]
示例#15
0
    def __init__(self, master_communicator=INJECTED, verbose=False):
        """
        :param master_communicator: CoreCommunicator
        :type master_communicator: master_core.core_communicator.CoreCommunicator
        :param verbose: Log all communication
        :type verbose: boolean.
        """
        self._verbose = verbose
        self._communicator = master_communicator
        self._read_buffer = []
        self._consumers = {}
        self._cc_pallet_mode = {}

        self._background_consumer = BackgroundConsumer(CoreAPI.ucan_rx_transport_message(), 1, self._process_transport_message)
        self._communicator.register_consumer(self._background_consumer)
示例#16
0
    def __init__(self, memory_type, master_communicator=INJECTED):
        """
        Initializes the MemoryFile instance, reprensenting one of the supported memory types.
        It provides caching for EEPROM, and direct write/read through for FRAM

        :type master_communicator: master_core.core_communicator.CoreCommunicator
        """
        if not master_communicator:
            raise RuntimeError('Could not inject argument: core_communicator')

        self._core_communicator = master_communicator
        self.type = memory_type
        self._cache = {}
        if memory_type == MemoryTypes.EEPROM:
            self._pages = 512
            self._page_length = 256
        elif memory_type == MemoryTypes.FRAM:
            self._pages = 128
            self._page_length = 256

        if memory_type == MemoryTypes.EEPROM:
            self._core_communicator.register_consumer(
                BackgroundConsumer(CoreAPI.event_information(), 0,
                                   self._handle_event))
 def _enumerate_io_modules(self, module_type):
     cmd = CoreAPI.general_configuration_number_of_modules()
     module_count = self._master_communicator.do_command(cmd, {})[module_type]
     return xrange(module_count * 8)
 def load_sensors(self, fields=None):
     amount_sensor_modules = self._master_communicator.do_command(CoreAPI.general_configuration_number_of_modules(), {})['sensor']
     sensors = []
     for i in xrange(amount_sensor_modules * 8):
         sensors.append(self.load_sensor(i, fields))
     return sensors
 def get_sensors_humidity(self):
     amount_sensor_modules = self._master_communicator.do_command(CoreAPI.general_configuration_number_of_modules(), {})['sensor']
     humidities = []
     for sensor_id in xrange(amount_sensor_modules * 8):
         humidities.append(self.get_sensor_humidity(sensor_id))
     return humidities
 def get_sensors_brightness(self):
     amount_sensor_modules = self._master_communicator.do_command(CoreAPI.general_configuration_number_of_modules(), {})['sensor']
     brightnesses = []
     for sensor_id in xrange(amount_sensor_modules * 8):
         brightnesses.append(self.get_sensor_brightness(sensor_id))
     return brightnesses