Skip to content

Commit 2071307

Browse files
committed
Merge branch 'dev'
2 parents 779967e + 1629f05 commit 2071307

Some content is hidden

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

42 files changed

+521
-1584
lines changed

.github/workflows/ci.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ jobs:
4040

4141
steps:
4242
- name: Checkout repo from github
43-
uses: actions/[email protected].0
43+
uses: actions/[email protected].1
4444

4545
- name: Set up Python ${{ matrix.python }}
46-
uses: actions/setup-python@v4.7.1
46+
uses: actions/setup-python@v5.0.0
4747
with:
4848
python-version: ${{ matrix.python }}
4949

@@ -61,7 +61,7 @@ jobs:
6161
6262
- name: Restore base Python virtual environment
6363
id: cache-venv
64-
uses: actions/cache@v3.3.2
64+
uses: actions/cache@v4.0.1
6565
with:
6666
path: ${{ env.VIRTUAL_ENV }}
6767
key: >-
@@ -117,15 +117,15 @@ jobs:
117117
runs-on: ubuntu-22.04
118118
timeout-minutes: 10
119119
steps:
120-
- uses: actions/checkout@v3
120+
- uses: actions/checkout@v4.1.1
121121

122-
- uses: github/codeql-action/init@v2
122+
- uses: github/codeql-action/init@v3
123123
with:
124124
languages: python
125125

126-
- uses: github/codeql-action/autobuild@v2
126+
- uses: github/codeql-action/autobuild@v3
127127

128-
- uses: github/codeql-action/analyze@v2
128+
- uses: github/codeql-action/analyze@v3
129129

130130
ci_complete:
131131
name: ci_complete

AUTHORS.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Thanks to
2020
- André Srinivasan
2121
- banana-sun
2222
- Blaise Thompson
23+
- CapraTheBest
2324
- cgernert
2425
- corollaries
2526
- Chandler Riehm
@@ -46,6 +47,7 @@ Thanks to
4647
- Joe Burmeister
4748
- Jonathan Reichelt Gjertsen
4849
- julian
50+
- Justin Standring
4951
- Kenny Johansson
5052
- Matthias Straka
5153
- laund

