1

I am trying to read holding registers over Modbus RTU with python. I can make it work with the minimalmodbus library, but not with the pymodbus library.

What has so far worked is the minimalmodbus library:

`import minimalmodbus

PORT='com5'
A_REGISTER = 40320
B_REGISTER  = 40321
OFFSET = 38001

A_REGISTER =A_REGISTER - OFFSET
B_REGISTER =B_REGISTER - OFFSET

#Set up instrument
instrument = minimalmodbus.Instrument(PORT,1,mode=minimalmodbus.MODE_RTU)

#Make the settings explicit
instrument.serial.baudrate = 19200        # Baud
instrument.serial.bytesize = 8
instrument.serial.parity   = minimalmodbus.serial.PARITY_EVEN
instrument.serial.stopbits = 1
instrument.serial.timeout  = 1          # seconds

#Good practice
instrument.close_port_after_each_call = True

instrument.clear_buffers_before_each_transaction = True

#Read temperatureas a float
#if you need to read a 16 bit register use instrument.read_register()
A_reg = instrument.read_float(A_REGISTER)

#Read the humidity
B_reg = instrument.read_float(B_REGISTER)

#Pront the values
print('The A register value is : %.1f deg C\r' % A_reg)
print('The B rgister value is: %.1f percent\r' % B_reg)
`

This works very well.

However when I try to connect to the exact same modbus slave, using the exact same physical setup, reading the same register, but using the pymodbus library, with the following code, it doesn't work:

`from pymodbus.client import ModbusSerialClient
from pymodbus.transaction import ModbusRtuFramer as ModbusFramer

client = ModbusSerialClient(
    framer=ModbusFramer,
    method='rtu',
    port='COM5',
    baudrate=19200,
    bytesize=8,
    parity="E",
    stopbits=1,
    retries = 5,
    timeout=1 
     )

client.strict = False
client.connect()

res = client.read_holding_registers(address=B_REGISTER, count=1, unit=1)
res.registers`

Most of the time I get the following error: ConnectionException: Modbus Error: [Connection] Failed to connect[ModbusSerialClient(<pymodbus.framer.rtu_framer.ModbusRtuFramer object at 0x0000021CE12F2EE0> baud[19200])]

But a few times I get [0]

Any good ideas? I have been reading quite a bit on Stackoverflow and other sources, but I can't figure out what I am doing wrong.

Jan
  • 11
  • 1
  • Hello Jan. Can you run the [pymodbus async client](https://pymodbus.readthedocs.io/en/latest/source/example/client_async.html) from the command line with the log option set to debug and post the results? Also, the offset value you are using seems a bit odd, what device are you connecting to? – Marcos G. Jan 04 '23 at 14:45

1 Answers1

0

thank you for the swift reply. Unfortunately I am not sure I know exactly how to follow your suggestions, but here goes, please bare with me.

When i run the following code

import asyncio
import logging
import os

# --------------------------------------------------------------------------- #
# import the various client implementations
# --------------------------------------------------------------------------- #
from examples.helper import get_commandline
from pymodbus.client import (
    AsyncModbusSerialClient,
    AsyncModbusTcpClient,
    AsyncModbusTlsClient,
    AsyncModbusUdpClient,
)


_logger = logging.getLogger()


def setup_async_client(args):
    if args.comm == "serial":
        client = AsyncModbusSerialClient(
            args.port,
            # Common optional paramers:
            #    framer=ModbusRtuFramer,
            #    timeout=10,
            #    retries=3,
            #    retry_on_empty=False,
            #    close_comm_on_error=False,
            #    strict=True,
            # Serial setup parameters
            #    baudrate=9600,
            #    bytesize=8,
            #    parity="N",
            #    stopbits=1,
            #    handle_local_echo=False,
        )
    return client


async def run_async_client(client, modbus_calls=None):
    """Run sync client."""
    _logger.info("### Client starting")
    await client.connect()
    assert client.protocol
    if modbus_calls:
        await modbus_calls(client)
    await client.close()
    _logger.info("### End of Program")


if __name__ == "__main__":
    cmd_args = get_commandline(
        server=False,
        description="Run asynchronous client.",
    )
    testclient = setup_async_client(cmd_args)
    asyncio.run(run_async_client(testclient), debug=True)

I get the following error

ModuleNotFoundError: No module named 'examples'

If I try to setup an async modbus serial client

from pymodbus.client import AsyncModbusSerialClient
from pymodbus.transaction import ModbusRtuFramer as ModbusFramer

client = AsyncModbusSerialClient(
    framer=ModbusFramer,
    method='rtu',
    port='COM5',
    baudrate=19200,
    bytesize=8,
    parity="E",
    stopbits=1,
    retries = 5,
    timeout=1,
    debug = True
    )

client.strict = False
client.connect()

res = client.read_holding_registers(address=B_REGISTER, count=1, unit=1)
res.registers

I get the following error

C:\Users\gen0238\AppData\Local\Temp\ipykernel_13700\1340640402.py:18: RuntimeWarning: coroutine 'AsyncModbusSerialClient.connect' was never awaited
  client.connect()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
---------------------------------------------------------------------------
ConnectionException                       Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_13700\1340640402.py in <module>
     18 client.connect()
     19 
---> 20 res = client.read_holding_registers(address=B_REGISTER, count=1, unit=1)
     21 res.registers

~\AppData\Roaming\Python\Python39\site-packages\pymodbus\client\mixin.py in read_holding_registers(self, address, count, slave, **kwargs)
    116             address, count, slave, **kwargs
    117         )
--> 118         return self.execute(request)
    119 
    120     def read_input_registers(

~\AppData\Roaming\Python\Python39\site-packages\pymodbus\client\base.py in execute(self, request)
    181         if self.use_protocol:
    182             if not self.protocol:
--> 183                 raise ConnectionException(f"Not connected[{str(self)}]")
    184             return self.protocol.execute(request)
    185         if not self.connect():

ConnectionException: Modbus Error: [Connection] Not connected[AsyncModbusSerialClient None:COM5]

About the offset; I am trying to connect to a mass spectrometer via its serial port. The thing is that if I set up a measured value to be stored on the device in the modbus holding register 40105 I need to acces that value from my modbus master at address 2104, but there is something modbus register/adress that I dont completely understand.

Jan
  • 11
  • 1
  • Hello Jan, that's ok, I can see the debug info you posted with the output of your code. The error you are getting means the serial port you are trying to use either does not exist or cannot be opened. Why are you using `COM5` instead of `com5` as for minimalmodubs. Anyway, the easiest thing to try is to switch to the synchronous client, just remove the `Async` from the import and client instantiation and you should be good to go. I don't think the async client is necessary for your configuration with just one device... – Marcos G. Jan 07 '23 at 10:16
  • 2
    If you want to know the correct names of your ports you can run the code provided in the first answer [here](https://stackoverflow.com/questions/12090503/listing-available-com-ports-with-python). I'm on Linux so when I run that script I get the name of my port as `['/dev/ttyUSB0']` – Marcos G. Jan 07 '23 at 10:23
  • 1
    You should [edit your original](https://stackoverflow.com/posts/75003596/edit) question to include this code and your results as this is not an answer. – import random Jan 10 '23 at 12:32