Search code examples
python-3.xpyserialmodbusmodbus-tcppymodbus

pymodbus: Modbus RTU read register call blocked & never woke up or Auto-reconnect to Modbus RTU device


I am trying to create Modbus RTU client which will read data from serial port using pymodbus library. I am able to connect to Modbus RTU running on COM2 in Windows10 & able to read data of different types like Int32, Float, etc.

Issue:

After some time I've disconnected my device & checked the status of ModbusClient. My client is connected to COM2 port & trying to read from the device which is not available & call for read_holding_registers blocked.

Environment:

Python: 3.6.5
pymodbus: 2.1.0
Windows: 10 64bit

According to me, it should throw an error something like below

[Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionRefusedError'>: Connection was refused by other side: 10061: No connection could be made because the target machine actively refused it.

OR

[Failure instance: Traceback (failure with no frames): <class 'pymodbus.exceptions.ConnectionException'>: Modbus Error: [Connection] Client is not connected

The above error I'm getting when disconnected from Modbus TCP device. But, there is no action done in case of Modbus RTU.

Below code handle connection lost & failed events:

from pymodbus.client.common import ModbusClientMixin
from twisted.internet import reactor, protocol

class CustomModbusClientFactory(protocol.ClientFactory, ModbusClientMixin):

    def buildProtocol(self, addr=None):
        modbusClientProtocol = CustomModbusClientProtocol()
        modbusClientProtocol.factory = self
        return modbusClientProtocol

    def clientConnectionLost(self, connector, reason):
        logger.critical("Connection lost with device running on {0}:{1}.".format(modbusTcpDeviceIP, modbusTcpDevicePort))
        logger.critical("Root Cause : {0}".format(reason))
        connector.connect()

    def clientConnectionFailed(self, connector, reason):
        logger.critical("Connection failed with device running on {0}:{1}.".format(modbusTcpDeviceIP, modbusTcpDevicePort))
        logger.critical("Root Cause : {0}".format(reason))
        connector.connect()

My complete code is given here : ModbusRTUClient.py

I've make sure availability of Modbus RTU device & raise an alerts if there is any issue with communication with device.

Does anyone have an idea how disconnection & re-connection of Modbus RTU device is handled ?

Any help would be appreciated.


Solution

  • You are confusing serial communications and TCP/IP ones. They are completely different. When using Modbus RTU, it works over serial lines (mostly it is RS-485 interface in industry, or RS-232 for configuration purposes).

    In TCP/IP you have a logical channel (TCP), which is responsible for self-diagnostics and dropping errors when trying to read/write to unconnected endpoint.

    With serial lines you just send the data to port (which is done regardless of whether someone on the other side is listening for it) and the only way to understand that your endpoint is down is timeout waiting for a reply.

    By the way, there are some point when no reply doesnt mean the device is offline - broadcast messages are an excellent example. For some modbus devices you can broadcast time information on slave 0 and no reply would be granted.

    Conclusion: with rtu devices there is no connect/disconnect procedure, you only speak in terms of request/reply.