CHANGELOG.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,29 @@ 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.6.6
11+
-------------
12+
* Solve transport close() as not inherited method. (#2098)
13+
* enable `mypy --check-untyped-defs` (#2096)
14+
* Add get_expected_response_length to transaction.
15+
* Remove control encode in framersRemove control encode in framers. (#2095)
16+
* Bump codeql in CI to v3. (#2093)
17+
* Improve server types (#2092)
18+
* Remove pointless try/except (#2091)
19+
* Improve transport types (#2090)
20+
* Use explicit ValueError when called with incorrect function code (#2089)
21+
* update message tests (incorporate all old tests). (#2088)
22+
* Improve simulator type hints (#2084)
23+
* Cleanup dead resetFrame code (#2082)
24+
* integrate message.encode() into framer.buildPacket. (#2062)
25+
* Repair client close() (intern= is needed for ModbusProtocol). (#2080)
26+
* Updated Message_Parser example (#2079)
27+
* Fix #2069 use released repl from pypi (#2077)
28+
* Fix field encoding of Read File Record Response (#2075)
29+
* Improve simulator types (#2076)
30+
* Bump actions. (#2071)
31+
32+
1033
Version 3.6.5
1134
-------------
1235
* Update framers to ease message integration (only decode/encode) (#2064)

MAKE_RELEASE.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ 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.6.5..HEAD > commit.log
18-
git log --pretty="%an" v3.6.1..HEAD | sort -uf > authors.log
19-
update AUTHORS
17+
git log --oneline v3.6.6..HEAD > commit.log
18+
git log --pretty="%an" v3.6.6..HEAD | sort -uf > authors.log
19+
update AUTHORS.rst and CHANGELOG.rst
2020
cd doc; ./build_html
2121
* rm -rf build/* dist/*
22+
* git checkout build
2223
* python3 -m build
2324
* twine check dist/*
2425
* Commit, push and merge.

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ PyModbus - A Python Modbus Stack
1111

1212
Pymodbus is a full Modbus protocol implementation offering client/server with synchronous/asynchronous API a well as simulators.
1313

14-
Current release is `3.6.5 <https://github.com/pymodbus-dev/pymodbus/releases/tag/v3.6.5>`_.
14+
Current release is `3.6.6 <https://github.com/pymodbus-dev/pymodbus/releases/tag/v3.6.6>`_.
1515

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

doc/source/_static/examples.tgz

5.55 KB
Binary file not shown.

doc/source/_static/examples.zip

-10 Bytes
Binary file not shown.

examples/message_parser.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import logging
1212
import textwrap
1313

14+
from pymodbus import pymodbus_apply_logging_config
1415
from pymodbus.factory import ClientDecoder, ServerDecoder
1516
from pymodbus.transaction import (
1617
ModbusAsciiFramer,
@@ -80,15 +81,10 @@ def decode(self, message):
8081
print(f"{decoder.decoder.__class__.__name__}")
8182
print("-" * 80)
8283
try:
83-
decoder.addToFrame(message)
84-
if decoder.checkFrame():
85-
slave = decoder._header.get( # pylint: disable=protected-access
86-
"uid", 0x00
87-
)
88-
decoder.advanceFrame()
89-
decoder.processIncomingPacket(message, self.report, slave)
90-
else:
91-
self.check_errors(decoder, message)
84+
slave = decoder._header.get( # pylint: disable=protected-access
85+
"uid", 0x00
86+
)
87+
decoder.processIncomingPacket(message, self.report, slave)
9288
except Exception: # pylint: disable=broad-except
9389
self.check_errors(decoder, message)
9490

@@ -144,6 +140,7 @@ def report(self, message):
144140
def parse_messages(cmdline=None):
145141
"""Do a helper method to generate the messages to parse."""
146142
args = get_commandline(cmdline=cmdline)
143+
pymodbus_apply_logging_config(args.log.upper())
147144
_logger.setLevel(args.log.upper())
148145
if not args.message:
149146
_logger.error("Missing --message.")

pymodbus/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@
1818
from pymodbus.pdu import ExceptionResponse
1919

2020

21-
__version__ = "3.6.5"
21+
__version__ = "3.6.6"
2222
__version_full__ = f"[pymodbus, version {__version__}]"

pymodbus/client/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def register(self, custom_response_class: ModbusResponse) -> None:
124124
"""
125125
self.framer.decoder.register(custom_response_class)
126126

127-
def close(self, reconnect: bool = False) -> None: # type: ignore[override] # pylint: disable=arguments-differ
127+
def close(self, reconnect: bool = False) -> None:
128128
"""Close connection."""
129129
if reconnect:
130130
self.connection_lost(asyncio.TimeoutError("Server not responding"))

pymodbus/client/serial.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ async def connect(self) -> bool:
101101
Log.debug("Connecting to {}.", self.comm_params.host)
102102
return await self.base_connect()
103103

104-
def close(self, reconnect: bool = False) -> None: # type: ignore[override]
104+
def close(self, reconnect: bool = False) -> None:
105105
"""Close connection."""
106106
super().close(reconnect=reconnect)
107107

pymodbus/client/tcp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ async def connect(self) -> bool:
8787
)
8888
return await self.base_connect()
8989

90-
def close(self, reconnect: bool = False) -> None: # type: ignore[override]
90+
def close(self, reconnect: bool = False) -> None:
9191
"""Close connection."""
9292
super().close(reconnect=reconnect)
9393

pymodbus/datastore/remote.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,13 @@ def getValues(self, fc_as_hex, _address, _count=1):
5050
def setValues(self, fc_as_hex, address, values):
5151
"""Set the datastore with the supplied values."""
5252
group_fx = self.decode(fc_as_hex)
53-
if fc_as_hex in self._write_fc:
54-
func_fc = self.__set_callbacks[f"{group_fx}{fc_as_hex}"]
55-
if fc_as_hex in {0x0F, 0x10}:
56-
self.result = func_fc(address, values)
57-
else:
58-
self.result = func_fc(address, values[0])
53+
if fc_as_hex not in self._write_fc:
54+
raise ValueError(f"setValues() called with an non-write function code {fc_as_hex}")
55+
func_fc = self.__set_callbacks[f"{group_fx}{fc_as_hex}"]
56+
if fc_as_hex in {0x0F, 0x10}: # Write Multiple Coils, Write Multiple Registers
57+
self.result = func_fc(address, values)
58+
else:
59+
self.result = func_fc(address, values[0])
5960
if self.result.isError():
6061
return self.result
6162
return None

pymodbus/datastore/simulator.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def __init__(self, runtime):
107107
"""Initialize."""
108108
self.runtime = runtime
109109
self.config = {}
110-
self.config_types = {
110+
self.config_types: dict[str, dict[str, Any]] = {
111111
Label.type_bits: {
112112
Label.type: CellType.BITS,
113113
Label.next: None,
@@ -748,11 +748,12 @@ def action_uptime(cls, registers, inx, cell, **_kwargs):
748748
# Internal helper methods
749749
# --------------------------------------------
750750

751-
def validate_type(self, func_code, real_address, count):
751+
def validate_type(self, func_code, real_address, count) -> bool:
752752
"""Check if request is done against correct type.
753753
754754
:meta private:
755755
"""
756+
check: tuple
756757
if func_code in self._bits_func_code:
757758
# Bit access
758759
check = (CellType.BITS, -1)

pymodbus/diag_message.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ def execute(self, *args):
382382
383383
:returns: The initialized response message
384384
"""
385-
char = (self.message & 0xFF00) >> 8
385+
char = (self.message & 0xFF00) >> 8 # type: ignore[operator]
386386
_MCB._setDelimiter(char) # pylint: disable=protected-access
387387
return ChangeAsciiInputDelimiterResponse(self.message)
388388

pymodbus/file_message.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def encode(self):
181181
total = sum(record.response_length + 1 for record in self.records)
182182
packet = struct.pack("B", total)
183183
for record in self.records:
184-
packet += struct.pack(">BB", 0x06, record.record_length)
184+
packet += struct.pack(">BB", record.record_length, 0x06)
185185
packet += record.record_data
186186
return packet
187187

pymodbus/framer/ascii_framer.py

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Ascii_framer."""
22
# pylint: disable=missing-type-doc
3-
import struct
4-
from binascii import a2b_hex, b2a_hex
3+
from binascii import a2b_hex
54

65
from pymodbus.exceptions import ModbusIOException
76
from pymodbus.framer.base import BYTE_ORDER, FRAME_HEADER, ModbusFramer
@@ -41,6 +40,7 @@ def __init__(self, decoder, client=None):
4140
self._hsize = 0x02
4241
self._start = b":"
4342
self._end = b"\r\n"
43+
self.message_handler = MessageAscii([0], True)
4444

4545
def decode_data(self, data):
4646
"""Decode data."""
@@ -95,24 +95,9 @@ def check_frame(self):
9595
def buildPacket(self, message):
9696
"""Create a ready to send modbus packet.
9797
98-
Built off of a modbus request/response
99-
10098
:param message: The request/response to send
10199
:return: The encoded packet
102100
"""
103-
encoded = message.encode()
104-
buffer = struct.pack(
105-
ASCII_FRAME_HEADER, message.slave_id, message.function_code
106-
)
107-
checksum = MessageAscii.compute_LRC(buffer + encoded)
108-
109-
packet = bytearray()
110-
packet.extend(self._start)
111-
packet.extend(f"{message.slave_id:02x}{message.function_code:02x}".encode())
112-
packet.extend(b2a_hex(encoded))
113-
packet.extend(f"{checksum:02x}".encode())
114-
packet.extend(self._end)
115-
return bytes(packet).upper()
116-
117-
118-
# __END__
101+
data = message.function_code.to_bytes(1,'big') + message.encode()
102+
packet = self.message_handler.encode(data, message.slave_id, message.transaction_id)
103+
return packet

pymodbus/framer/binary_framer.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from pymodbus.exceptions import ModbusIOException
66
from pymodbus.framer.base import BYTE_ORDER, FRAME_HEADER, ModbusFramer
77
from pymodbus.logging import Log
8-
from pymodbus.utilities import checkCRC, computeCRC
8+
from pymodbus.message.rtu import MessageRTU
99

1010

1111
BINARY_FRAME_HEADER = BYTE_ORDER + FRAME_HEADER
@@ -76,7 +76,7 @@ def check_frame(self) -> bool:
7676
self._header["uid"] = struct.unpack(">B", self._buffer[1:2])[0]
7777
self._header["crc"] = struct.unpack(">H", self._buffer[end - 2 : end])[0]
7878
data = self._buffer[1 : end - 2]
79-
return checkCRC(data, self._header["crc"])
79+
return MessageRTU.check_CRC(data, self._header["crc"])
8080
return False
8181

8282
while len(self._buffer) > 1:
@@ -113,7 +113,7 @@ def buildPacket(self, message):
113113
struct.pack(BINARY_FRAME_HEADER, message.slave_id, message.function_code)
114114
+ data
115115
)
116-
packet += struct.pack(">H", computeCRC(packet))
116+
packet += struct.pack(">H", MessageRTU.compute_CRC(packet))
117117
packet = self._start + packet + self._end
118118
return packet
119119

@@ -132,6 +132,3 @@ def _preflight(self, data):
132132
array.append(item)
133133
array.append(item)
134134
return bytes(array)
135-
136-
137-
# __END__

pymodbus/framer/rtu_framer.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
)
99
from pymodbus.framer.base import BYTE_ORDER, FRAME_HEADER, ModbusFramer
1010
from pymodbus.logging import Log
11-
from pymodbus.utilities import ModbusTransactionState, checkCRC, computeCRC
11+
from pymodbus.message.rtu import MessageRTU
12+
from pymodbus.utilities import ModbusTransactionState
1213

1314

1415
RTU_FRAME_HEADER = BYTE_ORDER + FRAME_HEADER
@@ -62,6 +63,7 @@ def __init__(self, decoder, client=None):
6263
self._end = b"\x0d\x0a"
6364
self._min_frame_size = 4
6465
self.function_codes = decoder.lookup.keys() if decoder else {}
66+
self.message_handler = MessageRTU([0], True)
6567

6668
def decode_data(self, data):
6769
"""Decode data."""
@@ -131,7 +133,7 @@ def check_frame(self):
131133
data = self._buffer[: frame_size - 2]
132134
crc = self._header["crc"]
133135
crc_val = (int(crc[0]) << 8) + int(crc[1])
134-
return checkCRC(data, crc_val)
136+
return MessageRTU.check_CRC(data, crc_val)
135137
except (IndexError, KeyError, struct.error):
136138
return False
137139

@@ -170,12 +172,9 @@ def buildPacket(self, message):
170172
171173
:param message: The populated request/response to send
172174
"""
173-
data = message.encode()
174-
packet = (
175-
struct.pack(RTU_FRAME_HEADER, message.slave_id, message.function_code)
176-
+ data
177-
)
178-
packet += struct.pack(">H", computeCRC(packet))
175+
data = message.function_code.to_bytes(1, 'big') + message.encode()
176+
packet = self.message_handler.encode(data, message.slave_id, message.transaction_id)
177+
179178
# Ensure that transaction is actually the slave id for serial comms
180179
if message.slave_id:
181180
message.transaction_id = message.slave_id

pymodbus/framer/socket_framer.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
)
88
from pymodbus.framer.base import SOCKET_FRAME_HEADER, ModbusFramer
99
from pymodbus.logging import Log
10+
from pymodbus.message.socket import MessageSocket
1011

1112

1213
# --------------------------------------------------------------------------- #
@@ -42,6 +43,7 @@ def __init__(self, decoder, client=None):
4243
"""
4344
super().__init__(decoder, client)
4445
self._hsize = 0x07
46+
self.message_handler = MessageSocket([0], True)
4547

4648
def decode_data(self, data):
4749
"""Decode data."""
@@ -116,14 +118,6 @@ def buildPacket(self, message):
116118
117119
:param message: The populated request/response to send
118120
"""
119-
data = message.encode()
120-
packet = struct.pack(
121-
SOCKET_FRAME_HEADER,
122-
message.transaction_id,
123-
message.protocol_id,
124-
len(data) + 2,
125-
message.slave_id,
126-
message.function_code,
127-
)
128-
packet += data
121+
data = message.function_code.to_bytes(1, 'big') + message.encode()
122+
packet = self.message_handler.encode(data, message.slave_id, message.transaction_id)
129123
return packet

0 commit comments

Comments
 (0)