Skip to content

Commit a1c14c7

Browse files
committed
Merge branch 'dev'
2 parents b34fa5e + 378bd5f commit a1c14c7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1908
-2945
lines changed

.github/workflows/ci.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ jobs:
3636
fail-fast: false
3737
matrix:
3838
os: [ubuntu-latest, macos-latest, windows-latest]
39-
python: ['3.9', '3.10', '3.11', '3.12']
39+
python: ['3.9', '3.10', '3.11', '3.12', "3.13"]
4040
include:
4141
- python: '3.9'
4242
run_lint: true
43-
- python: '3.12'
43+
- python: '3.13'
4444
run_doc: true
4545
run_lint: true
4646
- os: macos-latest
@@ -113,13 +113,13 @@ jobs:
113113
ruff check .
114114
115115
- name: pytest
116-
if: ${{ (matrix.os != 'ubuntu-latest') || (matrix.python != '3.12') }}
116+
if: ${{ (matrix.os != 'ubuntu-latest') || (matrix.python != '3.13') }}
117117
run: |
118118
env
119119
pytest
120120
121121
- name: pytest coverage
122-
if: ${{ (matrix.os == 'ubuntu-latest') && (matrix.python == '3.12') }}
122+
if: ${{ (matrix.os == 'ubuntu-latest') && (matrix.python == '3.13') }}
123123
run: |
124124
env
125125
pytest --cov

AUTHORS.rst

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Pymodbus version 3 family
1010
-------------------------
1111
Thanks to
1212

13+
- ahcm-dev
1314
- AKJ7
1415
- Alex
1516
- Alex Ruddick
@@ -58,13 +59,12 @@ Thanks to
5859
- julian
5960
- Justin Standring
6061
- Kenny Johansson
61-
- Martyy
62-
- Matthias Straka
62+
- Kürşat Aktaş
6363
- laund
6464
- Logan Gunthorpe
6565
- Marko Luther
66-
- Logan Gunthorpe
67-
- Marko Luther
66+
- Martyy
67+
- Máté Szabó
6868
- Matthias Straka
6969
- Matthias Urlichs
7070
- Michel F

CHANGELOG.rst

+34-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,40 @@ helps make pymodbus a better product.
77

88
:ref:`Authors`: contains a complete list of volunteers have contributed to each major version.
99

