0
# Client Operations
1
2
PyModbus provides comprehensive client implementations supporting all standard Modbus function codes. Clients are available in both synchronous and asynchronous variants across multiple transport protocols (TCP, UDP, Serial, TLS).
3
4
## Capabilities
5
6
### Client Classes
7
8
PyModbus offers dedicated client classes for each transport protocol in both synchronous and asynchronous variants.
9
10
```python { .api }
11
# Synchronous client classes
12
class ModbusTcpClient:
13
def __init__(self, host="127.0.0.1", port=502, framer=FramerType.SOCKET,
14
timeout=3, retries=3, retry_on_empty=False, close_comm_on_error=False,
15
strict=True, source_address=None, **kwargs): ...
16
def connect(self) -> bool: ...
17
def close(self) -> None: ...
18
19
class ModbusUdpClient:
20
def __init__(self, host="127.0.0.1", port=502, framer=FramerType.SOCKET,
21
timeout=3, retries=3, retry_on_empty=False, **kwargs): ...
22
def connect(self) -> bool: ...
23
def close(self) -> None: ...
24
25
class ModbusSerialClient:
26
def __init__(self, port=None, framer=FramerType.RTU, timeout=3, retries=3,
27
retry_on_empty=False, close_comm_on_error=False, strict=True,
28
baudrate=19200, bytesize=8, parity="N", stopbits=1, **kwargs): ...
29
def connect(self) -> bool: ...
30
def close(self) -> None: ...
31
32
class ModbusTlsClient:
33
def __init__(self, host="127.0.0.1", port=802, framer=FramerType.TLS,
34
timeout=3, retries=3, sslctx=None, certfile=None, keyfile=None,
35
password=None, server_hostname=None, **kwargs): ...
36
def connect(self) -> bool: ...
37
def close(self) -> None: ...
38
39
# Asynchronous client classes
40
class AsyncModbusTcpClient:
41
def __init__(self, host="127.0.0.1", port=502, framer=FramerType.SOCKET,
42
timeout=3, retries=3, retry_on_empty=False, close_comm_on_error=False,
43
strict=True, source_address=None, **kwargs): ...
44
async def connect(self) -> bool: ...
45
def close(self) -> None: ...
46
47
class AsyncModbusUdpClient:
48
def __init__(self, host="127.0.0.1", port=502, framer=FramerType.SOCKET,
49
timeout=3, retries=3, retry_on_empty=False, **kwargs): ...
50
async def connect(self) -> bool: ...
51
def close(self) -> None: ...
52
53
class AsyncModbusSerialClient:
54
def __init__(self, port=None, framer=FramerType.RTU, timeout=3, retries=3,
55
retry_on_empty=False, close_comm_on_error=False, strict=True,
56
baudrate=19200, bytesize=8, parity="N", stopbits=1, **kwargs): ...
57
async def connect(self) -> bool: ...
58
def close(self) -> None: ...
59
60
class AsyncModbusTlsClient:
61
def __init__(self, host="127.0.0.1", port=802, framer=FramerType.TLS,
62
timeout=3, retries=3, sslctx=None, certfile=None, keyfile=None,
63
password=None, server_hostname=None, **kwargs): ...
64
async def connect(self) -> bool: ...
65
def close(self) -> None: ...
66
```
67
68
### Base Client Classes and Mixin
69
70
All client classes inherit core functionality from base classes and the ModbusClientMixin providing standard Modbus operations.
71
72
```python { .api }
73
# Base client classes
74
class ModbusBaseClient:
75
"""Base asynchronous client class."""
76
def __init__(self, framer=None, **kwargs): ...
77
def connect(self) -> bool: ...
78
def close(self) -> None: ...
79
def execute(self, request) -> ModbusResponse: ...
80
def register(self, custom_response_class): ...
81
def set_max_no_responses(self, count: int): ...
82
83
class ModbusBaseSyncClient:
84
"""Base synchronous client class."""
85
def __init__(self, framer=None, **kwargs): ...
86
def connect(self) -> bool: ...
87
def close(self) -> None: ...
88
def execute(self, request) -> ModbusResponse: ...
89
def register(self, custom_response_class): ...
90
def set_max_no_responses(self, count: int): ...
91
92
class ModbusClientMixin:
93
"""
94
Mixin class providing all Modbus function code methods.
95
All client classes inherit from this mixin to provide standard operations.
96
"""
97
# Note: All the operation methods below (coils, registers, etc.)
98
# are provided by this mixin class
99
```
100
101
### Connection Management Methods
102
103
```python { .api }
104
def connect(self) -> bool: ...
105
def close(self) -> None: ...
106
def is_socket_open(self) -> bool: ...
107
```
108
109
### Coil Operations
110
111
Functions for reading and writing coil (binary) values.
112
113
```python { .api }
114
def read_coils(self, address, count=1, device_id=0) -> ReadCoilsResponse:
115
"""
116
Read coil status (FC 01).
117
118
Parameters:
119
- address (int): Starting address
120
- count (int): Number of coils to read
121
- device_id (int): Device identifier
122
123
Returns:
124
ReadCoilsResponse with .bits attribute containing list of boolean values
125
"""
126
127
def write_coil(self, address, value, device_id=0) -> WriteSingleCoilResponse:
128
"""
129
Write single coil (FC 05).
130
131
Parameters:
132
- address (int): Coil address
133
- value (bool): Coil value
134
- device_id (int): Device identifier
135
136
Returns:
137
WriteSingleCoilResponse
138
"""
139
140
def write_coils(self, address, values, device_id=0) -> WriteMultipleCoilsResponse:
141
"""
142
Write multiple coils (FC 15).
143
144
Parameters:
145
- address (int): Starting address
146
- values (list): List of boolean values
147
- device_id (int): Device identifier
148
149
Returns:
150
WriteMultipleCoilsResponse
151
"""
152
```
153
154
### Discrete Input Operations
155
156
Functions for reading discrete input values.
157
158
```python { .api }
159
def read_discrete_inputs(self, address, count=1, device_id=0) -> ReadDiscreteInputsResponse:
160
"""
161
Read discrete input status (FC 02).
162
163
Parameters:
164
- address (int): Starting address
165
- count (int): Number of inputs to read
166
- device_id (int): Device identifier
167
168
Returns:
169
ReadDiscreteInputsResponse with .bits attribute containing list of boolean values
170
"""
171
```
172
173
### Register Operations
174
175
Functions for reading and writing register (16-bit integer) values.
176
177
```python { .api }
178
def read_holding_registers(self, address, count=1, device_id=0) -> ReadHoldingRegistersResponse:
179
"""
180
Read holding registers (FC 03).
181
182
Parameters:
183
- address (int): Starting address
184
- count (int): Number of registers to read
185
- device_id (int): Device identifier
186
187
Returns:
188
ReadHoldingRegistersResponse with .registers attribute containing list of int values
189
"""
190
191
def read_input_registers(self, address, count=1, device_id=0) -> ReadInputRegistersResponse:
192
"""
193
Read input registers (FC 04).
194
195
Parameters:
196
- address (int): Starting address
197
- count (int): Number of registers to read
198
- device_id (int): Device identifier
199
200
Returns:
201
ReadInputRegistersResponse with .registers attribute containing list of int values
202
"""
203
204
def write_register(self, address, value, device_id=0) -> WriteSingleRegisterResponse:
205
"""
206
Write single register (FC 06).
207
208
Parameters:
209
- address (int): Register address
210
- value (int): Register value (0-65535)
211
- device_id (int): Device identifier
212
213
Returns:
214
WriteSingleRegisterResponse
215
"""
216
217
def write_registers(self, address, values, device_id=0) -> WriteMultipleRegistersResponse:
218
"""
219
Write multiple registers (FC 16).
220
221
Parameters:
222
- address (int): Starting address
223
- values (list): List of register values
224
- device_id (int): Device identifier
225
226
Returns:
227
WriteMultipleRegistersResponse
228
"""
229
230
def readwrite_registers(self, read_address, read_count, write_address, write_registers, device_id=0) -> ReadWriteMultipleRegistersResponse:
231
"""
232
Read and write multiple registers in single transaction (FC 23).
233
234
Parameters:
235
- read_address (int): Starting read address
236
- read_count (int): Number of registers to read
237
- write_address (int): Starting write address
238
- write_registers (list): Values to write
239
- device_id (int): Device identifier
240
241
Returns:
242
ReadWriteMultipleRegistersResponse with .registers attribute
243
"""
244
245
def mask_write_register(self, address, and_mask, or_mask, device_id=0) -> MaskWriteRegisterResponse:
246
"""
247
Mask write register (FC 22).
248
249
Parameters:
250
- address (int): Register address
251
- and_mask (int): AND mask
252
- or_mask (int): OR mask
253
- device_id (int): Device identifier
254
255
Returns:
256
MaskWriteRegisterResponse
257
"""
258
```
259
260
### File Record Operations
261
262
Functions for reading and writing file records.
263
264
```python { .api }
265
def read_file_record(self, records, device_id=0) -> ReadFileRecordResponse:
266
"""
267
Read file record (FC 20).
268
269
Parameters:
270
- records (list): List of file record requests
271
- device_id (int): Device identifier
272
273
Returns:
274
ReadFileRecordResponse
275
"""
276
277
def write_file_record(self, records, device_id=0) -> WriteFileRecordResponse:
278
"""
279
Write file record (FC 21).
280
281
Parameters:
282
- records (list): List of file record data
283
- device_id (int): Device identifier
284
285
Returns:
286
WriteFileRecordResponse
287
"""
288
289
def read_fifo_queue(self, address, device_id=0) -> ReadFifoQueueResponse:
290
"""
291
Read FIFO queue (FC 24).
292
293
Parameters:
294
- address (int): FIFO pointer address
295
- device_id (int): Device identifier
296
297
Returns:
298
ReadFifoQueueResponse
299
"""
300
```
301
302
### Diagnostic Operations
303
304
Functions for device diagnostics and status reporting.
305
306
```python { .api }
307
def diag_read_diagnostic_register(self, device_id=0) -> DiagnosticStatusResponse:
308
"""Read diagnostic register."""
309
310
def diag_change_ascii_input_delimiter(self, device_id=0) -> DiagnosticStatusResponse:
311
"""Change ASCII input delimiter."""
312
313
def diag_force_listen_only_mode(self, device_id=0) -> DiagnosticStatusResponse:
314
"""Force listen only mode."""
315
316
def diag_clear_counters(self, device_id=0) -> DiagnosticStatusResponse:
317
"""Clear counters and diagnostic register."""
318
319
def diag_read_bus_message_count(self, device_id=0) -> DiagnosticStatusResponse:
320
"""Read bus message count."""
321
322
def diag_read_bus_comm_error_count(self, device_id=0) -> DiagnosticStatusResponse:
323
"""Read bus communication error count."""
324
325
def diag_read_bus_exception_error_count(self, device_id=0) -> DiagnosticStatusResponse:
326
"""Read bus exception error count."""
327
328
def diag_read_device_message_count(self, device_id=0) -> DiagnosticStatusResponse:
329
"""Read device message count."""
330
331
def diag_read_device_no_response_count(self, device_id=0) -> DiagnosticStatusResponse:
332
"""Read device no response count."""
333
334
def diag_read_device_nak_count(self, device_id=0) -> DiagnosticStatusResponse:
335
"""Read device NAK count."""
336
337
def diag_read_device_busy_count(self, device_id=0) -> DiagnosticStatusResponse:
338
"""Read device busy count."""
339
340
def diag_read_bus_char_overrun_count(self, device_id=0) -> DiagnosticStatusResponse:
341
"""Read bus character overrun count."""
342
343
def diag_read_iop_overrun_count(self, device_id=0) -> DiagnosticStatusResponse:
344
"""Read IOP overrun count."""
345
346
def diag_clear_overrun_counter(self, device_id=0) -> DiagnosticStatusResponse:
347
"""Clear overrun counter and flag."""
348
349
def diag_get_clear_modbus_plus(self, device_id=0) -> DiagnosticStatusResponse:
350
"""Get/clear Modbus Plus statistics."""
351
```
352
353
### Device Information Operations
354
355
Functions for retrieving device information and identification.
356
357
```python { .api }
358
def read_device_information(self, read_code=None, object_id=0x00, device_id=0) -> ReadDeviceInformationResponse:
359
"""
360
Read device information (FC 43).
361
362
Parameters:
363
- read_code (int): Read device ID code (0x01, 0x02, 0x03, 0x04)
364
- object_id (int): Object ID to read
365
- device_id (int): Device identifier
366
367
Returns:
368
ReadDeviceInformationResponse with device information
369
"""
370
371
def report_device_id(self, device_id=0) -> ReportServerIdResponse:
372
"""
373
Report device identification (FC 17).
374
375
Parameters:
376
- device_id (int): Device identifier
377
378
Returns:
379
ReportServerIdResponse with device ID information
380
"""
381
```
382
383
### Event Operations
384
385
Functions for reading communication events and counters.
386
387
```python { .api }
388
def read_exception_status(self, device_id=0) -> ReadExceptionStatusResponse:
389
"""
390
Read exception status (FC 07).
391
392
Returns:
393
ReadExceptionStatusResponse with status byte
394
"""
395
396
def get_com_event_counter(self, device_id=0) -> GetCommEventCounterResponse:
397
"""
398
Get communication event counter (FC 11).
399
400
Returns:
401
GetCommEventCounterResponse with event count
402
"""
403
404
def get_com_event_log(self, device_id=0) -> GetCommEventLogResponse:
405
"""
406
Get communication event log (FC 12).
407
408
Returns:
409
GetCommEventLogResponse with event log data
410
"""
411
```
412
413
### Data Conversion Methods
414
415
Utility methods for converting between Python data types and Modbus register values.
416
417
```python { .api }
418
def convert_to_registers(self, value, data_type) -> list:
419
"""
420
Convert Python value to Modbus registers.
421
422
Parameters:
423
- value: Python value to convert
424
- data_type: Data type constant (INT16, INT32, FLOAT32, etc.)
425
426
Returns:
427
List of register values
428
"""
429
430
def convert_from_registers(self, registers, data_type):
431
"""
432
Convert Modbus registers to Python value.
433
434
Parameters:
435
- registers (list): List of register values
436
- data_type: Data type constant
437
438
Returns:
439
Converted Python value
440
"""
441
```
442
443
## Usage Examples
444
445
### TCP Client with Error Handling
446
447
```python
448
from pymodbus.client import ModbusTcpClient
449
from pymodbus import FramerType, ModbusException
450
451
client = ModbusTcpClient('192.168.1.10', port=502, framer=FramerType.SOCKET)
452
453
try:
454
if client.connect():
455
# Read holding registers
456
result = client.read_holding_registers(0, count=10, device_id=1)
457
if not result.isError():
458
print(f"Registers: {result.registers}")
459
else:
460
print(f"Error reading registers: {result}")
461
462
# Write multiple registers
463
values = [100, 200, 300, 400, 500]
464
result = client.write_registers(10, values, device_id=1)
465
if result.isError():
466
print(f"Error writing registers: {result}")
467
else:
468
print("Failed to connect to Modbus server")
469
470
except ModbusException as e:
471
print(f"Modbus exception: {e}")
472
finally:
473
client.close()
474
```
475
476
### Serial Client with RTU Framing
477
478
```python
479
from pymodbus.client import ModbusSerialClient
480
from pymodbus import FramerType
481
482
client = ModbusSerialClient(
483
port='/dev/ttyUSB0',
484
baudrate=9600,
485
bytesize=8,
486
parity='N',
487
stopbits=1,
488
framer=FramerType.RTU,
489
timeout=1
490
)
491
492
if client.connect():
493
try:
494
# Read coils
495
result = client.read_coils(0, count=16, device_id=1)
496
if not result.isError():
497
print(f"Coil states: {result.bits}")
498
499
# Write single coil
500
client.write_coil(5, True, device_id=1)
501
502
finally:
503
client.close()
504
```
505
506
### Async Client Pattern
507
508
```python
509
import asyncio
510
from pymodbus.client import AsyncModbusTcpClient
511
512
async def async_modbus_client():
513
client = AsyncModbusTcpClient('127.0.0.1', port=502)
514
515
try:
516
await client.connect()
517
518
# Read input registers
519
result = await client.read_input_registers(0, count=5, device_id=1)
520
if not result.isError():
521
print(f"Input registers: {result.registers}")
522
523
# Read/write operation
524
result = await client.readwrite_registers(
525
read_address=0, read_count=5,
526
write_address=10, write_registers=[1, 2, 3],
527
device_id=1
528
)
529
if not result.isError():
530
print(f"Read values: {result.registers}")
531
532
finally:
533
client.close()
534
535
# Run async client
536
asyncio.run(async_modbus_client())
537
```
538
539
### Data Type Conversion with Struct
540
541
```python
542
from pymodbus.client import ModbusTcpClient
543
import struct
544
545
client = ModbusTcpClient('127.0.0.1')
546
client.connect()
547
548
# Write float32 value using struct
549
float_value = 123.45
550
# Pack float as 2 registers (32-bit big-endian)
551
packed = struct.pack('>f', float_value)
552
registers = [struct.unpack('>H', packed[0:2])[0], struct.unpack('>H', packed[2:4])[0]]
553
client.write_registers(0, registers, device_id=1)
554
555
# Read float32 value
556
result = client.read_holding_registers(0, count=2, device_id=1)
557
if not result.isError():
558
# Unpack registers back to float
559
packed = struct.pack('>HH', result.registers[0], result.registers[1])
560
float_value = struct.unpack('>f', packed)[0]
561
print(f"Float value: {float_value}")
562
563
client.close()
564
```