Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
janiversen committed Mar 8, 2024
2 parents 779967e + 1629f05 commit 2071307
Show file tree
Hide file tree
Showing 42 changed files with 521 additions and 1,584 deletions.
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ jobs:

steps:
- name: Checkout repo from github
uses: actions/[email protected].0
uses: actions/[email protected].1

- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v4.7.1
uses: actions/setup-python@v5.0.0
with:
python-version: ${{ matrix.python }}

Expand All @@ -61,7 +61,7 @@ jobs:
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache@v3.3.2
uses: actions/cache@v4.0.1
with:
path: ${{ env.VIRTUAL_ENV }}
key: >-
Expand Down Expand Up @@ -117,15 +117,15 @@ jobs:
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4.1.1

- uses: github/codeql-action/init@v2
- uses: github/codeql-action/init@v3
with:
languages: python

- uses: github/codeql-action/autobuild@v2
- uses: github/codeql-action/autobuild@v3

- uses: github/codeql-action/analyze@v2
- uses: github/codeql-action/analyze@v3

ci_complete:
name: ci_complete
Expand Down
2 changes: 2 additions & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Thanks to
- André Srinivasan
- banana-sun
- Blaise Thompson
- CapraTheBest
- cgernert
- corollaries
- Chandler Riehm
Expand All @@ -46,6 +47,7 @@ Thanks to
- Joe Burmeister
- Jonathan Reichelt Gjertsen
- julian
- Justin Standring
- Kenny Johansson
- Matthias Straka
- laund
Expand Down
23 changes: 23 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@ helps make pymodbus a better product.

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

