def testPayloadBuilderWithRawPayload(self): """ Test basic bit message encoding/decoding """ _coils1 = [False, False, True, True, False, True, False, False, False, False, False, True, False, False, True, False, False, True, True, True, True, False, False, False, False, True, False, True, False, True, True, False] _coils2 = [False, False, False, True, False, False, True, False, False, False, True, True, False, True, False, False, False, True, False, True, False, True, True, False, False, True, True, True, True, False, False, False] builder = BinaryPayloadBuilder([b'\x12', b'\x34', b'\x56', b'\x78'], repack=True) self.assertEqual(b'\x12\x34\x56\x78', builder.to_string()) self.assertEqual([13330, 30806], builder.to_registers()) c = builder.to_coils() self.assertEqual(_coils1, c) builder = BinaryPayloadBuilder([b'\x12', b'\x34', b'\x56', b'\x78'], byteorder=Endian.Big) self.assertEqual(b'\x12\x34\x56\x78', builder.to_string()) self.assertEqual([4660, 22136], builder.to_registers()) self.assertEqual('\x12\x34\x56\x78', str(builder)) c = builder.to_coils() self.assertEqual(_coils2, c)
def testPayloadBuilderWithRawPayload(self): """ Test basic bit message encoding/decoding """ _coils1 = [ False, False, True, True, False, True, False, False, False, False, False, True, False, False, True, False, False, True, True, True, True, False, False, False, False, True, False, True, False, True, True, False ] _coils2 = [ False, False, False, True, False, False, True, False, False, False, True, True, False, True, False, False, False, True, False, True, False, True, True, False, False, True, True, True, True, False, False, False ] builder = BinaryPayloadBuilder([b'\x12', b'\x34', b'\x56', b'\x78'], repack=True) self.assertEqual(b'\x12\x34\x56\x78', builder.to_string()) self.assertEqual([13330, 30806], builder.to_registers()) c = builder.to_coils() self.assertEqual(_coils1, c) builder = BinaryPayloadBuilder([b'\x12', b'\x34', b'\x56', b'\x78'], byteorder=Endian.Big) self.assertEqual(b'\x12\x34\x56\x78', builder.to_string()) self.assertEqual([4660, 22136], builder.to_registers()) self.assertEqual('\x12\x34\x56\x78', str(builder)) c = builder.to_coils() self.assertEqual(_coils2, c)
def convert(self, config, data): byte_order = config["byteOrder"] if config.get("byteOrder") else "LITTLE" if byte_order == "LITTLE": builder = BinaryPayloadBuilder(byteorder=Endian.Little) elif byte_order == "BIG": builder = BinaryPayloadBuilder(byteorder=Endian.Big) else: log.warning("byte order is not BIG or LITTLE") return reg_count = config.get("registerCount", 1) value = config["value"] if config.get("tag") is not None: tags = (findall('[A-Z][a-z]*', config["tag"])) if "Coil" in tags: builder.add_bits(value) elif "String" in tags: builder.add_string(value) elif "Double" in tags: if reg_count == 4: builder.add_64bit_float(value) else: log.warning("unsupported amount of registers with double type for device %s in Downlink converter", self.__config["deviceName"]) return elif "Float" in tags: if reg_count == 2: builder.add_32bit_float(value) else: log.warning("unsupported amount of registers with float type for device %s in Downlink converter", self.__config["deviceName"]) return elif "Integer" in tags or "DWord" in tags or "DWord/Integer" in tags or "Word" in tags: if reg_count == 1: builder.add_16bit_int(value) elif reg_count == 2: builder.add_32bit_int(value) elif reg_count == 4: builder.add_64bit_int(value) else: log.warning("unsupported amount of registers with integer/word/dword type for device %s in Downlink converter", self.__config["deviceName"]) return else: log.warning("unsupported hardware data type for device %s in Downlink converter", self.__config["deviceName"]) if config.get("bit") is not None: bits = [0 for _ in range(8)] bits[config["bit"]-1] = int(value) log.debug(bits) builder.add_bits(bits) return builder.to_string() if config["functionCode"] in [5, 15]: return builder.to_coils() elif config["functionCode"] in [6, 16]: return builder.to_registers() else: log.warning("Unsupported function code, for device %s in Downlink converter", self.__config["deviceName"]) return
#builder_di.add_bits([1,1,1,1,1,1,1,1]) # [heater,cooler,...] builder_co = BinaryPayloadBuilder() builder_co.add_bits([0, 0, 0, 0, 0, 0, 0, 0]) # temperature builder_hr = BinaryPayloadBuilder() builder_hr.add_8bit_int(70) # wanted to use input registers for temperature, but they are read only #builder_ir = BinaryPayloadBuilder() #builder_ir.add_8bit_int(70) #di_block = ModbusSequentialDataBlock(0x01, builder_di.to_coils()) co_block = ModbusSequentialDataBlock(0x101, builder_co.to_coils()) hr_block = ModbusSequentialDataBlock(0x201, builder_hr.to_registers()) #ir_block = ModbusSequentialDataBlock(0x301, builder_ir.to_registers()) #store = ModbusSlaveContext(di=di_block, co=co_block, hr=hr_block, ir=ir_block) store = ModbusSlaveContext(co=co_block, hr=hr_block) context = ModbusServerContext(slaves=store, single=True) identity = ModbusDeviceIdentification() identity.VendorName = 'Pymodbus' identity.ProductCode = 'PM' identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' identity.ProductName = 'Pymodbus Server' identity.ModelName = 'Pymodbus Server' identity.MajorMinorRevision = '2.2.0'
def _build_payload( value: int | float, obj: ModbusObj ) -> int | list[int | bytes | bool]: """ # TODO make 4 decoders for all combinations in bo, wo and use them? Args: value: Value to write in object. obj: Object instance. Returns: Built payload. """ scaled = int(value / obj.scale - obj.offset) # Scaling # In `pymodbus` example INT and UINT values presented by hex values. # value = hex(value) if obj.data_type in {DataType.INT, DataType.UINT} else value if obj.data_type is ModbusDataType.BOOL and obj.data_length in {1, 16}: # scaled = [scaled] + [0] * 7 return int(bool(scaled)) builder = BinaryPayloadBuilder(byteorder=obj.byte_order, wordorder=obj.word_order) build_funcs = { # 1: {DataType.BOOL: builder.add_bits}, 8: { ModbusDataType.INT: builder.add_8bit_int, ModbusDataType.UINT: builder.add_8bit_uint, # DataType.BOOL: builder.add_bits, }, 16: { ModbusDataType.INT: builder.add_16bit_int, ModbusDataType.UINT: builder.add_16bit_uint, ModbusDataType.FLOAT: builder.add_16bit_float, # DataType.BOOL: builder.add_bits, }, 32: { ModbusDataType.INT: builder.add_32bit_int, ModbusDataType.UINT: builder.add_32bit_uint, ModbusDataType.FLOAT: builder.add_32bit_float, }, 64: { ModbusDataType.INT: builder.add_64bit_int, ModbusDataType.UINT: builder.add_64bit_uint, ModbusDataType.FLOAT: builder.add_64bit_float, }, } assert build_funcs[obj.data_length][obj.data_type] is not None build_funcs[obj.data_length][obj.data_type](scaled) # FIXME: string not support now payload = builder.to_coils() if obj.is_coil else builder.to_registers() _LOG.debug( "Encoded", extra={ "object": obj, "value_raw": value, "value_scaled": scaled, "value_encoded": payload, }, ) return payload