-
Notifications
You must be signed in to change notification settings - Fork 1k
Closed
Description
Versions
- Python: 3.11.9
- OS: Windows
- Pymodbus: 3.6.8
- Modbus Hardware (if used): Keyence KV-7500
Pymodbus Specific
- Client: tcp
Description
This is my code with the library
from pymodbus.client import ModbusTcpClient as mb
client = mb('10.0.0.222')
client.connect()
result = client.read_holding_registers(4500, 2, 1)
num = mb.convert_from_registers(result.registers, mb.DATATYPE.FLOAT32)
print(num)
client.close()In /pymodbus/client/mixin.py under convert_from_registers()
Code
@classmethod
def convert_from_registers(
cls, registers: list[int], data_type: DATATYPE
) -> int | float | str:
"""Convert registers to int/float/str.
:param registers: list of registers received from e.g. read_holding_registers()
:param data_type: data type to convert to
:returns: int, float or str depending on "data_type"
:raises ModbusException: when size of registers is not 1, 2 or 4
"""
byte_list = bytearray()
for x in registers:
byte_list.extend(int.to_bytes(x, 2, "big"))
if data_type == cls.DATATYPE.STRING:
if byte_list[-1:] == b"\00":
byte_list = byte_list[:-1]
return byte_list.decode("utf-8")
if len(registers) != data_type.value[1]:
raise ModbusException(
f"Illegal size ({len(registers)}) of register array, cannot convert!"
)
return struct.unpack(f">{data_type.value[0]}", byte_list)[0]PLC floating point numbers use either double words (DWORD) or quad words (QWORD) and they are interpreted in reversed manner eg a case for DWORD: DM0 = 0x5678, DM1 = 0x1234. If we interpret these 2 DMs as a HEX 32 bit number, then it should be 0x12345678 and the same goes for a floating number be it 32bit or 64bit. So, it is necessary to rearrange the registers in the code above in a reversed manner. I did some change to your code and it seemed to return the correct floating number that I put in my PLC. Below is the corrected code:
@classmethod
def convert_from_registers(
cls, registers: list[int], data_type: DATATYPE
) -> int | float | str:
"""Convert registers to int/float/str.
:param registers: list of registers received from e.g. read_holding_registers()
:param data_type: data type to convert to
:returns: int, float or str depending on "data_type"
:raises ModbusException: when size of registers is not 1, 2 or 4
"""
byte_list = bytearray()
for x in reversed(registers): #change i made
byte_list.extend(int.to_bytes(x, 2, "big"))
if data_type == cls.DATATYPE.STRING:
if byte_list[-1:] == b"\00":
byte_list = byte_list[:-1]
return byte_list.decode("utf-8")
if len(registers) != data_type.value[1]:
raise ModbusException(
f"Illegal size ({len(registers)}) of register array, cannot convert!"
)
return struct.unpack(f">{data_type.value[0]}", byte_list)[0]Metadata
Metadata
Assignees
Labels
No labels