Search code examples
decodetranslatemodbuspymodbus

decode register to 32bit float big endian in python code on raspberry pi 3B with python library pymodbus2.5.3


I'm trying to get the data stream of a sensor transmitter that uses the modbus rtu communication protocol on my raspberry pi 3B. I'm able to get the data with the pymodbus2.5.3 library. For this I use this code:

from pymodbus.client.sync import ModbusSerialClient # Import the pymodbus library part for syncronous master (=client)

client = ModbusSerialClient(
    method='rtu', #Modbus Modus = RTU = via USB & RS485
    port='/dev/ttyUSB0', #Connected over ttyUSB0, not AMA0
    baudrate=19200, #Baudrate was changed from 38400 to 19200
    timeout=3, #
    parity='N', #Parity = None
    stopbits=2, #Bites was changed from 1 to 2
    bytesize=8 #
)

if client.connect():  # Trying to connect to Modbus Server/Slave
    #Reading from a holding register
    res = client.read_holding_registers(address=100, count=8, unit=1) #Startregister = 100, Registers to be read = 8, Answer size = 1 byte



    if not res.isError(): #If Registers don't show Error
        print(res.registers) #Print content of registers
    else:
        print(res) #Print Error Message, for meaning look at (insert git hub)

else: #If not able to connect, do this
    print('Cannot connect to the Transmitter M80 SM and Sensor InPro 5000i.')
    print('Please check the following things:')
    print('Does the RS485-to-USB Adapter have power? Which LEDs are active?')
    print('Are the cables connected correctly?')

And get the following output:

[15872, 17996, 16828, 15728, 16283, 45436, 16355, 63231]

With the help of the Modbus Poll and Slave Programms I know that those results should decoded be: [0.125268, --, 23.53, --, 1.21094, --, 1.77344, --]

To get to the right results I tried the command that the pymodbus github suggests .decode():

res.decode(word_order = little, byte_order = little, formatters = float64)

[I know that those aren't the needed options but I copied the suggested github code to check if it works.]

After putting the code segment into the code the changed part looks like this:

    if not res.isError(): #If Registers don't show Error
        res.decode(word_order = little, byte_order = little, formatters = float64)
        print(res.registers) #Print content of registers
    else:
        print(res) #Print Error Message, for meaning look at (insert git hub)

When I run this code, I get the following output, that traces to the decoding segment:

NameError: name 'little' is not defined

After this, I imported also the pymodbus part translation. But it showed the same output.

How can I decode my incoming data?


Solution

  • You can use BinaryPayloadDecoder to help decoding your payload, here is a simplified example, change Endian.Big and Endian.Little if needed.

    if client.connect():  # Trying to connect to Modbus Server/Slave
        #Reading from a holding register
        res = client.read_holding_registers(address=100, count=8, unit=1) #Startregister = 100, Registers to be read = 8, Answer size = 1 byte
    
        # ====== added code start ======
        decoder = BinaryPayloadDecoder.fromRegisters(res.registers, Endian.Little, wordorder=Endian.Little)
        first_reading = decoder.decode_32bit_float()
        second_reading = decoder.decode_32bit_float()
        # ====== added code end ======
    
        if not res.isError(): #If Registers don't show Error
            print(res.registers) #Print content of registers
        else:
            print(res) #Print Error Message, for meaning look at (insert git hub)
    

    Remember to import from pymodbus.payload import BinaryPayloadDecoder at top and add necessary exception handlers in your final code.

    Reference document: https://pymodbus.readthedocs.io/en/latest/source/library/pymodbus.html#pymodbus.payload.BinaryPayloadDecoder