Skip to content

Commit 704929b

Browse files
mateshjaniversen
andauthored
Add no_response_expected argument to requests (#2385)
Co-authored-by: jan iversen <jancasacondor@gmail.com>
1 parent 1193758 commit 704929b

File tree

11 files changed

+196
-176
lines changed

11 files changed

+196
-176
lines changed

doc/source/_static/examples.tgz

9 Bytes
Binary file not shown.

doc/source/_static/examples.zip

3 Bytes
Binary file not shown.

doc/source/client.rst

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,12 @@ The logical devices represented by the device is addressed with the :mod:`slave=
199199
With **Serial**, the comm port is defined when creating the object.
200200
The physical devices are addressed with the :mod:`slave=` parameter.
201201

202-
:mod:`slave=0` is used as broadcast in order to address all devices.
203-
However experience shows that modern devices do not allow broadcast, mostly because it is
204-
inheriently dangerous. With :mod:`slave=0` the application can get upto 254 responses on a single request,
205-
and this is not handled with the normal API calls!
202+
:mod:`slave=0` is defined as broadcast in the modbus standard, but pymodbus treats is a normal device.
206203

207-
The simple request calls (mixin) do NOT support broadcast, if an application wants to use broadcast
208-
it must call :mod:`client.execute` and deal with the responses.
204+
If an application is expecting multiple responses to a broadcast request, it must call :mod:`client.execute` and deal with the responses.
209205

206+
If no response is expected to a request, the :mod:`no_response_expected=True` argument can be used
207+
in the normal API calls, this will cause the call to return imidiatble with :mod:`None`
210208

211209

212210
Client response handling
@@ -235,6 +233,7 @@ And in case of read retrieve the data depending on type of request
235233
- :mod:`rr.bits` is set for coils / input_register requests
236234
- :mod:`rr.registers` is set for other requests
237235

236+
Remark if using :mod:`no_response_expected=True` rr will always be None.
238237

239238
Client interface classes
240239
------------------------

examples/client_custom_msg.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,12 @@ async def main(host="localhost", port=5020):
128128
client.register(CustomModbusPDU)
129129
slave=1
130130
request = CustomRequest(32, slave=slave)
131-
result = await client.execute(request)
131+
result = await client.execute(False, request)
132132
print(result)
133133

134134
# inherited request
135135
request = Read16CoilsRequest(32, slave)
136-
result = await client.execute(request)
136+
result = await client.execute(False, request)
137137
print(result)
138138

139139

pymodbus/client/base.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,20 +83,16 @@ def close(self) -> None:
8383
"""Close connection."""
8484
self.ctx.close()
8585

86-
def execute(self, request: ModbusPDU):
86+
def execute(self, no_response_expected: bool, request: ModbusPDU):
8787
"""Execute request and get response (call **sync/async**).
8888
89-
:param request: The request to process
90-
:returns: The result of the request execution
91-
:raises ConnectionException: Check exception text.
92-
9389
:meta private:
9490
"""
9591
if not self.ctx.transport:
9692
raise ConnectionException(f"Not connected[{self!s}]")
97-
return self.async_execute(request)
93+
return self.async_execute(no_response_expected, request)
9894

99-
async def async_execute(self, request) -> ModbusPDU:
95+
async def async_execute(self, no_response_expected: bool, request) -> ModbusPDU | None:
10096
"""Execute requests asynchronously.
10197
10298
:meta private:
@@ -109,6 +105,9 @@ async def async_execute(self, request) -> ModbusPDU:
109105
async with self._lock:
110106
req = self.build_response(request)
111107
self.ctx.send(packet)
108+
if no_response_expected:
109+
resp = None
110+
break
112111
try:
113112
resp = await asyncio.wait_for(
114113
req, timeout=self.ctx.comm_params.timeout_connect
@@ -225,9 +224,10 @@ def idle_time(self) -> float:
225224
return 0
226225
return self.last_frame_end + self.silent_interval
227226

228-
def execute(self, request: ModbusPDU) -> ModbusPDU:
227+
def execute(self, no_response_expected: bool, request: ModbusPDU) -> ModbusPDU:
229228
"""Execute request and get response (call **sync/async**).
230229
230+
:param no_response_expected: The client will not expect a response to the request
231231
:param request: The request to process
232232
:returns: The result of the request execution
233233
:raises ConnectionException: Check exception text.
@@ -236,7 +236,7 @@ def execute(self, request: ModbusPDU) -> ModbusPDU:
236236
"""
237237
if not self.connect():
238238
raise ConnectionException(f"Failed to connect[{self!s}]")
239-
return self.transaction.execute(request)
239+
return self.transaction.execute(no_response_expected, request)
240240

241241
# ----------------------------------------------------------------------- #
242242
# Internal methods

0 commit comments

Comments
 (0)