Skip to content

Commit 1e8c9d9

Browse files
authored
add API to set max until disconnect. (#2521)
1 parent dad9704 commit 1e8c9d9

File tree

4 files changed

+39
-11
lines changed

4 files changed

+39
-11
lines changed

pymodbus/client/base.py

+28
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,20 @@ def execute(self, no_response_expected: bool, request: ModbusPDU):
8383
raise ConnectionException(f"Not connected[{self!s}]")
8484
return self.ctx.execute(no_response_expected, request)
8585

86+
def set_max_no_responses(self, max_count: int) -> None:
87+
"""Override default max no request responses.
88+
89+
:param max_count: Max aborted requests before disconnecting.
90+
91+
The parameter retries defines how many times a request is retried
92+
before being aborted. Once aborted a counter is incremented, and when
93+
this counter is greater than max_count the connection is terminated.
94+
95+
.. tip::
96+
When a request is successful the count is reset.
97+
"""
98+
self.ctx.max_until_disconnect = max_count
99+
86100
async def __aenter__(self):
87101
"""Implement the client with enter block.
88102
@@ -185,6 +199,20 @@ def execute(self, no_response_expected: bool, request: ModbusPDU) -> ModbusPDU:
185199
raise ConnectionException(f"Failed to connect[{self!s}]")
186200
return self.transaction.sync_execute(no_response_expected, request)
187201

202+
def set_max_no_responses(self, max_count: int) -> None:
203+
"""Override default max no request responses.
204+
205+
:param max_count: Max aborted requests before disconnecting.
206+
207+
The parameter retries defines how many times a request is retried
208+
before being aborted. Once aborted a counter is incremented, and when
209+
this counter is greater than max_count the connection is terminated.
210+
211+
.. tip::
212+
When a request is successful the count is reset.
213+
"""
214+
self.transaction.max_until_disconnect = max_count
215+
188216
# ----------------------------------------------------------------------- #
189217
# Internal methods
190218
# ----------------------------------------------------------------------- #

pymodbus/transaction/transaction.py

+9-10
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ def __init__(
5353
self.trace_packet = trace_packet or self.dummy_trace_packet
5454
self.trace_pdu = trace_pdu or self.dummy_trace_pdu
5555
self.trace_connect = trace_connect or self.dummy_trace_connect
56-
self.accept_no_response_limit = retries + 3
57-
self.count_no_responses = 0
56+
self.max_until_disconnect = self.count_until_disconnect = retries + 3
5857
if sync_client:
5958
self.sync_client = sync_client
6059
self._sync_lock = RLock()
@@ -109,12 +108,12 @@ def sync_execute(self, no_response_expected: bool, request: ModbusPDU) -> Modbus
109108
return self.sync_get_response()
110109
except asyncio.exceptions.TimeoutError:
111110
count_retries += 1
112-
if self.count_no_responses >= self.accept_no_response_limit:
111+
if self.count_until_disconnect < 0:
113112
self.connection_lost(asyncio.TimeoutError("Server not responding"))
114113
raise ModbusIOException(
115-
f"ERROR: No response received of the last {self.accept_no_response_limit} request, CLOSING CONNECTION."
114+
"ERROR: No response received of the last requests (default: retries+3), CLOSING CONNECTION."
116115
)
117-
self.count_no_responses += 1
116+
self.count_until_disconnect -= 1
118117
txt = f"No response received after {self.retries} retries, continue with next request"
119118
Log.error(txt)
120119
raise ModbusIOException(txt)
@@ -141,16 +140,16 @@ async def execute(self, no_response_expected: bool, request: ModbusPDU) -> Modbu
141140
response = await asyncio.wait_for(
142141
self.response_future, timeout=self.comm_params.timeout_connect
143142
)
144-
self.count_no_responses = 0
143+
self.count_until_disconnect= self.max_until_disconnect
145144
return response
146145
except asyncio.exceptions.TimeoutError:
147146
count_retries += 1
148-
if self.count_no_responses >= self.accept_no_response_limit:
147+
if self.count_until_disconnect < 0:
149148
self.connection_lost(asyncio.TimeoutError("Server not responding"))
150149
raise ModbusIOException(
151-
f"ERROR: No response received of the last {self.accept_no_response_limit} request, CLOSING CONNECTION."
150+
"ERROR: No response received of the last requests (default: retries+3), CLOSING CONNECTION."
152151
)
153-
self.count_no_responses += 1
152+
self.count_until_disconnect -= 1
154153
txt = f"No response received after {self.retries} retries, continue with next request"
155154
Log.error(txt)
156155
raise ModbusIOException(txt)
@@ -175,7 +174,7 @@ def callback_new_connection(self):
175174

176175
def callback_connected(self) -> None:
177176
"""Call when connection is succcesfull."""
178-
self.count_no_responses = 0
177+
self.count_until_disconnect = self.max_until_disconnect
179178
self.next_tid = 0
180179
self.trace_connect(True)
181180

test/client/test_client.py

+1
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ async def test_client_modbusbaseclient(self):
368368
)
369369
client.register(pdu_bit.ReadCoilsResponse)
370370
assert str(client)
371+
client.set_max_no_responses(110)
371372
client.close()
372373

373374
async def test_client_connection_made(self):

test/client/test_client_sync.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ def test_tcp_client_repr(self):
188188
f"ipaddr={client.comm_params.host}, port={client.comm_params.port}, timeout={client.comm_params.timeout_connect}>"
189189
)
190190
assert repr(client) == rep
191-
191+
client.set_max_no_responses(110)
192192

193193
class TestSyncClientTls:
194194
"""Unittest for the pymodbus.client module."""

0 commit comments

Comments
 (0)