From 08ca596e09425a0b2291ca1ea445aa4d79240250 Mon Sep 17 00:00:00 2001 From: jan iversen Date: Tue, 16 Dec 2025 10:08:48 +0100 Subject: [PATCH 1/3] remove last_frame_end. --- examples/package_test_tool.py | 39 +++++++++++++++++++++++++++++++++++ pymodbus/client/base.py | 5 +---- pymodbus/client/serial.py | 3 --- pymodbus/client/tcp.py | 2 -- pymodbus/client/udp.py | 2 -- test/client/test_client.py | 9 -------- 6 files changed, 40 insertions(+), 20 deletions(-) diff --git a/examples/package_test_tool.py b/examples/package_test_tool.py index 6e6eb88d6..ff57a96ea 100755 --- a/examples/package_test_tool.py +++ b/examples/package_test_tool.py @@ -102,6 +102,12 @@ def callback_new_connection(self) -> ModbusProtocol: new_stub.stub_handle_data = self.stub_handle_data return new_stub +<<<<<<< HEAD +======= + +test_port = 5004 + +>>>>>>> 6d161685 (remove last_frame_end.) class ClientTester: # pylint: disable=too-few-public-methods """Main program.""" @@ -109,23 +115,40 @@ class ClientTester: # pylint: disable=too-few-public-methods def __init__(self, comm: CommType): """Initialize runtime tester.""" +<<<<<<< HEAD +======= + global test_port # pylint: disable=global-statement +>>>>>>> 6d161685 (remove last_frame_end.) self.comm = comm host = NULLMODEM_HOST self.client: modbusClient.AsyncModbusTcpClient | modbusClient.AsyncModbusSerialClient if comm == CommType.TCP: self.client = modbusClient.AsyncModbusTcpClient( host, +<<<<<<< HEAD port=self.TEST_PORT, ) else: # if comm == CommType.SERIAL: host = f"{NULLMODEM_HOST}:{self.TEST_PORT}" +======= + port=test_port, + ) + else: # if comm == CommType.SERIAL: + host = f"{NULLMODEM_HOST}:{test_port}" +>>>>>>> 6d161685 (remove last_frame_end.) self.client = modbusClient.AsyncModbusSerialClient( host, ) server_params = self.client.ctx.comm_params.copy() +<<<<<<< HEAD server_params.source_address = (host, self.TEST_PORT) self.stub = TransportStub(server_params, True, simulate_server) self.TEST_PORT += 1 +======= + server_params.source_address = (host, test_port) + self.stub = TransportStub(server_params, True, simulate_server) + test_port += 1 +>>>>>>> 6d161685 (remove last_frame_end.) async def run(self): @@ -148,6 +171,10 @@ class ServerTester: # pylint: disable=too-few-public-methods def __init__(self, comm: CommType): """Initialize runtime tester.""" +<<<<<<< HEAD +======= + global test_port # pylint: disable=global-statement +>>>>>>> 6d161685 (remove last_frame_end.) self.comm = comm self.store = ModbusDeviceContext( di=ModbusSequentialDataBlock(0, [17] * 100), @@ -165,19 +192,31 @@ def __init__(self, comm: CommType): self.context, framer=FramerType.SOCKET, identity=self.identity, +<<<<<<< HEAD address=(NULLMODEM_HOST, self.TEST_PORT), +======= + address=(NULLMODEM_HOST, test_port), +>>>>>>> 6d161685 (remove last_frame_end.) ) else: # if comm == CommType.SERIAL: self.server = modbusServer.ModbusSerialServer( self.context, framer=FramerType.SOCKET, identity=self.identity, +<<<<<<< HEAD port=f"{NULLMODEM_HOST}:{self.TEST_PORT}", +======= + port=f"{NULLMODEM_HOST}:{test_port}", +>>>>>>> 6d161685 (remove last_frame_end.) ) client_params = self.server.comm_params.copy() client_params.timeout_connect = 1.0 self.stub = TransportStub(client_params, False, simulate_client) +<<<<<<< HEAD self.TEST_PORT += 1 +======= + test_port += 1 +>>>>>>> 6d161685 (remove last_frame_end.) async def run(self): diff --git a/pymodbus/client/base.py b/pymodbus/client/base.py index 099a9d956..60991145a 100644 --- a/pymodbus/client/base.py +++ b/pymodbus/client/base.py @@ -160,7 +160,6 @@ def __init__( ) self.reconnect_delay_current = self.comm_params.reconnect_delay or 0 self.use_udp = False - self.last_frame_end: float | None = 0 self.silent_interval: float = 0 # ----------------------------------------------------------------------- # @@ -183,9 +182,7 @@ def idle_time(self) -> float: Applications can call message functions without checking idle_time(), this is done automatically. """ - if self.last_frame_end is None or self.silent_interval is None: - return 0 - return self.last_frame_end + self.silent_interval + return 0 def execute(self, no_response_expected: bool, request: ModbusPDU) -> ModbusPDU: """Execute request and get response (call **sync/async**). diff --git a/pymodbus/client/serial.py b/pymodbus/client/serial.py index 84faced4e..c55efbb42 100644 --- a/pymodbus/client/serial.py +++ b/pymodbus/client/serial.py @@ -206,7 +206,6 @@ def __init__( # pylint: disable=too-many-arguments trace_connect, ) self.socket: serial.Serial | None = None - self.last_frame_end = None self._t0 = float(1 + bytesize + stopbits) / baudrate # Check every 4 bytes / 2 registers if the reading is ready @@ -243,7 +242,6 @@ def connect(self) -> bool: exclusive=True, ) self.socket.inter_byte_timeout = self.inter_byte_timeout - self.last_frame_end = None # except serial.SerialException as msg: # pyserial raises undocumented exceptions like termios except Exception as msg: # pylint: disable=broad-exception-caught @@ -303,7 +301,6 @@ def recv(self, size: int | None) -> bytes: if size > self._in_waiting(): self._wait_for_data() result = self.socket.read(size) - self.last_frame_end = round(time.time(), 6) return result def is_socket_open(self) -> bool: diff --git a/pymodbus/client/tcp.py b/pymodbus/client/tcp.py index dfd77f1a7..d45390b7b 100644 --- a/pymodbus/client/tcp.py +++ b/pymodbus/client/tcp.py @@ -275,8 +275,6 @@ def recv(self, size: int | None) -> bytes: break recv_size = size - data_length - - self.last_frame_end = round(time.time(), 6) return b"".join(data) def _handle_abrupt_socket_close(self, size: int | None, data: list[bytes], duration: float) -> bytes: diff --git a/pymodbus/client/udp.py b/pymodbus/client/udp.py index f5e9fbdc7..7b8740dcf 100644 --- a/pymodbus/client/udp.py +++ b/pymodbus/client/udp.py @@ -2,7 +2,6 @@ from __future__ import annotations import socket -import time from collections.abc import Callable from pymodbus.client.base import ModbusBaseClient, ModbusBaseSyncClient @@ -228,7 +227,6 @@ def recv(self, size: int | None) -> bytes: if size is None: size = 4096 data = self.socket.recvfrom(size)[0] - self.last_frame_end = round(time.time(), 6) return data def is_socket_open(self): diff --git a/test/client/test_client.py b/test/client/test_client.py index 506f434d9..a3a290521 100755 --- a/test/client/test_client.py +++ b/test/client/test_client.py @@ -425,9 +425,7 @@ async def test_client_instanciate( ) # Test information methods - client.last_frame_end = 2 client.silent_interval = 2 - client.last_frame_end = None # a successful execute client.transaction = mock.Mock(**{"execute.return_value": True}) @@ -633,13 +631,6 @@ class CustomRequest: # pylint: disable=too-few-public-methods client.register(CustomRequest) client.framer.decoder.register.assert_called_once_with(CustomRequest) - def test_idle_time(self): - """Test idle_time().""" - client = lib_client.ModbusTcpClient("127.0.0.1") - assert not client.idle_time() - client.last_frame_end = None - assert not client.idle_time() - def test_sync_block(self): """Test idle_time().""" with lib_client.ModbusTcpClient("127.0.0.1") as client: From 6f8ee0654f768deb78846a3d2dd87186b0ae1a24 Mon Sep 17 00:00:00 2001 From: jan iversen Date: Tue, 16 Dec 2025 10:16:27 +0100 Subject: [PATCH 2/3] Remove idle_time. --- API_changes.rst | 1 + pymodbus/client/base.py | 9 --------- pymodbus/client/serial.py | 7 +------ test/client/test_client.py | 7 ++----- test/client/test_client_sync.py | 7 ------- 5 files changed, 4 insertions(+), 27 deletions(-) diff --git a/API_changes.rst b/API_changes.rst index 403dd1836..0c00e1d4e 100644 --- a/API_changes.rst +++ b/API_changes.rst @@ -5,6 +5,7 @@ Versions (X.Y.Z) where Z > 0 e.g. 3.0.1 do NOT have API changes! API changes 3.12.0 ------------------ - when using no_response_expected=, the call returns None +- remove idle_time() from sync client since it is void API changes 3.11.0 ------------------ diff --git a/pymodbus/client/base.py b/pymodbus/client/base.py index 60991145a..8a28a212e 100644 --- a/pymodbus/client/base.py +++ b/pymodbus/client/base.py @@ -160,7 +160,6 @@ def __init__( ) self.reconnect_delay_current = self.comm_params.reconnect_delay or 0 self.use_udp = False - self.silent_interval: float = 0 # ----------------------------------------------------------------------- # # Client external interface @@ -176,14 +175,6 @@ def register(self, custom_response_class: type[ModbusPDU]) -> None: """ self.framer.decoder.register(custom_response_class) - def idle_time(self) -> float: - """Time before initiating next transaction (call **sync**). - - Applications can call message functions without checking idle_time(), - this is done automatically. - """ - return 0 - def execute(self, no_response_expected: bool, request: ModbusPDU) -> ModbusPDU: """Execute request and get response (call **sync/async**). diff --git a/pymodbus/client/serial.py b/pymodbus/client/serial.py index c55efbb42..791781d99 100644 --- a/pymodbus/client/serial.py +++ b/pymodbus/client/serial.py @@ -214,13 +214,8 @@ def __init__( # pylint: disable=too-many-arguments self._recv_interval = max(self._recv_interval, 0.001) self.inter_byte_timeout: float = 0 - self.silent_interval: float = 0 - if baudrate > 19200: - self.silent_interval = 1.75 / 1000 # ms - else: + if baudrate <= 19200: self.inter_byte_timeout = 1.5 * self._t0 - self.silent_interval = 3.5 * self._t0 - self.silent_interval = round(self.silent_interval, 6) @property def connected(self) -> bool: diff --git a/test/client/test_client.py b/test/client/test_client.py index a3a290521..791595c96 100755 --- a/test/client/test_client.py +++ b/test/client/test_client.py @@ -424,9 +424,6 @@ async def test_client_instanciate( **cur_args["opt_args"], ) - # Test information methods - client.silent_interval = 2 - # a successful execute client.transaction = mock.Mock(**{"execute.return_value": True}) @@ -632,12 +629,12 @@ class CustomRequest: # pylint: disable=too-few-public-methods client.framer.decoder.register.assert_called_once_with(CustomRequest) def test_sync_block(self): - """Test idle_time().""" + """Test sync block.""" with lib_client.ModbusTcpClient("127.0.0.1") as client: assert not client.connected def test_sync_execute(self): - """Test idle_time().""" + """Test sync execute.""" client = lib_client.ModbusTcpClient("127.0.0.1") client.connect = mock.Mock(return_value=False) with pytest.raises(ConnectionException): diff --git a/test/client/test_client_sync.py b/test/client/test_client_sync.py index 24a1526e7..0f0ff1acc 100755 --- a/test/client/test_client_sync.py +++ b/test/client/test_client_sync.py @@ -282,13 +282,6 @@ def test_sync_serial_client_instantiation(self): FramerRTU, ) - def test_sync_serial_rtu_client_timeouts(self): - """Test sync serial rtu.""" - client = ModbusSerialClient("/dev/null", framer=FramerType.RTU, baudrate=9600) - assert client.silent_interval == round((3.5 * 10 / 9600), 6) - client = ModbusSerialClient("/dev/null", framer=FramerType.RTU, baudrate=38400) - assert client.silent_interval == round((1.75 / 1000), 6) - @mock.patch("serial.Serial") def test_basic_sync_serial_client(self, mock_serial): """Test the basic methods for the serial sync client.""" From 8031ab0c24b957ebd3259182aba1156470ff83e3 Mon Sep 17 00:00:00 2001 From: jan iversen Date: Tue, 16 Dec 2025 10:37:47 +0100 Subject: [PATCH 3/3] Package_test_tool is already updated. --- examples/package_test_tool.py | 39 ----------------------------------- 1 file changed, 39 deletions(-) diff --git a/examples/package_test_tool.py b/examples/package_test_tool.py index ff57a96ea..6e6eb88d6 100755 --- a/examples/package_test_tool.py +++ b/examples/package_test_tool.py @@ -102,12 +102,6 @@ def callback_new_connection(self) -> ModbusProtocol: new_stub.stub_handle_data = self.stub_handle_data return new_stub -<<<<<<< HEAD -======= - -test_port = 5004 - ->>>>>>> 6d161685 (remove last_frame_end.) class ClientTester: # pylint: disable=too-few-public-methods """Main program.""" @@ -115,40 +109,23 @@ class ClientTester: # pylint: disable=too-few-public-methods def __init__(self, comm: CommType): """Initialize runtime tester.""" -<<<<<<< HEAD -======= - global test_port # pylint: disable=global-statement ->>>>>>> 6d161685 (remove last_frame_end.) self.comm = comm host = NULLMODEM_HOST self.client: modbusClient.AsyncModbusTcpClient | modbusClient.AsyncModbusSerialClient if comm == CommType.TCP: self.client = modbusClient.AsyncModbusTcpClient( host, -<<<<<<< HEAD port=self.TEST_PORT, ) else: # if comm == CommType.SERIAL: host = f"{NULLMODEM_HOST}:{self.TEST_PORT}" -======= - port=test_port, - ) - else: # if comm == CommType.SERIAL: - host = f"{NULLMODEM_HOST}:{test_port}" ->>>>>>> 6d161685 (remove last_frame_end.) self.client = modbusClient.AsyncModbusSerialClient( host, ) server_params = self.client.ctx.comm_params.copy() -<<<<<<< HEAD server_params.source_address = (host, self.TEST_PORT) self.stub = TransportStub(server_params, True, simulate_server) self.TEST_PORT += 1 -======= - server_params.source_address = (host, test_port) - self.stub = TransportStub(server_params, True, simulate_server) - test_port += 1 ->>>>>>> 6d161685 (remove last_frame_end.) async def run(self): @@ -171,10 +148,6 @@ class ServerTester: # pylint: disable=too-few-public-methods def __init__(self, comm: CommType): """Initialize runtime tester.""" -<<<<<<< HEAD -======= - global test_port # pylint: disable=global-statement ->>>>>>> 6d161685 (remove last_frame_end.) self.comm = comm self.store = ModbusDeviceContext( di=ModbusSequentialDataBlock(0, [17] * 100), @@ -192,31 +165,19 @@ def __init__(self, comm: CommType): self.context, framer=FramerType.SOCKET, identity=self.identity, -<<<<<<< HEAD address=(NULLMODEM_HOST, self.TEST_PORT), -======= - address=(NULLMODEM_HOST, test_port), ->>>>>>> 6d161685 (remove last_frame_end.) ) else: # if comm == CommType.SERIAL: self.server = modbusServer.ModbusSerialServer( self.context, framer=FramerType.SOCKET, identity=self.identity, -<<<<<<< HEAD port=f"{NULLMODEM_HOST}:{self.TEST_PORT}", -======= - port=f"{NULLMODEM_HOST}:{test_port}", ->>>>>>> 6d161685 (remove last_frame_end.) ) client_params = self.server.comm_params.copy() client_params.timeout_connect = 1.0 self.stub = TransportStub(client_params, False, simulate_client) -<<<<<<< HEAD self.TEST_PORT += 1 -======= - test_port += 1 ->>>>>>> 6d161685 (remove last_frame_end.) async def run(self):