Version 3.6.6
-------------
* Solve transport close() as not inherited method. (#2098)
* enable `mypy --check-untyped-defs` (#2096)
* Add get_expected_response_length to transaction.
* Remove control encode in framersRemove control encode in framers. (#2095)
* Bump codeql in CI to v3. (#2093)
* Improve server types (#2092)
* Remove pointless try/except (#2091)
* Improve transport types (#2090)
* Use explicit ValueError when called with incorrect function code (#2089)
* update message tests (incorporate all old tests). (#2088)
* Improve simulator type hints (#2084)
* Cleanup dead resetFrame code (#2082)
* integrate message.encode() into framer.buildPacket. (#2062)
* Repair client close() (intern= is needed for ModbusProtocol). (#2080)
* Updated Message_Parser example (#2079)
* Fix #2069 use released repl from pypi (#2077)
* Fix field encoding of Read File Record Response (#2075)
* Improve simulator types (#2076)
* Bump actions. (#2071)


Version 3.6.5
-------------
* Update framers to ease message integration (only decode/encode) (#2064)
Expand Down
7 changes: 4 additions & 3 deletions MAKE_RELEASE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ Prepare/make release on dev.
* Control / Update API_changes.rst
* Update CHANGELOG.rst
* Add commits from last release, but selectively !
git log --oneline v3.6.5..HEAD > commit.log
git log --pretty="%an" v3.6.1..HEAD | sort -uf > authors.log
update AUTHORS
git log --oneline v3.6.6..HEAD > commit.log
git log --pretty="%an" v3.6.6..HEAD | sort -uf > authors.log
update AUTHORS.rst and CHANGELOG.rst
cd doc; ./build_html
* rm -rf build/* dist/*
* git checkout build
* python3 -m build
* twine check dist/*
* Commit, push and merge.
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ PyModbus - A Python Modbus Stack

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

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

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

Expand Down
Binary file modified doc/source/_static/examples.tgz
Binary file not shown.
Binary file modified doc/source/_static/examples.zip
Binary file not shown.
15 changes: 6 additions & 9 deletions examples/message_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import logging
import textwrap

from pymodbus import pymodbus_apply_logging_config
from pymodbus.factory import ClientDecoder, ServerDecoder
from pymodbus.transaction import (
ModbusAsciiFramer,
Expand Down Expand Up @@ -80,15 +81,10 @@ def decode(self, message):
print(f"{decoder.decoder.__class__.__name__}")
print("-" * 80)
try:
decoder.addToFrame(message)
if decoder.checkFrame():
slave = decoder._header.get( # pylint: disable=protected-access
"uid", 0x00
)
decoder.advanceFrame()
decoder.processIncomingPacket(message, self.report, slave)
else:
self.check_errors(decoder, message)
slave = decoder._header.get( # pylint: disable=protected-access
"uid", 0x00
)
decoder.processIncomingPacket(message, self.report, slave)
except Exception: # pylint: disable=broad-except
self.check_errors(decoder, message)

Expand Down Expand Up @@ -144,6 +140,7 @@ def report(self, message):
def parse_messages(cmdline=None):
"""Do a helper method to generate the messages to parse."""
args = get_commandline(cmdline=cmdline)
pymodbus_apply_logging_config(args.log.upper())
_logger.setLevel(args.log.upper())
if not args.message:
_logger.error("Missing --message.")
Expand Down
2 changes: 1 addition & 1 deletion pymodbus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@
from pymodbus.pdu import ExceptionResponse


__version__ = "3.6.5"
__version__ = "3.6.6"
__version_full__ = f"[pymodbus, version {__version__}]"
2 changes: 1 addition & 1 deletion pymodbus/client/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def register(self, custom_response_class: ModbusResponse) -> None:
"""
self.framer.decoder.register(custom_response_class)

def close(self, reconnect: bool = False) -> None: # type: ignore[override] # pylint: disable=arguments-differ
def close(self, reconnect: bool = False) -> None:
"""Close connection."""
if reconnect:
self.connection_lost(asyncio.TimeoutError("Server not responding"))
Expand Down
2 changes: 1 addition & 1 deletion pymodbus/client/serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ async def connect(self) -> bool:
Log.debug("Connecting to {}.", self.comm_params.host)
return await self.base_connect()

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

Expand Down
2 changes: 1 addition & 1 deletion pymodbus/client/tcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ async def connect(self) -> bool:
)
return await self.base_connect()

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

Expand Down
13 changes: 7 additions & 6 deletions pymodbus/datastore/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,13 @@ def getValues(self, fc_as_hex, _address, _count=1):
def setValues(self, fc_as_hex, address, values):
"""Set the datastore with the supplied values."""
group_fx = self.decode(fc_as_hex)
if fc_as_hex in self._write_fc:
func_fc = self.__set_callbacks[f"{group_fx}{fc_as_hex}"]
if fc_as_hex in {0x0F, 0x10}:
self.result = func_fc(address, values)
else:
self.result = func_fc(address, values[0])
if fc_as_hex not in self._write_fc:
raise ValueError(f"setValues() called with an non-write function code {fc_as_hex}")
func_fc = self.__set_callbacks[f"{group_fx}{fc_as_hex}"]
if fc_as_hex in {0x0F, 0x10}: # Write Multiple Coils, Write Multiple Registers
self.result = func_fc(address, values)
else:
self.result = func_fc(address, values[0])
if self.result.isError():
return self.result
return None
Expand Down
5 changes: 3 additions & 2 deletions pymodbus/datastore/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def __init__(self, runtime):
"""Initialize."""
self.runtime = runtime
self.config = {}
self.config_types = {
self.config_types: dict[str, dict[str, Any]] = {
Label.type_bits: {
Label.type: CellType.BITS,
Label.next: None,
Expand Down Expand Up @@ -748,11 +748,12 @@ def action_uptime(cls, registers, inx, cell, **_kwargs):
# Internal helper methods
# --------------------------------------------

def validate_type(self, func_code, real_address, count):
def validate_type(self, func_code, real_address, count) -> bool:
"""Check if request is done against correct type.
:meta private:
"""
check: tuple
if func_code in self._bits_func_code:
# Bit access
check = (CellType.BITS, -1)
Expand Down
2 changes: 1 addition & 1 deletion pymodbus/diag_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ def execute(self, *args):
:returns: The initialized response message
"""
char = (self.message & 0xFF00) >> 8
char = (self.message & 0xFF00) >> 8 # type: ignore[operator]
_MCB._setDelimiter(char) # pylint: disable=protected-access
return ChangeAsciiInputDelimiterResponse(self.message)

Expand Down
2 changes: 1 addition & 1 deletion pymodbus/file_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def encode(self):
total = sum(record.response_length + 1 for record in self.records)
packet = struct.pack("B", total)
for record in self.records:
packet += struct.pack(">BB", 0x06, record.record_length)
packet += struct.pack(">BB", record.record_length, 0x06)
packet += record.record_data
return packet

Expand Down
25 changes: 5 additions & 20 deletions pymodbus/framer/ascii_framer.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Ascii_framer."""
# pylint: disable=missing-type-doc
import struct
from binascii import a2b_hex, b2a_hex
from binascii import a2b_hex

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

def decode_data(self, data):
"""Decode data."""
Expand Down Expand Up @@ -95,24 +95,9 @@ def check_frame(self):
def buildPacket(self, message):
"""Create a ready to send modbus packet.
Built off of a modbus request/response
:param message: The request/response to send
:return: The encoded packet
"""
encoded = message.encode()
buffer = struct.pack(
ASCII_FRAME_HEADER, message.slave_id, message.function_code
)
checksum = MessageAscii.compute_LRC(buffer + encoded)

packet = bytearray()
packet.extend(self._start)
packet.extend(f"{message.slave_id:02x}{message.function_code:02x}".encode())
packet.extend(b2a_hex(encoded))
packet.extend(f"{checksum:02x}".encode())
packet.extend(self._end)
return bytes(packet).upper()


# __END__
data = message.function_code.to_bytes(1,'big') + message.encode()
packet = self.message_handler.encode(data, message.slave_id, message.transaction_id)
return packet
9 changes: 3 additions & 6 deletions pymodbus/framer/binary_framer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from pymodbus.exceptions import ModbusIOException
from pymodbus.framer.base import BYTE_ORDER, FRAME_HEADER, ModbusFramer
from pymodbus.logging import Log
from pymodbus.utilities import checkCRC, computeCRC
from pymodbus.message.rtu import MessageRTU


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

while len(self._buffer) > 1:
Expand Down Expand Up @@ -113,7 +113,7 @@ def buildPacket(self, message):
struct.pack(BINARY_FRAME_HEADER, message.slave_id, message.function_code)
+ data
)
packet += struct.pack(">H", computeCRC(packet))
packet += struct.pack(">H", MessageRTU.compute_CRC(packet))
packet = self._start + packet + self._end
return packet

Expand All @@ -132,6 +132,3 @@ def _preflight(self, data):
array.append(item)
array.append(item)
return bytes(array)


# __END__
15 changes: 7 additions & 8 deletions pymodbus/framer/rtu_framer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
)
from pymodbus.framer.base import BYTE_ORDER, FRAME_HEADER, ModbusFramer
from pymodbus.logging import Log
from pymodbus.utilities import ModbusTransactionState, checkCRC, computeCRC
from pymodbus.message.rtu import MessageRTU
from pymodbus.utilities import ModbusTransactionState


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

def decode_data(self, data):
"""Decode data."""
Expand Down Expand Up @@ -131,7 +133,7 @@ def check_frame(self):
data = self._buffer[: frame_size - 2]
crc = self._header["crc"]
crc_val = (int(crc[0]) << 8) + int(crc[1])
return checkCRC(data, crc_val)
return MessageRTU.check_CRC(data, crc_val)
except (IndexError, KeyError, struct.error):
return False

Expand Down Expand Up @@ -170,12 +172,9 @@ def buildPacket(self, message):
:param message: The populated request/response to send
"""
data = message.encode()
packet = (
struct.pack(RTU_FRAME_HEADER, message.slave_id, message.function_code)
+ data
)
packet += struct.pack(">H", computeCRC(packet))
data = message.function_code.to_bytes(1, 'big') + message.encode()
packet = self.message_handler.encode(data, message.slave_id, message.transaction_id)

# Ensure that transaction is actually the slave id for serial comms
if message.slave_id:
message.transaction_id = message.slave_id
Expand Down
14 changes: 4 additions & 10 deletions pymodbus/framer/socket_framer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
)
from pymodbus.framer.base import SOCKET_FRAME_HEADER, ModbusFramer
from pymodbus.logging import Log
from pymodbus.message.socket import MessageSocket


# --------------------------------------------------------------------------- #
Expand Down Expand Up @@ -42,6 +43,7 @@ def __init__(self, decoder, client=None):
"""
super().__init__(decoder, client)
self._hsize = 0x07
self.message_handler = MessageSocket([0], True)

def decode_data(self, data):
"""Decode data."""
Expand Down Expand Up @@ -116,14 +118,6 @@ def buildPacket(self, message):
:param message: The populated request/response to send
"""
data = message.encode()
packet = struct.pack(
SOCKET_FRAME_HEADER,
message.transaction_id,
message.protocol_id,
len(data) + 2,
message.slave_id,
message.function_code,
)
packet += data
data = message.function_code.to_bytes(1, 'big') + message.encode()
packet = self.message_handler.encode(data, message.slave_id, message.transaction_id)
return packet
Loading

0 comments on commit 2071307

Please sign in to comment.