def __new__(cls, addr, *args, **kwargs): """ Overridden __new__ for setting the size. """ return ModbusRegister.__new__(cls, addr, size=3, *args, **kwargs)
def __new__(cls, addr, *args, **kwargs): """ Overridden __new__ for setting the signed option. """ return ModbusRegister.__new__(cls, addr, signed=True, *args, **kwargs)
def __new__(cls, addr, *args, **kwargs): """ Overridden __new__ for fixing the register size and forcing unsigned values since 2's complement is used here. """ return ModbusRegister.__new__(cls, addr, size=2, signed=False, *args, **kwargs)
def __new__(cls, addr, *args, **kwargs): """ Overridden __new__ for fixing the register size. """ return ModbusRegister.__new__(cls, addr, *args, **kwargs)
class DigiRail_2A(RTUModbusHWDevice): """ DigiRail-2A A/D converter HW device The supported model is the RTU RS485 one, the RS485 bus being connected via a USB.RS485 interface. """ DEFAULT_BAUDRATE = 19200 # registers # - configuration REG_MODBUS_ADDR = ModbusRegister(3) REG_INPUT_TYPE_1 = ModbusRegister(21) REG_INPUT_TYPE_2 = ModbusRegister(22) REG_MEAS_UNIT_1 = ModbusRegister(26) REG_MEAS_UNIT_2 = ModbusRegister(27) # - data REG_PV_ENG_1 = ModbusRegister(14) REG_PV_ENG_2 = ModbusRegister(15) #: the compiled sequence of collected registers COLLECTED_REGS = [REG_PV_ENG_1, REG_PV_ENG_2] _TOTAL_INPUT_SIZE = reduce(lambda accum, size: accum + size, [r.size for r in COLLECTED_REGS]) # Definition of the type of the poll() method result # VERY IMPORTANT : # The name of its items MUST match the name of the outputs described # in the metadata stored in devcfg.d directory, since the notification # events generation process is based on this. # (see pycstbox.hyal.device.PolledDevice.poll() method for details) OutputValues = namedtuple( 'OutputValues', [ 'in1', # input 1 'in2', # input 2 ]) def __init__(self, port, unit_id): """ :param str port: serial port on which the RS485 interface is connected :param int unit_id: the address of the device """ super(DigiRail_2A, self).__init__(port=port, unit_id=int(unit_id), logname='dr2a') self._logger.info('reading inputs configuration from device...') input_types = self.unpack_registers( start_register=self.REG_INPUT_TYPE_1, reg_count=2, unpack_format='>hh') input_units = self.unpack_registers( start_register=self.REG_MEAS_UNIT_1, reg_count=2, unpack_format='>hh') self._logger.info('creating corresponding model instances...') self.inputs = [ DRInput(input_type, input_unit) for input_type, input_unit in zip(input_types, input_units) ] for n, input in enumerate(self.inputs): self._logger.info('... [%d] %s', n + 1, input) @property def unit_id(self): """ The id of the device """ return self.address def poll(self): """ Reads the registers data and returns the values as a named tuple. """ # since the input registers are contiguous, optimise the operation by reading them in a single request return self.OutputValues(**dict( zip(self.OutputValues._fields, [ inp.physical_value(rv) for inp, rv in zip( self.inputs, self.unpack_registers( self.REG_PV_ENG_1, reg_count=2, unpack_format=">hh")) ]))) def input_unit(self, channel_num): try: return self.inputs[channel_num - 1].unit except KeyError: raise ValueError('invalid channel number (%s)' % channel_num) def is_enabled(self, channel_num): try: return self.inputs[channel_num - 1].enabled except KeyError: raise ValueError('invalid channel number (%s)' % channel_num)