Search code examples
pythondecodemodbusmodbus-tcp

Why can't read the correct data in python with modbus?


I am trying to get data from a power network meter (https://www.lumel.com.pl/resources/Pliki%20do%20pobrania/ND25/ND25_service_manual_Interface.pdf), but the data I get isn't "understandable" for me. I get some UINT16 values (checked in wireshark), but they aren't good values.

Here is the code:

import time
from pyModbusTCP.client import ModbusClient

slave_adress = '192.168.1.10'
port = 502
unit_id = 2

modbus_clinet = ModbusClient(host=slave_adress, port=port, unit_id=unit_id, auto_open=True)

if __name__ == '__main__':
    while True:
        regs = modbus_clinet.read_holding_registers(reg_addr=0x1772, reg_nb=16)
        if regs:
            print(regs)
        else:
            print("baj van")
        time.sleep(2)

here are the print values:

[16640, 0, 16384, 0, 17359, 32768, 16544, 0, 16448, 0, 17096, 0, 0, 0, 16384, 0]

from the documentation writes something else.

Tried difference python modbus modules


Solution

  • Those actually ARE the correct values. The information you've missed is that these are single-precision floating point values, being sent to you as pairs of 16-bit integers, which is all ModBus supports. The first two values in hex are 0x4100 and 0, and 0x41000000 is the floating point value 8.0, which is the default for register 46003 as you have requested.

    Try this:

    >>> x = [16640, 0, 16384, 0, 17359, 32768, 16544, 0, 16448, 0, 17096, 0, 0, 0, 16384, 0]
    >>> import struct
    >>> print(struct.unpack('>8f',struct.pack('>16H',*x)))
    (8.0, 2.0, 415.0, 5.0, 3.0, 100.0, 0.0, 2.0)
    >>> 
    

    Those match the documentation. Note that both the encoding and decoding need to be big-endian.