Search code examples
pythonpython-3.xmodbuspymodbus

PYModbus can't replicate Modpoll register read


I have attempted many of the fixes related to pymodpoll that exist on this platform. I am able to successfully write to the register but I am unable to read from it, I have confirmed that the register I am attempting to read from is in fact a RW register. Datasheet of the product.

The mod poll command that works properly for reading the register is this modpoll -m rtu -0 -1 -a 1 -b 9600 -p none -r 48 /dev/ttyUSB0

    from pymodbus.client import ModbusSerialClient as modbus
    #Connection to the modbus
    def connect(self) -> None:
        self.modbus = modbus(method='rtu', 
                            port="/dev/ttyUSB0", 
                            baudrate=9600,
                            stopbits=1,
                            bytesize=8,
                            timeout=1)
        self.modbus.connect()

    #function that works properly for setting the register value
    def set_voltage(self, voltage:float =0) -> None:
        if (voltage < self.min_volt) or (voltage > self.max_volt):
            raise modbusError(
                "Invalid voltage provided to the interface, voltage provided: {0}"
                .format(voltage))
        self.modbus.write_register(0x0030, int(voltage*100), unit=1)

    #Read register function
    def get_voltage_target(self) -> float:
        reg =  self.modbus.read_holding_registers(0x0030, 1, unit=1)
        print(reg.registers)

Output:

AttributeError: 'ModbusIOException' object has no attribute 'registers'

I receive this error from the reg.registers print, I am assuming this is just from the fact that I am not connecting properly to the modbus to read the proper registers.

This is the code I am currently working with, thanks for the help!


Simplified version Edit:

from pymodbus.client import ModbusSerialClient as RTUClient
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)

PowerSupplyMB = RTUClient(method='rtu', port="/dev/ttyUSB0", baudrate=9600,stopbits=1,bytesize=8,timeout=1)
PowerSupplyMB.connect()
PowerSupplyMB.write_register(0x0030, int(10.2*100), unit=1)
mb_response  = PowerSupplyMB.read_holding_registers(0x0030, 1, unit=1)

if not mb_response.isError():
    '''isError() method implemented in pymodbus 1.4.0 and above'''
    print(mb_response.registers)  # Your problem is here.

else:
    # Do stuff for error handling.
    print('Error message: {}'.format(mb_response))


Output:

DEBUG:pymodbus.logging:Current transaction state - IDLE
DEBUG:pymodbus.logging:Running transaction 1
DEBUG:pymodbus.logging:SEND: 0x0 0x3 0x0 0x30 0x0 0x1 0x85 0xd4
DEBUG:pymodbus.logging:New Transaction state "SENDING"
DEBUG:pymodbus.logging:Changing transaction state from "SENDING" to "WAITING FOR REPLY"
DEBUG:pymodbus.logging:Transaction failed. (Modbus Error: [Invalid Message] No response received, expected at least 4 bytes (0 received))
DEBUG:pymodbus.logging:Frame - [b''] not ready
DEBUG:pymodbus.logging:Getting transaction 0
DEBUG:pymodbus.logging:Changing transaction state from "PROCESSING REPLY" to "TRANSACTION_COMPLETE"
Error message: Modbus Error: [Input/Output] Modbus Error: [Invalid Message] No response received, expected at least 4 bytes (0 received)

Further investigation showed that registers contains an error - Modbus Error: [Input/Output] No Response received from the remote slave/Unable to decode response.


Solution

  • Your modpoll command includes -a 1 (Slave address = 1) but looking at the debugging info the request is being sent to slave 0 ("0x0 0x3 0x0 0x30 0x0 0x1 0x85 0xd4") so that would explain the lack of response.

    From the docs the function definition is read_holding_registers(address: int, count: int = 1, slave: int = 0, **kwargs: Any) → ModbusResponse; in your code you say unit=1 not slave=1... (I did not pick this up because you said the write_register works; it may well do so because you are writing to the broadcast address 0 but you cannot read using that address).