pythonpyserialmodbusminimalmodbus

Trouble reading MODBUS register using Python


I am trying to use Python (PyCharm) to read a register on a modbus device. I have confirmed the COM port, Baud rate and other communication settings and I can use the devices application to read the value (it is a water level logger). I am getting no response from the instrument.

Register is readable in mbpoll using -

mbpoll -B -m RTU  -t 4:float -a 1 -b 19200 -r 46 -c 2 /dev/ttyUSB0

enter image description here (Address different as running on Pi not PC)

And MBPOLL - enter image description here enter image description here enter image description here

My code is as follows -

import minimalmodbus
import serial

instrument = minimalmodbus.Instrument('COM5', 1)  # port name, slave address (in decimal)
instrument.serial.port = 'COM5'                     # this is the serial port name
instrument.serial.baudrate = 19200         # Baud
instrument.serial.bytesize = 8
instrument.serial.parity   = serial.PARITY_EVEN
instrument.serial.stopbits = 1
instrument.serial.timeout  = 3          # seconds
instrument.address = 1                         # this is the slave address number
instrument.mode = minimalmodbus.MODE_RTU   # rtu or ascii mode
instrument.clear_buffers_before_each_transaction = True

temperature = instrument.read_float(registeraddress=40046, functioncode=3, number_of_registers=2, byteorder=0)  # Registernumber, number of decimals
print(temperature)
 

Error Received - enter image description here

import minimalmodbus
import serial

instrument = minimalmodbus.Instrument('COM5', 1)  # port name, slave address (in decimal)
instrument.serial.port = 'COM5'                     # this is the serial port name
instrument.serial.baudrate = 19200         # Baud
instrument.serial.bytesize = 8
instrument.serial.parity   = serial.PARITY_EVEN
instrument.serial.stopbits = 1
instrument.serial.timeout  = 0.1        # seconds
instrument.address = 1                         # this is the slave address number
instrument.mode = minimalmodbus.MODE_RTU   # rtu or ascii mode
#nstrument.clear_buffers_before_each_transaction = True

temperature = instrument.read_float(registeraddress=45, functioncode=4, number_of_registers=2, byteorder=0)  # Registernumber, number of decimals

try:
    print(temperature)
except:
    print(temperature)

Edit to include a try - except

Any help appreciated!

EDIT: Link to device manual - https://in-situ.com/en/pub/media/support/documents/Modbus_Manual.pdf Device is a Level Troll 400 Connected to PC via manufactures cable

EDIT 2: I have tried to incorporate minimal modbus structure but to no avail.

EDIT 3: I am able to read a register using Modbus Poll. Register is 40046, so I understand this to be register 45 of the holding registers? How do I translate this to minimalmodbus?

EDIT 4: I am not married to minimal modbus - I am happy to use any tool to get this done

EDIT 5: I have also tried depth = instrument.read_long(x, x) with different values


Solution

  • Just updating with the solution if anyone happens to stumble upon this and has the same problem. As semi-alluded to in other suggestions the device I am connecting to has a 'sleep' period or the like and needs to be polled once, unsuccessfully, before successfully returning values for any subsequent polls. I apologies for my armature code but the solution that works for me is the below -

    import minimalmodbus
    import serial
    
    instrument = minimalmodbus.Instrument('COM5', 1)  # port name, slave address (in decimal)
    instrument.serial.port = 'COM5'                     # this is the serial port name
    instrument.serial.baudrate = 19200         # Baud
    instrument.serial.bytesize = 8
    instrument.serial.parity   = serial.PARITY_EVEN
    instrument.serial.stopbits = 1
    instrument.serial.timeout  = 1        # seconds
    instrument.address = 1                         # this is the slave address number
    instrument.mode = minimalmodbus.MODE_RTU   # rtu or ascii mode
    #nstrument.clear_buffers_before_each_transaction = True
    try:
        temperature = instrument.read_long(registeraddress=9001, functioncode=3,
                                            byteorder=0)  # Registernumber, number of decimals
    
        print(temperature)
    
    
    except:
        pass
    
    try:
        temperature = instrument.read_long(registeraddress=9001, functioncode=3,
                                            byteorder=0)  # Registernumber, number of decimals
    
        print(temperature)
    
    
    except:
        pass