Skip to content

Commit 36253cd

Browse files
authored
Dev mixin client (#1056)
Complete/Document client mixin.
1 parent 3ce0dbd commit 36253cd

31 files changed

+625
-437
lines changed

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

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

doc/source/library/pymodbus.client.rst

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
================
12
pymodbus\.client
23
================
34

@@ -37,11 +38,63 @@ or asynchronous example::
3738
# disconnect device
3839
await async_client.close()
3940

41+
Pymodbus offers Serial/TCP/TLS/UDP as transport protocols, with the option to add
42+
custom protocols. Each transport protocol is implemented as
43+
a :mod:`synchronous client` and a :mod:`asynchronous client`
44+
45+
Large parts of the actual implementation are shared between the different classes,
46+
to ensure a higher stability and more efficient maintenance.
47+
48+
Client setup.
49+
-------------
50+
51+
Common parameters/methods.
52+
~~~~~~~~~~~~~~~~~~~~~~~~~~
53+
54+
.. autoclass:: pymodbus.client.base.ModbusBaseClient
55+
:members:
56+
:member-order: bysource
57+
58+
Serial RS-485 transport.
59+
~~~~~~~~~~~~~~~~~~~~~~~~
60+
61+
.. autoclass:: pymodbus.client.async_serial.AsyncModbusSerialClient
62+
63+
.. autoclass:: pymodbus.client.sync_serial.ModbusSerialClient
64+
65+
TCP transport.
66+
~~~~~~~~~~~~~~
67+
68+
.. autoclass:: pymodbus.client.async_tcp.AsyncModbusTcpClient
69+
70+
.. autoclass:: pymodbus.client.sync_tcp.ModbusTcpClient
71+
72+
TLS transport.
73+
~~~~~~~~~~~~~~
74+
75+
.. autoclass:: pymodbus.client.async_tls.AsyncModbusTlsClient
76+
77+
.. autoclass:: pymodbus.client.sync_tls.ModbusTlsClient
78+
79+
UDP transport.
80+
~~~~~~~~~~~~~~
81+
82+
.. autoclass:: pymodbus.client.async_udp.AsyncModbusUdpClient
83+
:members:
84+
85+
.. autoclass:: pymodbus.client.sync_udp.ModbusUdpClient
86+
:members:
87+
88+
89+
Client device calls.
90+
--------------------
4091

41-
.. toctree::
92+
Pymodbus makes a all standard modbus requests/responses available as simple calls.
4293

43-
pymodbus.client.setup
94+
All calls are available as synchronous and asynchronous (asyncio based).
4495

45-
.. toctree::
96+
Using Modbus<transport>Client.register() custom messagees can be added to pymodbus,
97+
and handled automatically.
4698

47-
pymodbus.client.calls
99+
.. autoclass:: pymodbus.client.mixin.ModbusClientMixin
100+
:members:

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

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

doc/source/library/pymodbus.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Subpackages
1010
-----------
1111

1212
.. toctree::
13+
:maxdepth: 4
1314

1415
pymodbus.client
1516
pymodbus.constants
@@ -166,5 +167,3 @@ pymodbus\.version module
166167
:members:
167168
:undoc-members:
168169
:show-inheritance:
169-
170-

examples/client_async_basic_calls.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,34 @@
1010

1111
from examples.client_async import _logger, run_client, setup_client
1212

13-
UNIT = 0x01
13+
SLAVE = 0x01
1414

1515

1616
async def handle_coils(client):
1717
"""Read/Write coils."""
1818
_logger.info("### Reading Coil")
19-
rr = await client.read_coils(1, 1, unit=UNIT)
19+
rr = await client.read_coils(1, 1, slave=SLAVE)
2020
assert not rr.isError() # test that call was OK
2121
txt = f"### coils response: {str(rr.bits)}"
2222
_logger.debug(txt)
2323

2424
_logger.info("### Reading Coils to get bit 5")
25-
rr = await client.read_coils(1, 5, unit=UNIT)
25+
rr = await client.read_coils(1, 5, slave=SLAVE)
2626
assert not rr.isError() # test that call was OK
2727
txt = f"### coils response: {str(rr.bits)}"
2828
_logger.debug(txt)
2929

3030
_logger.info("### Write true to coil bit 0 and read to verify")
31-
rq = await client.write_coil(0, True, unit=UNIT)
32-
rr = await client.read_coils(0, 1, unit=UNIT)
31+
rq = await client.write_coil(0, True, slave=SLAVE)
32+
rr = await client.read_coils(0, 1, slave=SLAVE)
3333
assert not rq.isError() and not rr.isError() # test that calls was OK
3434
assert rr.bits[0] # test the expected value
3535
txt = f"### coils response: {str(rr.bits)}"
3636
_logger.debug(txt)
3737

3838
_logger.info("### Write true to multiple coils 1-8")
39-
rq = await client.write_coils(1, [True] * 21, unit=UNIT)
40-
rr = await client.read_coils(1, 21, unit=UNIT)
39+
rq = await client.write_coils(1, [True] * 21, slave=SLAVE)
40+
rr = await client.read_coils(1, 21, slave=SLAVE)
4141
assert not rq.isError() and not rr.isError() # test that calls was OK
4242
resp = [True] * 21
4343
# If the returned output quantity is not a multiple of eight,
@@ -49,8 +49,8 @@ async def handle_coils(client):
4949
_logger.debug(txt)
5050

5151
_logger.info("### Write False to address 1-8 coils")
52-
rq = await client.write_coils(1, [False] * 8, unit=UNIT)
53-
rr = await client.read_coils(1, 8, unit=UNIT)
52+
rq = await client.write_coils(1, [False] * 8, slave=SLAVE)
53+
rr = await client.read_coils(1, 8, slave=SLAVE)
5454
assert not rq.isError() and not rr.isError() # test that calls was OK
5555
assert rr.bits == [False] * 8 # test the expected value
5656
txt = f"### coils response: {str(rr.bits)}"
@@ -60,7 +60,7 @@ async def handle_coils(client):
6060
async def handle_discrete_input(client):
6161
"""Read discrete inputs."""
6262
_logger.info("### Reading discrete input, Read address:0-7")
63-
rr = await client.read_discrete_inputs(0, 8, unit=UNIT)
63+
rr = await client.read_discrete_inputs(0, 8, slave=SLAVE)
6464
assert not rr.isError() # nosec test that we are not an error
6565
txt = f"### address 0-7 is: {str(rr.bits)}"
6666
_logger.debug(txt)
@@ -69,16 +69,16 @@ async def handle_discrete_input(client):
6969
async def handle_holding_registers(client):
7070
"""Read/write holding registers."""
7171
_logger.info("### write holding register and read holding registers")
72-
rq = await client.write_register(1, 10, unit=UNIT)
73-
rr = await client.read_holding_registers(1, 1, unit=UNIT)
72+
rq = await client.write_register(1, 10, slave=SLAVE)
73+
rr = await client.read_holding_registers(1, 1, slave=SLAVE)
7474
assert not rq.isError() and not rr.isError() # test that calls was OK
7575
assert rr.registers[0] == 10 # nosec test the expected value
7676
txt = f"### address 1 is: {str(rr.registers[0])}"
7777
_logger.debug(txt)
7878

7979
_logger.info("### write holding registers and read holding registers")
80-
rq = await client.write_registers(1, [10] * 8, unit=UNIT)
81-
rr = await client.read_holding_registers(1, 8, unit=UNIT)
80+
rq = await client.write_registers(1, [10] * 8, slave=SLAVE)
81+
rr = await client.read_holding_registers(1, 8, slave=SLAVE)
8282
assert not rq.isError() and not rr.isError() # test that calls was OK
8383
assert rr.registers == [10] * 8 # nosec test the expected value
8484
txt = f"### address 1-8 is: {str(rr.registers)}"
@@ -91,8 +91,8 @@ async def handle_holding_registers(client):
9191
"write_address": 1,
9292
"write_registers": [256, 128, 100, 50, 25, 10, 5, 1],
9393
}
94-
rq = await client.readwrite_registers(unit=UNIT, **arguments)
95-
rr = await client.read_holding_registers(1, 8, unit=UNIT)
94+
rq = await client.readwrite_registers(unit=SLAVE, **arguments)
95+
rr = await client.read_holding_registers(1, 8, slave=SLAVE)
9696
assert not rq.isError() and not rr.isError() # test that calls was OK
9797
assert rq.registers == arguments["write_registers"]
9898
assert rr.registers == arguments["write_registers"]
@@ -103,7 +103,7 @@ async def handle_holding_registers(client):
103103
async def handle_input_registers(client):
104104
"""Read input registers."""
105105
_logger.info("### read input registers")
106-
rr = await client.read_input_registers(1, 8, unit=UNIT)
106+
rr = await client.read_input_registers(1, 8, slave=SLAVE)
107107
assert not rr.isError() # nosec test that we are not an error
108108
txt = f"### address 1 is: {str(rr.registers[0])}"
109109
_logger.debug(txt)

