Skip to content

Commit 367f964

Browse files
committed
New combined test for all types of clients.
1 parent 36253cd commit 367f964

28 files changed

+807
-1016
lines changed

pymodbus/client/async_serial.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44

55
from serial_asyncio import create_serial_connection
66

7-
from pymodbus.client.base import ModbusClientProtocol
87
from pymodbus.framer import ModbusFramer
9-
from pymodbus.transaction import ModbusRtuFramer
10-
from pymodbus.client.base import ModbusBaseClient
8+
from pymodbus.framer.rtu_framer import ModbusRtuFramer
9+
from pymodbus.client.base import ModbusBaseClient, ModbusClientProtocol
1110
from pymodbus.constants import Defaults
1211

1312
_logger = logging.getLogger(__name__)
@@ -67,7 +66,7 @@ def __init__(
6766

6867
async def close(self): # pylint: disable=invalid-overridden-method
6968
"""Stop connection."""
70-
if self._connected and self.protocol and self.protocol.transport:
69+
if self.connected and self.protocol and self.protocol.transport:
7170
self.protocol.transport.close()
7271

7372
def _create_protocol(self):
@@ -77,7 +76,7 @@ def _create_protocol(self):
7776
return protocol
7877

7978
@property
80-
def _connected(self):
79+
def connected(self):
8180
"""Connect internal."""
8281
return self._connected_event.is_set()
8382

@@ -108,15 +107,15 @@ async def connect(self): # pylint: disable=invalid-overridden-method
108107
def protocol_made_connection(self, protocol):
109108
"""Notify successful connection."""
110109
_logger.info("Serial connected.")
111-
if not self._connected:
110+
if not self.connected:
112111
self._connected_event.set()
113112
self.protocol = protocol
114113
else:
115114
_logger.error("Factory protocol connect callback called while connected.")
116115

117116
def protocol_lost_connection(self, protocol):
118117
"""Notify lost connection."""
119-
if self._connected:
118+
if self.connected:
120119
_logger.info("Serial lost connection.")
121120
if protocol is not self.protocol:
122121
_logger.error(

pymodbus/client/async_tcp.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
import typing
55

66
from pymodbus.framer import ModbusFramer
7-
from pymodbus.transaction import ModbusSocketFramer
8-
from pymodbus.client.base import ModbusBaseClient
9-
from pymodbus.client.base import ModbusClientProtocol
7+
from pymodbus.framer.socket_framer import ModbusSocketFramer
8+
from pymodbus.client.base import ModbusBaseClient, ModbusClientProtocol
109
from pymodbus.constants import Defaults
1110

1211
_logger = logging.getLogger(__name__)
@@ -102,20 +101,17 @@ def protocol_made_connection(self, protocol):
102101

103102
def protocol_lost_connection(self, protocol):
104103
"""Notify lost connection."""
105-
if self.connected:
106-
_logger.info("Protocol lost connection.")
107-
if protocol is not self.protocol:
108-
_logger.error(
109-
"Factory protocol callback called "
110-
"from unexpected protocol instance."
111-
)
112-
113-
self.connected = False
114-
self.protocol = None
115-
if self.params.host:
116-
asyncio.ensure_future(self._reconnect())
117-
else:
118-
_logger.error("Factory protocol connect callback called while connected.")
104+
_logger.info("Protocol lost connection.")
105+
if protocol is not self.protocol:
106+
_logger.error(
107+
"Factory protocol callback called "
108+
"from unexpected protocol instance."
109+
)
110+
111+
self.connected = False
112+
self.protocol = None
113+
if self.params.host:
114+
asyncio.ensure_future(self._reconnect())
119115

120116
async def _reconnect(self):
121117
"""Reconnect."""

pymodbus/client/async_tls.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,42 @@
44
import ssl
55

66
from pymodbus.client.async_tcp import AsyncModbusTcpClient
7-
from pymodbus.transaction import ModbusTlsFramer, FifoTransactionManager
8-
from pymodbus.client.helper_tls import sslctx_provider
7+
from pymodbus.transaction import FifoTransactionManager
98
from pymodbus.client.base import ModbusClientProtocol
109
from pymodbus.framer import ModbusFramer
10+
from pymodbus.framer.tls_framer import ModbusTlsFramer
1111
from pymodbus.constants import Defaults
1212

1313
_logger = logging.getLogger(__name__)
1414

1515

16+
def sslctx_provider(sslctx=None, certfile=None, keyfile=None, password=None): # pylint: disable=missing-type-doc
17+
"""Provide the SSLContext for ModbusTlsClient.
18+
19+
If the user defined SSLContext is not passed in, sslctx_provider will
20+
produce a default one.
21+
22+
:param sslctx: The user defined SSLContext to use for TLS (default None and
23+
auto create)
24+
:param certfile: The optional client"s cert file path for TLS server request
25+
:param keyfile: The optional client"s key file path for TLS server request
26+
:param password: The password for for decrypting client"s private key file
27+
"""
28+
if sslctx is None:
29+
# According to MODBUS/TCP Security Protocol Specification, it is
30+
# TLSv2 at least
31+
sslctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
32+
sslctx.verify_mode = ssl.CERT_REQUIRED
33+
sslctx.check_hostname = True
34+
35+
if certfile and keyfile:
36+
sslctx.load_cert_chain(
37+
certfile=certfile, keyfile=keyfile, password=password
38+
)
39+
40+
return sslctx
41+
42+
1643
class AsyncModbusTlsClient(AsyncModbusTcpClient):
1744
"""**AsyncModbusTlsClient**.
1845

pymodbus/client/async_udp.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
import socket
66
import typing
77

8-
from pymodbus.client.base import ModbusBaseClient
9-
from pymodbus.transaction import ModbusSocketFramer
10-
from pymodbus.client.base import ModbusClientProtocol
8+
from pymodbus.framer.socket_framer import ModbusSocketFramer
9+
from pymodbus.client.base import ModbusBaseClient, ModbusClientProtocol
1110
from pymodbus.framer import ModbusFramer
1211
from pymodbus.constants import Defaults
1312

pymodbus/client/base.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Base for all clients."""
22
from __future__ import annotations
33
from dataclasses import dataclass
4+
import socket
45
import asyncio
56
import logging
67

@@ -186,6 +187,15 @@ def recv(self, size):
186187
"""
187188
return size
188189

190+
@classmethod
191+
def _get_address_family(cls, address):
192+
"""Get the correct address family."""
193+
try:
194+
_ = socket.inet_pton(socket.AF_INET6, address)
195+
except socket.error: # not a valid ipv6 address
196+
return socket.AF_INET
197+
return socket.AF_INET6
198+
189199
# ----------------------------------------------------------------------- #
190200
# The magic methods
191201
# ----------------------------------------------------------------------- #
@@ -195,6 +205,7 @@ def __enter__(self):
195205
:returns: The current instance of the client
196206
:raises ConnectionException:
197207
"""
208+
198209
if not self.connect():
199210
raise ConnectionException(f"Failed to connect[{self.__str__()}]")
200211
return self
@@ -279,7 +290,8 @@ def connection_made(self, transport):
279290

280291
async def close(self): # pylint: disable=invalid-overridden-method
281292
"""Close connection."""
282-
self.transport.close()
293+
if self.transport:
294+
self.transport.close()
283295
self._connected = False
284296

285297
def connection_lost(self, reason):

pymodbus/client/helper_tls.py

Lines changed: 0 additions & 30 deletions
This file was deleted.

pymodbus/client/mixin.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import pymodbus.diag_message as pdu_diag
1313
from pymodbus.utilities import ModbusTransactionState
1414
from pymodbus.pdu import ModbusResponse, ModbusRequest
15-
from pymodbus.exceptions import ModbusException
1615

1716

1817
_logger = logging.getLogger(__name__)
@@ -50,7 +49,7 @@ def execute(self, request: ModbusRequest) -> ModbusResponse:
5049
:param request: Request to send
5150
:raises ModbusException:
5251
"""
53-
raise ModbusException(f"Execute({request}) not implemented.")
52+
return request
5453

5554
def read_coils(
5655
self,

pymodbus/client/sync_diag.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from pymodbus.client.sync_tcp import ModbusTcpClient
77
from pymodbus.constants import Defaults
88
from pymodbus.exceptions import ConnectionException
9-
from pymodbus.transaction import ModbusSocketFramer
9+
from pymodbus.framer.socket_framer import ModbusSocketFramer
1010

1111
_logger = logging.getLogger(__name__)
1212

pymodbus/client/sync_serial.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pymodbus.client.base import ModbusBaseClient
99
from pymodbus.exceptions import ConnectionException
1010
from pymodbus.framer import ModbusFramer
11-
from pymodbus.transaction import ModbusRtuFramer
11+
from pymodbus.framer.rtu_framer import ModbusRtuFramer
1212
from pymodbus.utilities import ModbusTransactionState, hexlify_packets
1313
from pymodbus.constants import Defaults
1414

@@ -76,6 +76,11 @@ def __init__(
7676
self.silent_interval = 3.5 * self._t0
7777
self.silent_interval = round(self.silent_interval, 6)
7878

79+
@property
80+
def connected(self):
81+
"""Connect internal."""
82+
return self.connect()
83+
7984
def connect(self):
8085
"""Connect to the modbus serial server."""
8186
if self.socket:

pymodbus/client/sync_tcp.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pymodbus.exceptions import ConnectionException
99
from pymodbus.utilities import ModbusTransactionState
1010
from pymodbus.client.base import ModbusBaseClient
11-
from pymodbus.transaction import ModbusSocketFramer
11+
from pymodbus.framer.socket_framer import ModbusSocketFramer
1212
from pymodbus.framer import ModbusFramer
1313
from pymodbus.constants import Defaults
1414

@@ -51,6 +51,11 @@ def __init__(
5151
self.source_address = source_address
5252
self.socket = None
5353

54+
@property
55+
def connected(self):
56+
"""Connect internal."""
57+
return self.connect()
58+
5459
def connect(self):
5560
"""Connect to the modbus tcp server."""
5661
if self.socket:

0 commit comments

Comments
 (0)