From 5c4bc734cf0921d7922929fb0b00d8b1c8b421a8 Mon Sep 17 00:00:00 2001 From: Andy Walker Date: Sat, 14 Sep 2024 20:04:53 +0100 Subject: [PATCH 1/2] Improve docs around sync clients and reconnection Sync clients don't do reconnection in the same way as async clients, and should have a little more explanation as to what they do. See issue #2320 --- doc/source/client.rst | 24 ++++++++++++++++++++---- pymodbus/client/serial.py | 14 ++++++-------- pymodbus/client/tcp.py | 14 ++++++-------- pymodbus/client/tls.py | 14 ++++++-------- pymodbus/client/udp.py | 14 ++++++-------- 5 files changed, 44 insertions(+), 36 deletions(-) diff --git a/doc/source/client.rst b/doc/source/client.rst index cec456a5b..f7c34e029 100644 --- a/doc/source/client.rst +++ b/doc/source/client.rst @@ -118,19 +118,32 @@ that a device have received the packet. Client usage ------------ Using pymodbus client to set/get information from a device (server) -is done in a few simple steps, like the following synchronous example:: +is done in a few simple steps. + +Synchronous example +^^^^^^^^^^^^^^^^^^^ + +:: from pymodbus.client import ModbusTcpClient client = ModbusTcpClient('MyDevice.lan') # Create client object - client.connect() # connect to device, reconnect automatically + client.connect() # connect to device client.write_coil(1, True, slave=1) # set information in device result = client.read_coils(2, 3, slave=1) # get information from device print(result.bits[0]) # use information client.close() # Disconnect device +The line :mod:`client.connect()` connects to the device (or comm port). If this cannot connect successfully within +the timeout it throws an exception. After this initial connection, further +calls to the same client (here, :mod:`client.write_coil(...)` and +:mod:`client.read_coils(...)` ) will check whether the client is still +connected, and automatically reconnect if not. -and a asynchronous example:: +Asynchronous example +^^^^^^^^^^^^^^^^^^^^ + +:: from pymodbus.client import AsyncModbusTcpClient @@ -141,7 +154,7 @@ and a asynchronous example:: print(result.bits[0]) # use information client.close() # Disconnect device -The line :mod:`client = AsyncModbusTcpClient('MyDevice.lan')` only creates the object it does not activate +The line :mod:`client = AsyncModbusTcpClient('MyDevice.lan')` only creates the object; it does not activate anything. The line :mod:`await client.connect()` connects to the device (or comm port), if this cannot connect successfully within @@ -153,6 +166,9 @@ The line :mod:`result = await client.read_coils(2, 3, slave=1)` is an example of The last line :mod:`client.close()` closes the connection and render the object inactive. +Usage notes +^^^^^^^^^^^ + Large parts of the implementation are shared between the different classes, to ensure high stability and efficient maintenance. diff --git a/pymodbus/client/serial.py b/pymodbus/client/serial.py index c48e9f43b..47f7846ad 100644 --- a/pymodbus/client/serial.py +++ b/pymodbus/client/serial.py @@ -123,15 +123,15 @@ class ModbusSerialClient(ModbusBaseSyncClient): :param stopbits: Number of stop bits 0-2. :param handle_local_echo: Discard local echo from dongle. :param name: Set communication name, used in logging - :param reconnect_delay: Minimum delay in seconds.milliseconds before reconnecting. - :param reconnect_delay_max: Maximum delay in seconds.milliseconds before reconnecting. + :param reconnect_delay: Not used in the sync client + :param reconnect_delay_max: Not used in the sync client :param timeout: Timeout for a connection request, in seconds. :param retries: Max number of retries per request. - .. tip:: - **reconnect_delay** doubles automatically with each unsuccessful connect, from - **reconnect_delay** to **reconnect_delay_max**. - Set `reconnect_delay=0` to avoid automatic reconnection. + Note that unlike the async client, the sync client does not perform + retries. If the connection has closed, the client will attempt to reconnect + once before executing each read/write request, and will raise a + ConnectionException if this fails. Example:: @@ -145,8 +145,6 @@ def run(): client.close() Please refer to :ref:`Pymodbus internals` for advanced usage. - - Remark: There are no automatic reconnect as with AsyncModbusSerialClient """ state = ModbusTransactionState.IDLE diff --git a/pymodbus/client/tcp.py b/pymodbus/client/tcp.py index ca40ae92a..190d8e98b 100644 --- a/pymodbus/client/tcp.py +++ b/pymodbus/client/tcp.py @@ -103,15 +103,15 @@ class ModbusTcpClient(ModbusBaseSyncClient): :param port: Port used for communication :param name: Set communication name, used in logging :param source_address: source address of client - :param reconnect_delay: Minimum delay in seconds.milliseconds before reconnecting. - :param reconnect_delay_max: Maximum delay in seconds.milliseconds before reconnecting. + :param reconnect_delay: Not used in the sync client + :param reconnect_delay_max: Not used in the sync client :param timeout: Timeout for a connection request, in seconds. :param retries: Max number of retries per request. - .. tip:: - **reconnect_delay** doubles automatically with each unsuccessful connect, from - **reconnect_delay** to **reconnect_delay_max**. - Set `reconnect_delay=0` to avoid automatic reconnection. + Note that unlike the async client, the sync client does not perform + retries. If the connection has closed, the client will attempt to reconnect + once before executing each read/write request, and will raise a + ConnectionException if this fails. Example:: @@ -125,8 +125,6 @@ async def run(): client.close() Please refer to :ref:`Pymodbus internals` for advanced usage. - - Remark: There are no automatic reconnect as with AsyncModbusTcpClient """ socket: socket.socket | None diff --git a/pymodbus/client/tls.py b/pymodbus/client/tls.py index deddd6bc2..aba914e19 100644 --- a/pymodbus/client/tls.py +++ b/pymodbus/client/tls.py @@ -120,15 +120,15 @@ class ModbusTlsClient(ModbusTcpClient): :param port: Port used for communication :param name: Set communication name, used in logging :param source_address: Source address of client - :param reconnect_delay: Minimum delay in seconds.milliseconds before reconnecting. - :param reconnect_delay_max: Maximum delay in seconds.milliseconds before reconnecting. + :param reconnect_delay: Not used in the sync client + :param reconnect_delay_max: Not used in the sync client :param timeout: Timeout for a connection request, in seconds. :param retries: Max number of retries per request. - .. tip:: - **reconnect_delay** doubles automatically with each unsuccessful connect, from - **reconnect_delay** to **reconnect_delay_max**. - Set `reconnect_delay=0` to avoid automatic reconnection. + Note that unlike the async client, the sync client does not perform + retries. If the connection has closed, the client will attempt to reconnect + once before executing each read/write request, and will raise a + ConnectionException if this fails. Example:: @@ -142,8 +142,6 @@ async def run(): client.close() Please refer to :ref:`Pymodbus internals` for advanced usage. - - Remark: There are no automatic reconnect as with AsyncModbusTlsClient """ def __init__( # pylint: disable=too-many-arguments diff --git a/pymodbus/client/udp.py b/pymodbus/client/udp.py index 48b71edab..9e6f733d4 100644 --- a/pymodbus/client/udp.py +++ b/pymodbus/client/udp.py @@ -103,15 +103,15 @@ class ModbusUdpClient(ModbusBaseSyncClient): :param port: Port used for communication. :param name: Set communication name, used in logging :param source_address: source address of client, - :param reconnect_delay: Minimum delay in seconds.milliseconds before reconnecting. - :param reconnect_delay_max: Maximum delay in seconds.milliseconds before reconnecting. + :param reconnect_delay: Not used in the sync client + :param reconnect_delay_max: Not used in the sync client :param timeout: Timeout for a connection request, in seconds. :param retries: Max number of retries per request. - .. tip:: - **reconnect_delay** doubles automatically with each unsuccessful connect, from - **reconnect_delay** to **reconnect_delay_max**. - Set `reconnect_delay=0` to avoid automatic reconnection. + Note that unlike the async client, the sync client does not perform + retries. If the connection has closed, the client will attempt to reconnect + once before executing each read/write request, and will raise a + ConnectionException if this fails. Example:: @@ -125,8 +125,6 @@ async def run(): client.close() Please refer to :ref:`Pymodbus internals` for advanced usage. - - Remark: There are no automatic reconnect as with AsyncModbusUdpClient """ socket: socket.socket | None From 565d5ea2f6761d79b143358acb579f85b2022b13 Mon Sep 17 00:00:00 2001 From: jan iversen Date: Tue, 24 Sep 2024 11:38:28 +0200 Subject: [PATCH 2/2] Corrections. --- doc/source/client.rst | 4 ++-- pymodbus/client/tcp.py | 9 +++++---- pymodbus/client/tls.py | 9 +++++---- pymodbus/client/udp.py | 9 +++++---- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/doc/source/client.rst b/doc/source/client.rst index f7c34e029..ec71e15b9 100644 --- a/doc/source/client.rst +++ b/doc/source/client.rst @@ -166,8 +166,8 @@ The line :mod:`result = await client.read_coils(2, 3, slave=1)` is an example of The last line :mod:`client.close()` closes the connection and render the object inactive. -Usage notes -^^^^^^^^^^^ +Development notes +^^^^^^^^^^^^^^^^^ Large parts of the implementation are shared between the different classes, to ensure high stability and efficient maintenance. diff --git a/pymodbus/client/tcp.py b/pymodbus/client/tcp.py index 190d8e98b..a17aa4f60 100644 --- a/pymodbus/client/tcp.py +++ b/pymodbus/client/tcp.py @@ -108,10 +108,11 @@ class ModbusTcpClient(ModbusBaseSyncClient): :param timeout: Timeout for a connection request, in seconds. :param retries: Max number of retries per request. - Note that unlike the async client, the sync client does not perform - retries. If the connection has closed, the client will attempt to reconnect - once before executing each read/write request, and will raise a - ConnectionException if this fails. + .. tip:: + Unlike the async client, the sync client does not perform + retries. If the connection has closed, the client will attempt to reconnect + once before executing each read/write request, and will raise a + ConnectionException if this fails. Example:: diff --git a/pymodbus/client/tls.py b/pymodbus/client/tls.py index aba914e19..f52cf9a83 100644 --- a/pymodbus/client/tls.py +++ b/pymodbus/client/tls.py @@ -125,10 +125,11 @@ class ModbusTlsClient(ModbusTcpClient): :param timeout: Timeout for a connection request, in seconds. :param retries: Max number of retries per request. - Note that unlike the async client, the sync client does not perform - retries. If the connection has closed, the client will attempt to reconnect - once before executing each read/write request, and will raise a - ConnectionException if this fails. + .. tip:: + Unlike the async client, the sync client does not perform + retries. If the connection has closed, the client will attempt to reconnect + once before executing each read/write request, and will raise a + ConnectionException if this fails. Example:: diff --git a/pymodbus/client/udp.py b/pymodbus/client/udp.py index 9e6f733d4..25fb7d20e 100644 --- a/pymodbus/client/udp.py +++ b/pymodbus/client/udp.py @@ -108,10 +108,11 @@ class ModbusUdpClient(ModbusBaseSyncClient): :param timeout: Timeout for a connection request, in seconds. :param retries: Max number of retries per request. - Note that unlike the async client, the sync client does not perform - retries. If the connection has closed, the client will attempt to reconnect - once before executing each read/write request, and will raise a - ConnectionException if this fails. + .. tip:: + Unlike the async client, the sync client does not perform + retries. If the connection has closed, the client will attempt to reconnect + once before executing each read/write request, and will raise a + ConnectionException if this fails. Example::