10+
Version 3.7.4
11+
-------------
12+
* Clean PDU init. (#2399)
13+
* Wrong close, when transaction do not match. (#2401)
14+
* Remove unmaintained (not working) example contributions. (#2400)
15+
* All pdu (incl. function code) tests to pdu directory. (#2397)
16+
* Add `no_response_expected` argument to requests (#2385)
17+
* Resubmit: Don't close/reopen tcp connection on single modbus message timeout (#2350)
18+
* 100% test coverage for PDU. (#2394)
19+
* Type DecodePDU. (#2392)
20+
* Update to use DecodePDU. (#2391)
21+
* Client/Server decoder renamed and moved to pdu. (#2390)
22+
* Move client/server decoder to pdu. (#2388)
23+
* Introducing PyModbus Guru on Gurubase.io (#2387)
24+
* Remove IllegalFunctionRequest. (#2384)
25+
* remove ModbusResponse. (#2383)
26+
* Add typing to pdu base classes. (#2380)
27+
* Updated roadmap.
28+
* remove databuffer from framer. (#2379)
29+
* Improve retries for sync client. (#2377)
30+
* Move process test to framer tests (#2376)
31+
* Framer do not check ids (#2375)
32+
* Remove callback from framer. (#2374)
33+
* Auto fill device ids for clients. (#2372)
34+
* Reenable multidrop tests. (#2370)
35+
* write_register/s accept bytes or int. (#2369)
36+
* roadmap corrections.
37+
* Added roadmap (not written in stone). (#2367)
38+
* Update README to show python 3.13.
39+
* Test on Python 3.13 (#2366)
40+
* Use @abstractmethod (#2365)
41+
* Corrected smaller documentation bugs. (#2364)
42+
* README as landing page in readthedocs. (#2363)
43+
1044
Version 3.7.3
1145
-------------
1246
* 100% test coverage of framers (#2359)
@@ -44,7 +78,6 @@ Version 3.7.3
4478
* fixed type hints for write_register and write_registers (#2309)
4579
* Remove _header from framers. (#2305)
4680

47-
4881
Version 3.7.2
4982
-------------
5083
* Correct README

MAKE_RELEASE.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ Prepare/make release on dev.
1414
* Control / Update API_changes.rst
1515
* Update CHANGELOG.rst
1616
* Add commits from last release, but selectively !
17-
git log --oneline v3.7.3..HEAD > commit.log
18-
git log --pretty="%an" v3.7.3..HEAD | sort -uf > authors.log
17+
git log --oneline v3.7.4..HEAD > commit.log
18+
git log --pretty="%an" v3.7.4..HEAD | sort -uf > authors.log
1919
update AUTHORS.rst and CHANGELOG.rst
20+
update roadmap.rst
2021
cd doc; ./build_html
2122
* rm -rf build/* dist/*
2223
* python3 -m build

README.rst

+6-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ PyModbus - A Python Modbus Stack
88
.. image:: https://pepy.tech/badge/pymodbus
99
:target: https://pepy.tech/project/pymodbus
1010
:alt: Downloads
11+
.. image:: https://img.shields.io/badge/Gurubase-Ask%20PyModbus%20Guru-006BFF
12+
:target: https://gurubase.io/g/pymodbus
13+
:alt: PyModbus Guru
1114

12-
Pymodbus is a full Modbus protocol implementation offering client/server with synchronous/asynchronous API a well as simulators.
15+
Pymodbus is a full Modbus protocol implementation offering client/server with synchronous/asynchronous API and simulators.
1316

1417
Our releases is defined as X.Y.Z, and we have strict rules what to release when:
1518

@@ -23,7 +26,7 @@ Upgrade examples:
2326
- 3.6.1 -> 3.7.0: Smaller changes to the pymodbus calls might be needed
2427
- 2.5.4 -> 3.0.0: Major changes in the application might be needed
2528

26-
Current release is `3.7.3 <https://github.com/pymodbus-dev/pymodbus/releases/tag/v3.7.3>`_.
29+
Current release is `3.7.4 <https://github.com/pymodbus-dev/pymodbus/releases/tag/v3.7.4>`_.
2730

2831
Bleeding edge (not released) is `dev <https://github.com/pymodbus-dev/pymodbus/tree/dev>`_.
2932

@@ -57,7 +60,7 @@ Common features
5760
* very lightweight project
5861
* requires Python >= 3.9
5962
* thorough test suite, that test all corners of the library
60-
* automatically tested on Windows, Linux and MacOS combined with python 3.9 - 3.12
63+
* automatically tested on Windows, Linux and MacOS combined with python 3.9 - 3.13
6164
* strongly typed API (py.typed present)
6265

6366
The modbus protocol specification: Modbus_Application_Protocol_V1_1b3.pdf can be found on

doc/index.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ Please select a topic in the left hand column.
88
:caption: Contents:
99
:hidden:
1010

11-
source/readme
1211
source/api_changes
1312
source/client
1413
source/server
@@ -17,5 +16,7 @@ Please select a topic in the left hand column.
1716
source/examples
1817
source/authors
1918
source/changelog
20-
source/api_changes
2119
source/internals
20+
source/roadmap
21+
22+
.. include:: ../README.rst

doc/source/README.rst

-1
This file was deleted.

doc/source/_static/examples.tgz

-4.78 KB
Binary file not shown.

doc/source/_static/examples.zip

-14 Bytes
Binary file not shown.

doc/source/client.rst

+13-6
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,14 @@ The line :mod:`result = await client.read_coils(2, 3, slave=1)` is an example of
166166

167167
The last line :mod:`client.close()` closes the connection and render the object inactive.
168168

169+
Retry logic for async clients
170+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
171+
172+
If no response is received to a request (call), it is retried (parameter retries) times, if not successful
173+
an exception response is returned, BUT the connection is not touched.
174+
175+
If 3 consequitve requests (calls) do not receive a response, the connection is terminated.
176+
169177
Development notes
170178
^^^^^^^^^^^^^^^^^
171179

@@ -191,14 +199,12 @@ The logical devices represented by the device is addressed with the :mod:`slave=
191199
With **Serial**, the comm port is defined when creating the object.
192200
The physical devices are addressed with the :mod:`slave=` parameter.
193201

194-
:mod:`slave=0` is used as broadcast in order to address all devices.
195-
However experience shows that modern devices do not allow broadcast, mostly because it is
196-
inheriently dangerous. With :mod:`slave=0` the application can get upto 254 responses on a single request,
197-
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.
198203

199-
The simple request calls (mixin) do NOT support broadcast, if an application wants to use broadcast
200-
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.
201205

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`
202208

203209

204210
Client response handling
@@ -227,6 +233,7 @@ And in case of read retrieve the data depending on type of request
227233
- :mod:`rr.bits` is set for coils / input_register requests
228234
- :mod:`rr.registers` is set for other requests
229235

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

231238
Client interface classes
232239
------------------------

doc/source/library/pymodbus.rst

+5-5
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ Extra functions
2121
:undoc-members:
2222
:show-inheritance:
2323

24-
.. automodule:: pymodbus.factory
25-
:members:
26-
:undoc-members:
27-
:show-inheritance:
28-
2924
.. automodule:: pymodbus.payload
3025
:members:
3126
:undoc-members:
@@ -45,6 +40,11 @@ Extra functions
4540
PDU classes
4641
===========
4742

43+
.. automodule:: pymodbus.pdu.decoders
44+
:members:
45+
:undoc-members:
46+
:show-inheritance:
47+
4848
.. automodule:: pymodbus.pdu.bit_read_message
4949
:members:
5050
:undoc-members:

doc/source/repl.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ Pymodbus REPL (Read Evaluate Print Loop)
33

44
.. raw:: html
55

6-
<p style="color: red;"><strong>Warning:</strong> The Pymodbus REPL documentation is not updated.</p>
6+
<p style="color: red;"><strong>Warning:</strong> The Pymodbus REPL documentation is not updated,
7+
because it lives in a different repo.</p>
78

89
Installation
910
------------

doc/source/roadmap.rst

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
Roadmap
2+
=======
3+
4+
The roadmap is not a finite plan, but merely an expression of intentions !
5+
6+
Pymodbus development is mainly driven by contributors, who have an itch, and provide a solution for the community.
7+
The maintainers are very open to these pull request, and ONLY work to secure that:
8+
9+
- it does not break existing usage/functionality (PR put on hold for next API change release)
10+
- it is a generic feature (e.g. not just for serial 9.600 bps)
11+
- it have proper test cases, to ensure against side effects.
12+
13+
It is important to note the maintainer do NOT reject ANY pull request that emcompases the above criteria.
14+
It is the community that decides how pymodbus evolves NOT the maintainers !
15+
16+
The following bullet points are what the maintainers focus on:
17+
18+
- 3.7.5, bug fix release, hopefully with:
19+
- Simplify PDU classes
20+
- Simplify transaction manager (central control point)
21+
- Remove ModbusControlBlock
22+
- 3.7.6, bug fix release, with:
23+
- Not planned
24+
- 3.8.0, with:
25+
- new transaction handling
26+
- transaction 100% coverage
27+
- skip_encode, zero_mode parameters removed
28+
- 4.0.0, with:
29+
- client async with sync/async API
30+
- Only one datastore, but with different API`s
31+
- Simulator standard in server
32+
- GUI client, to analyze devices
33+
- GUI server, to simulate devices
34+
35+
All contributions are WELCOME, and we (the maintainers) are always open to talk about ideas,
36+
best way is via `discussions <https://github.com/pymodbus-dev/pymodbus/discussions>`_ on github.
37+
38+
We have lately decided, that we do strictly follow the `modbus org <https://modbus.org>`_ standard,
39+
but we also accept vendor specific (like Huawei) pull requests, as long as they extend the standard or are actitvated with
40+
a specific argument like --huawei.

examples/client_custom_msg.py

+14-12
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
from pymodbus import FramerType
1717
from pymodbus.client import AsyncModbusTcpClient as ModbusClient
18-
from pymodbus.pdu import ModbusExceptions, ModbusRequest, ModbusResponse
18+
from pymodbus.pdu import ModbusExceptions, ModbusPDU
1919
from pymodbus.pdu.bit_read_message import ReadCoilsRequest
2020

2121

@@ -26,19 +26,20 @@
2626
# Since the function code is already registered with the decoder factory,
2727
# this will be decoded as a read coil response. If you implement a new
2828
# method that is not currently implemented, you must register the request
29-
# and response with a ClientDecoder factory.
29+
# and response with the active DecodePDU object.
3030
# --------------------------------------------------------------------------- #
3131

3232

33-
class CustomModbusResponse(ModbusResponse):
33+
class CustomModbusPDU(ModbusPDU):
3434
"""Custom modbus response."""
3535

3636
function_code = 55
3737
_rtu_byte_count_pos = 2
3838

3939
def __init__(self, values=None, slave=1, transaction=0, skip_encode=False):
4040
"""Initialize."""
41-
ModbusResponse.__init__(self, slave, transaction, skip_encode)
41+
super().__init__()
42+
super().setData(slave, transaction, skip_encode)
4243
self.values = values or []
4344

4445
def encode(self):
@@ -62,15 +63,16 @@ def decode(self, data):
6263
self.values.append(struct.unpack(">H", data[i : i + 2])[0])
6364

6465

65-
class CustomModbusRequest(ModbusRequest):
66+
class CustomRequest(ModbusPDU):
6667
"""Custom modbus request."""
6768

6869
function_code = 55
6970
_rtu_frame_size = 8
7071

7172
def __init__(self, address=None, slave=1, transaction=0, skip_encode=False):
7273
"""Initialize."""
73-
ModbusRequest.__init__(self, slave, transaction, skip_encode)
74+
super().__init__()
75+
super().setData(slave, transaction, skip_encode)
7476
self.address = address
7577
self.count = 16
7678

@@ -89,7 +91,7 @@ def execute(self, context):
8991
if not context.validate(self.function_code, self.address, self.count):
9092
return self.doException(ModbusExceptions.IllegalAddress)
9193
values = context.getValues(self.function_code, self.address, self.count)
92-
return CustomModbusResponse(values)
94+
return CustomModbusPDU(values)
9395

9496

9597
# --------------------------------------------------------------------------- #
@@ -122,18 +124,18 @@ async def main(host="localhost", port=5020):
122124
await client.connect()
123125

124126
# create a response object to control it works
125-
CustomModbusResponse()
127+
CustomModbusPDU()
126128

127129
# new modbus function code.
128-
client.register(CustomModbusResponse)
130+
client.register(CustomModbusPDU)
129131
slave=1
130-
request = CustomModbusRequest(32, slave=slave)
131-
result = await client.execute(request)
132+
request = CustomRequest(32, slave=slave)
133+
result = await client.execute(False, request)
132134
print(result)
133135

134136
# inherited request
135137
request = Read16CoilsRequest(32, slave)
136-
result = await client.execute(request)
138+
result = await client.execute(False, request)
137139
print(result)
138140

139141

0 commit comments

Comments
 (0)