Skip to content

Commit 3ce0dbd

Browse files
authored
Add/update client documentation, including docstrings etc. (#1055)
Simplify async/sync calls, update doc.
1 parent 94fbbb3 commit 3ce0dbd

27 files changed

+539
-648
lines changed

doc/source/library/pymodbus.client.calls.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@ Pymodbus makes a all standard modbus requests/responses available as simple call
55

66
All calls are available as synchronous and asynchronous (asyncio based).
77

8-
.. automodule:: pymodbus.client.mixin
8+
Using Modbus<transport>Client.register() custom messagees can be added to pymodbus,
9+
and handled automatically.
10+
11+
.. autoclass:: pymodbus.client.mixin.ModbusClientMixin
912
:members:

doc/source/library/pymodbus.client.rst

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,37 @@ Pymodbus offers clients with different transport protocols in 2 versions:
66
- synchronous,
77
- asynchronous (based on asyncio).
88

9-
Using a client to set/get information from a device (server) is simple as seen in this
10-
example (more details in below)::
9+
Using pymodbus client to set/get information from a device (server)
10+
is done in a few simple steps, like the following synchronous example::
1111

1212
# create client object
1313
client = ModbusSerial("/dev/tty")
1414

1515
# connect to device
16-
client.start()
16+
client.connect()
1717

1818
# set/set information
19-
client.read_coils(0x01)
19+
rr = client.read_coils(0x01)
2020
client.write_coil(0x01, values)
21-
...
2221

2322
# disconnect device
24-
client.stop()
23+
client.close()
24+
25+
or asynchronous example::
26+
27+
# create client object
28+
async_client = AsyncModbusSerial("/dev/tty")
29+
30+
# connect to device
31+
await async_client.connect()
32+
33+
# set/set information
34+
rr = await async_client.read_coils(0x01)
35+
await async_client.write_coil(0x01, values)
36+
37+
# disconnect device
38+
await async_client.close()
39+
2540

2641
.. toctree::
2742

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,63 @@
11
Client setup.
22
=============
33

4-
Pymodbus offers different transport protocols Serial/TCP/TLS/UDP, which are implemented
5-
as separate classes. Each class defines exactly on transport type.
4+
Pymodbus offers different transport protocols Serial/TCP/TLS/UDP,
5+
which are implemented as separate classes.
6+
Each class defines exactly on transport type.
67

78
Applications can add custom transport types as long as the new class inherits
8-
from class BaseOldModbusClient.
9+
from class ModbusBaseClient.
910

10-
Applications can also custom decoders and customer framers.
11+
Applications can also use customer framers.
1112

1213
All transport types are supplied in 2 versions:
1314

1415
a :mod:`synchronous client <pymodbus.client>` and
1516

1617
a :mod:`asynchronous client based on asyncio <pymodbus.client.asynchronous>`.
1718

18-
Care have been made to ensure that large parts of the actual implementation or shared
19-
between the different classes, to ensure a higher stability.
19+
Large parts of the actual implementation are shared between the different classes,
20+
to ensure a higher stability and more efficient maintenance.
2021

21-
Common parameters for all clients.
22-
----------------------------------
22+
Common parameters/methods for all clients.
23+
------------------------------------------
2324

24-
.. automodule:: pymodbus.client.base
25+
.. autoclass:: pymodbus.client.base.ModbusBaseClient
2526
:members:
2627
:member-order: bysource
2728

2829
Serial RS-485 transport.
2930
------------------------
3031

31-
.. automodule:: pymodbus.client.async_serial
32+
.. autoclass:: pymodbus.client.async_serial.AsyncModbusSerialClient
3233
:members:
3334

34-
.. automodule:: pymodbus.client.sync_serial
35+
.. autoclass:: pymodbus.client.sync_serial.ModbusSerialClient
3536
:members:
3637

3738
TCP transport.
3839
--------------
3940

40-
.. automodule:: pymodbus.client.async_tcp
41+
.. autoclass:: pymodbus.client.async_tcp.AsyncModbusTcpClient
4142
:members:
4243

43-
.. automodule:: pymodbus.client.sync_tcp
44+
.. autoclass:: pymodbus.client.sync_tcp.ModbusTcpClient
4445
:members:
4546

4647
TLS transport.
4748
--------------
4849

49-
.. automodule:: pymodbus.client.async_tls
50+
.. autoclass:: pymodbus.client.async_tls.AsyncModbusTlsClient
5051
:members:
5152

52-
.. automodule:: pymodbus.client.sync_tls
53+
.. autoclass:: pymodbus.client.sync_tls.ModbusTlsClient
5354
:members:
5455

5556
UDP transport.
5657
--------------
5758

58-
.. automodule:: pymodbus.client.async_udp
59+
.. autoclass:: pymodbus.client.async_udp.AsyncModbusUdpClient
5960
:members:
6061

61-
.. automodule:: pymodbus.client.sync_udp
62+
.. autoclass:: pymodbus.client.sync_udp.ModbusUdpClient
6263
:members:

examples/client_async.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ def setup_client(args=None):
5656
"127.0.0.1",
5757
port=args.port, # on which port
5858
# Common optional paramers:
59-
# modbus_decoder=ClientDecoder,
6059
framer=args.framer,
6160
# timeout=10,
6261
# retries=3,
@@ -71,7 +70,6 @@ def setup_client(args=None):
7170
"127.0.0.1",
7271
port=args.port,
7372
# Common optional paramers:
74-
# modbus_decoder=ClientDecoder,
7573
framer=args.framer,
7674
# timeout=10,
7775
# retries=3,
@@ -85,7 +83,6 @@ def setup_client(args=None):
8583
client = AsyncModbusSerialClient(
8684
args.port,
8785
# Common optional paramers:
88-
# modbus_decoder=ClientDecoder,
8986
# framer=ModbusRtuFramer,
9087
# timeout=10,
9188
# retries=3,
@@ -104,7 +101,6 @@ def setup_client(args=None):
104101
"localhost",
105102
port=args.port,
106103
# Common optional paramers:
107-
# modbus_decoder=ClientDecoder,
108104
framer=args.framer,
109105
# timeout=10,
110106
# retries=3,
@@ -124,11 +120,11 @@ def setup_client(args=None):
124120
async def run_client(client, modbus_calls=None):
125121
"""Run sync client."""
126122
_logger.info("### Client starting")
127-
await client.aConnect()
123+
await client.connect()
128124
assert client.protocol
129125
if modbus_calls:
130126
await modbus_calls(client.protocol)
131-
await client.aClose()
127+
await client.close()
132128
_logger.info("### End of Program")
133129

134130

examples/client_sync.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ def setup_client(args=None):
5353
"127.0.0.1",
5454
port=args.port,
5555
# Common optional paramers:
56-
# modbus_decoder=ClientDecoder,
5756
framer=args.framer,
5857
# timeout=10,
5958
# retries=3,
@@ -68,7 +67,6 @@ def setup_client(args=None):
6867
"localhost",
6968
port=args.port,
7069
# Common optional paramers:
71-
# modbus_decoder=ClientDecoder,
7270
framer=args.framer,
7371
# timeout=10,
7472
# retries=3,
@@ -82,7 +80,6 @@ def setup_client(args=None):
8280
client = ModbusSerialClient(
8381
port=args.port, # serial port
8482
# Common optional paramers:
85-
# modbus_decoder=ClientDecoder,
8683
# framer=ModbusRtuFramer,
8784
# timeout=10,
8885
# retries=3,
@@ -101,7 +98,6 @@ def setup_client(args=None):
10198
"localhost",
10299
port=args.port,
103100
# Common optional paramers:
104-
# modbus_decoder=ClientDecoder,
105101
framer=args.framer,
106102
# timeout=10,
107103
# retries=3,

examples/contrib/libmodbus_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ class LibmodbusLevel1Client:
143143
"""
144144

145145
@classmethod
146-
def create_tcp_client(cls, my_host="127.0.0.1", my_port=Defaults.Port):
146+
def create_tcp_client(cls, my_host="127.0.0.1", my_port=Defaults.TcpPort):
147147
"""Create a TCP modbus client for the supplied parameters.
148148
149149
:param host: The host to connect to

pymodbus/client/async_serial.py

Lines changed: 45 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,58 @@
1-
"""**Modbus client async serial communication.**
2-
3-
The serial communication is RS-485 based, and usually used vith a usb RS485 dongle.
4-
5-
Example::
6-
7-
from pymodbus.client import AsyncModbusSerialClient
8-
9-
async def run():
10-
client = AsyncModbusSerialClient(
11-
"dev/pty0", # serial port
12-
# Common optional paramers:
13-
# modbus_decoder=ClientDecoder,
14-
# framer=ModbusRtuFramer,
15-
# timeout=10,
16-
# retries=3,
17-
# retry_on_empty=False,
18-
# close_comm_on_error=False,
19-
# strict=True,
20-
# Serial setup parameters
21-
# baudrate=9600,
22-
# bytesize=8,
23-
# parity="N",
24-
# stopbits=1,
25-
# handle_local_echo=False,
26-
)
27-
28-
await client.aConnect()
29-
...
30-
await client.aClose()
31-
"""
1+
"""Modbus client async serial communication."""
322
import asyncio
333
import logging
344

355
from serial_asyncio import create_serial_connection
366

377
from pymodbus.client.base import ModbusClientProtocol
8+
from pymodbus.framer import ModbusFramer
389
from pymodbus.transaction import ModbusRtuFramer
3910
from pymodbus.client.base import ModbusBaseClient
11+
from pymodbus.constants import Defaults
4012

4113
_logger = logging.getLogger(__name__)
4214

4315

4416
class AsyncModbusSerialClient(ModbusBaseClient):
45-
r"""Modbus client for async serial (RS-485) communication.
46-
47-
:param port: (positional) Serial port used for communication.
48-
:param framer: (optional, default ModbusRtuFramer) Framer class.
49-
:param baudrate: (optional, default 9600) Bits pr second.
50-
:param bytesize: (optional, default 8) Number of bits pr byte 7-8.
51-
:param parity: (optional, default None).
52-
:param stopbits: (optional, default 1) Number of stop bits 0-2 to use.
53-
:param handle_local_echo: (optional, default false) Handle local echo of the USB-to-RS485 dongle.
54-
:param \*\*kwargs: (optional) Extra experimental parameters for transport
55-
:return: client object
17+
"""**AsyncModbusSerialClient**.
18+
19+
:param port: Serial port used for communication.
20+
:param framer: (optional) Framer class.
21+
:param baudrate: (optional) Bits pr second.
22+
:param bytesize: (optional) Number of bits pr byte 7-8.
23+
:param parity: (optional) 'E'ven, 'O'dd or 'N'one
24+
:param stopbits: (optional) Number of stop bits 0-2¡.
25+
:param handle_local_echo: (optional) Discard local echo from dongle.
26+
:param kwargs: (optional) Experimental parameters
27+
28+
The serial communication is RS-485 based, and usually used vith a usb RS485 dongle.
29+
30+
Example::
31+
32+
from pymodbus.client import AsyncModbusSerialClient
33+
34+
async def run():
35+
client = AsyncModbusSerialClient("dev/serial0")
36+
37+
await client.connect()
38+
...
39+
await client.close()
5640
"""
5741

5842
transport = None
5943
framer = None
6044

6145
def __init__(
6246
self,
63-
port,
64-
framer=ModbusRtuFramer,
65-
baudrate=9600,
66-
bytesize=8,
67-
parity="N",
68-
stopbits=1,
69-
handle_local_echo=False,
70-
**kwargs,
71-
):
47+
port: str,
48+
framer: ModbusFramer = ModbusRtuFramer,
49+
baudrate: int = Defaults.Baudrate,
50+
bytesize: int = Defaults.Bytesize,
51+
parity: chr = Defaults.Parity,
52+
stopbits: int = Defaults.Stopbits,
53+
handle_local_echo: bool = Defaults.HandleLocalEcho,
54+
**kwargs: any,
55+
) -> None:
7256
"""Initialize Asyncio Modbus Serial Client."""
7357
super().__init__(framer=framer, **kwargs)
7458
self.params.port = port
@@ -81,8 +65,11 @@ def __init__(
8165
self.protocol = None
8266
self._connected_event = asyncio.Event()
8367

84-
async def aClose(self):
85-
"""Stop connection."""
68+
async def close(self): # pylint: disable=invalid-overridden-method
69+
"""Stop connection.
70+
71+
:meta private:
72+
"""
8673
if self._connected and self.protocol and self.protocol.transport:
8774
self.protocol.transport.close()
8875

@@ -97,8 +84,11 @@ def _connected(self):
9784
"""Connect internal."""
9885
return self._connected_event.is_set()
9986

100-
async def aConnect(self):
101-
"""Connect Async client."""
87+
async def connect(self): # pylint: disable=invalid-overridden-method
88+
"""Connect Async client.
89+
90+
:meta private:
91+
"""
10292
# get current loop, if there are no loop a RuntimeError will be raised
10393
self.loop = asyncio.get_running_loop()
10494

0 commit comments

Comments
 (0)