examples/client_sync_basic_calls.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,34 @@
88
"""
99
from examples.client_sync import _logger, run_client, setup_client
1010

11-
UNIT = 0x01
11+
SLAVE = 0x01
1212

1313

1414
def handle_coils(client):
1515
"""Read/Write coils."""
1616
_logger.info("### Reading Coil")
17-
rr = client.read_coils(1, 1, unit=UNIT)
17+
rr = client.read_coils(1, 1, slave=SLAVE)
1818
assert not rr.isError() # test that call was OK
1919
txt = f"### coils response: {str(rr.bits)}"
2020
_logger.debug(txt)
2121

2222
_logger.info("### Reading Coils to get bit 5")
23-
rr = client.read_coils(1, 5, unit=UNIT)
23+
rr = client.read_coils(1, 5, slave=SLAVE)
2424
assert not rr.isError() # test that call was OK
2525
txt = f"### coils response: {str(rr.bits)}"
2626
_logger.debug(txt)
2727

2828
_logger.info("### Write true to coil bit 0 and read to verify")
29-
rq = client.write_coil(0, True, unit=UNIT)
30-
rr = client.read_coils(0, 1, unit=UNIT)
29+
rq = client.write_coil(0, True, slave=SLAVE)
30+
rr = client.read_coils(0, 1, slave=SLAVE)
3131
assert not rq.isError() and not rr.isError() # test that calls was OK
3232
assert rr.bits[0] # test the expected value
3333
txt = f"### coils response: {str(rr.bits)}"
3434
_logger.debug(txt)
3535

3636
_logger.info("### Write true to multiple coils 1-8")
37-
rq = client.write_coils(1, [True] * 21, unit=UNIT)
38-
rr = client.read_coils(1, 21, unit=UNIT)
37+
rq = client.write_coils(1, [True] * 21, slave=SLAVE)
38+
rr = client.read_coils(1, 21, slave=SLAVE)
3939
assert not rq.isError() and not rr.isError() # test that calls was OK
4040
resp = [True] * 21
4141
# If the returned output quantity is not a multiple of eight,
@@ -47,8 +47,8 @@ def handle_coils(client):
4747
_logger.debug(txt)
4848

4949
_logger.info("### Write False to address 1-8 coils")
50-
rq = client.write_coils(1, [False] * 8, unit=UNIT)
51-
rr = client.read_coils(1, 8, unit=UNIT)
50+
rq = client.write_coils(1, [False] * 8, slave=SLAVE)
51+
rr = client.read_coils(1, 8, slave=SLAVE)
5252
assert not rq.isError() and not rr.isError() # test that calls was OK
5353
assert rr.bits == [False] * 8 # test the expected value
5454
txt = f"### coils response: {str(rr.bits)}"
@@ -58,7 +58,7 @@ def handle_coils(client):
5858
def handle_discrete_input(client):
5959
"""Read discrete inputs."""
6060
_logger.info("### Reading discrete input, Read address:0-7")
61-
rr = client.read_discrete_inputs(0, 8, unit=UNIT)
61+
rr = client.read_discrete_inputs(0, 8, slave=SLAVE)
6262
assert not rr.isError() # nosec test that we are not an error
6363
txt = f"### address 0-7 is: {str(rr.bits)}"
6464
_logger.debug(txt)
@@ -67,16 +67,16 @@ def handle_discrete_input(client):
6767
def handle_holding_registers(client):
6868
"""Read/write holding registers."""
6969
_logger.info("### write holding register and read holding registers")
70-
rq = client.write_register(1, 10, unit=UNIT)
71-
rr = client.read_holding_registers(1, 1, unit=UNIT)
70+
rq = client.write_register(1, 10, slave=SLAVE)
71+
rr = client.read_holding_registers(1, 1, slave=SLAVE)
7272
assert not rq.isError() and not rr.isError() # test that calls was OK
7373
assert rr.registers[0] == 10 # nosec test the expected value
7474
txt = f"### address 1 is: {str(rr.registers[0])}"
7575
_logger.debug(txt)
7676

7777
_logger.info("### write holding registers and read holding registers")
78-
rq = client.write_registers(1, [10] * 8, unit=UNIT)
79-
rr = client.read_holding_registers(1, 8, unit=UNIT)
78+
rq = client.write_registers(1, [10] * 8, slave=SLAVE)
79+
rr = client.read_holding_registers(1, 8, slave=SLAVE)
8080
assert not rq.isError() and not rr.isError() # test that calls was OK
8181
assert rr.registers == [10] * 8 # nosec test the expected value
8282
txt = f"### address 1-8 is: {str(rr.registers)}"
@@ -89,8 +89,8 @@ def handle_holding_registers(client):
8989
"write_address": 1,
9090
"write_registers": [256, 128, 100, 50, 25, 10, 5, 1],
9191
}
92-
rq = client.readwrite_registers(unit=UNIT, **arguments)
93-
rr = client.read_holding_registers(1, 8, unit=UNIT)
92+
rq = client.readwrite_registers(unit=SLAVE, **arguments)
93+
rr = client.read_holding_registers(1, 8, slave=SLAVE)
9494
assert not rq.isError() and not rr.isError() # test that calls was OK
9595
assert rq.registers == arguments["write_registers"]
9696
assert rr.registers == arguments["write_registers"]
@@ -101,7 +101,7 @@ def handle_holding_registers(client):
101101
def handle_input_registers(client):
102102
"""Read input registers."""
103103
_logger.info("### read input registers")
104-
rr = client.read_input_registers(1, 8, unit=UNIT)
104+
rr = client.read_input_registers(1, 8, slave=SLAVE)
105105
assert not rr.isError() # nosec test that we are not an error
106106
txt = f"### address 1 is: {str(rr.registers[0])}"
107107
_logger.debug(txt)

examples/common/payload_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def run_binary_payload_client():
107107
print("Reading Registers:")
108108
address = 0x0
109109
count = len(payload)
110-
result = client.read_holding_registers(address, count, unit=1)
110+
result = client.read_holding_registers(address, count, slave=1)
111111
print(result.registers)
112112
print("\n")
113113
decoder = BinaryPayloadDecoder.fromRegisters(

examples/common/performance.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def single_client_test(n_host, n_cycles):
6565
count = 0
6666
client = ModbusTcpClient(n_host, port=5020)
6767
while count < n_cycles:
68-
client.read_holding_registers(10, 123, unit=1)
68+
client.read_holding_registers(10, 123, slave=1)
6969
count += 1
7070
except Exception: # pylint: disable=broad-except
7171
logger.exception("failed to run test successfully")

examples/contrib/libmodbus_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def __init__(self, my_client):
184184
:param client: The underlying client instance to operate with.
185185
"""
186186
self.client = my_client
187-
self.slave = Defaults.UnitId
187+
self.slave = Defaults.Slave
188188

189189
def set_slave(self, slave):
190190
"""Set the current slave to operate against.

0 commit comments

Comments
 (0)