0
# PDU Messages
1
2
PyModbus provides complete implementation of all standard Modbus Protocol Data Units (PDUs) including bit operations, register operations, file operations, diagnostic functions, and device information queries. PDU classes can be used directly for custom protocol implementations or advanced use cases.
3
4
## Capabilities
5
6
### Base PDU Classes
7
8
Core PDU classes providing the foundation for all Modbus messages.
9
10
```python { .api }
11
class ModbusPDU:
12
def __init__(self, **kwargs): ...
13
def encode(self) -> bytes: ...
14
def decode(self, data: bytes): ...
15
def calculate_rtu_frame_size(data: bytes) -> int: ...
16
17
class ExceptionResponse(ModbusPDU):
18
function_code = 0x80
19
def __init__(self, function_code, exception_code=None, **kwargs): ...
20
def encode(self) -> bytes: ...
21
def decode(self, data: bytes): ...
22
23
class DecodePDU:
24
def __init__(self, data: bytes, **kwargs): ...
25
def decode(self) -> ModbusPDU: ...
26
```
27
28
### Bit Access Operations
29
30
PDU messages for reading and writing coil (binary) values.
31
32
```python { .api }
33
# Read Coils (FC 01)
34
class ReadCoilsRequest(ModbusPDU):
35
function_code = 0x01
36
def __init__(self, address=None, count=None, slave=0, **kwargs): ...
37
def encode(self) -> bytes: ...
38
def decode(self, data: bytes): ...
39
40
class ReadCoilsResponse(ModbusPDU):
41
function_code = 0x01
42
def __init__(self, values=None, **kwargs): ...
43
@property
44
def bits(self) -> list: ...
45
def encode(self) -> bytes: ...
46
def decode(self, data: bytes): ...
47
48
# Read Discrete Inputs (FC 02)
49
class ReadDiscreteInputsRequest(ModbusPDU):
50
function_code = 0x02
51
def __init__(self, address=None, count=None, slave=0, **kwargs): ...
52
def encode(self) -> bytes: ...
53
def decode(self, data: bytes): ...
54
55
class ReadDiscreteInputsResponse(ModbusPDU):
56
function_code = 0x02
57
def __init__(self, values=None, **kwargs): ...
58
@property
59
def bits(self) -> list: ...
60
def encode(self) -> bytes: ...
61
def decode(self, data: bytes): ...
62
63
# Write Single Coil (FC 05)
64
class WriteSingleCoilRequest(ModbusPDU):
65
function_code = 0x05
66
def __init__(self, address=None, value=None, slave=0, **kwargs): ...
67
def encode(self) -> bytes: ...
68
def decode(self, data: bytes): ...
69
70
class WriteSingleCoilResponse(ModbusPDU):
71
function_code = 0x05
72
def __init__(self, address=None, value=None, **kwargs): ...
73
def encode(self) -> bytes: ...
74
def decode(self, data: bytes): ...
75
76
# Write Multiple Coils (FC 15)
77
class WriteMultipleCoilsRequest(ModbusPDU):
78
function_code = 0x0F
79
def __init__(self, address=None, values=None, slave=0, **kwargs): ...
80
def encode(self) -> bytes: ...
81
def decode(self, data: bytes): ...
82
83
class WriteMultipleCoilsResponse(ModbusPDU):
84
function_code = 0x0F
85
def __init__(self, address=None, count=None, **kwargs): ...
86
def encode(self) -> bytes: ...
87
def decode(self, data: bytes): ...
88
```
89
90
### Register Access Operations
91
92
PDU messages for reading and writing register (16-bit integer) values.
93
94
```python { .api }
95
# Read Holding Registers (FC 03)
96
class ReadHoldingRegistersRequest(ModbusPDU):
97
function_code = 0x03
98
def __init__(self, address=None, count=None, slave=0, **kwargs): ...
99
def encode(self) -> bytes: ...
100
def decode(self, data: bytes): ...
101
102
class ReadHoldingRegistersResponse(ModbusPDU):
103
function_code = 0x03
104
def __init__(self, values=None, **kwargs): ...
105
@property
106
def registers(self) -> list: ...
107
def encode(self) -> bytes: ...
108
def decode(self, data: bytes): ...
109
110
# Read Input Registers (FC 04)
111
class ReadInputRegistersRequest(ModbusPDU):
112
function_code = 0x04
113
def __init__(self, address=None, count=None, slave=0, **kwargs): ...
114
def encode(self) -> bytes: ...
115
def decode(self, data: bytes): ...
116
117
class ReadInputRegistersResponse(ModbusPDU):
118
function_code = 0x04
119
def __init__(self, values=None, **kwargs): ...
120
@property
121
def registers(self) -> list: ...
122
def encode(self) -> bytes: ...
123
def decode(self, data: bytes): ...
124
125
# Write Single Register (FC 06)
126
class WriteSingleRegisterRequest(ModbusPDU):
127
function_code = 0x06
128
def __init__(self, address=None, value=None, slave=0, **kwargs): ...
129
def encode(self) -> bytes: ...
130
def decode(self, data: bytes): ...
131
132
class WriteSingleRegisterResponse(ModbusPDU):
133
function_code = 0x06
134
def __init__(self, address=None, value=None, **kwargs): ...
135
def encode(self) -> bytes: ...
136
def decode(self, data: bytes): ...
137
138
# Write Multiple Registers (FC 16)
139
class WriteMultipleRegistersRequest(ModbusPDU):
140
function_code = 0x10
141
def __init__(self, address=None, values=None, slave=0, **kwargs): ...
142
def encode(self) -> bytes: ...
143
def decode(self, data: bytes): ...
144
145
class WriteMultipleRegistersResponse(ModbusPDU):
146
function_code = 0x10
147
def __init__(self, address=None, count=None, **kwargs): ...
148
def encode(self) -> bytes: ...
149
def decode(self, data: bytes): ...
150
151
# Read/Write Multiple Registers (FC 23)
152
class ReadWriteMultipleRegistersRequest(ModbusPDU):
153
function_code = 0x17
154
def __init__(self, read_address=None, read_count=None, write_address=None,
155
write_registers=None, slave=0, **kwargs): ...
156
def encode(self) -> bytes: ...
157
def decode(self, data: bytes): ...
158
159
class ReadWriteMultipleRegistersResponse(ModbusPDU):
160
function_code = 0x17
161
def __init__(self, values=None, **kwargs): ...
162
@property
163
def registers(self) -> list: ...
164
def encode(self) -> bytes: ...
165
def decode(self, data: bytes): ...
166
167
# Mask Write Register (FC 22)
168
class MaskWriteRegisterRequest(ModbusPDU):
169
function_code = 0x16
170
def __init__(self, address=None, and_mask=0xFFFF, or_mask=0x0000, slave=0, **kwargs): ...
171
def encode(self) -> bytes: ...
172
def decode(self, data: bytes): ...
173
174
class MaskWriteRegisterResponse(ModbusPDU):
175
function_code = 0x16
176
def __init__(self, address=None, and_mask=0xFFFF, or_mask=0x0000, **kwargs): ...
177
def encode(self) -> bytes: ...
178
def decode(self, data: bytes): ...
179
```
180
181
### File Record Operations
182
183
PDU messages for file record access operations.
184
185
```python { .api }
186
# File Record data structure
187
class FileRecord:
188
def __init__(self, file_number=0x00, record_number=0x0000, record_data=None): ...
189
def encode(self) -> bytes: ...
190
def decode(self, data: bytes): ...
191
192
# Read File Record (FC 20)
193
class ReadFileRecordRequest(ModbusPDU):
194
function_code = 0x14
195
def __init__(self, records=None, slave=0, **kwargs): ...
196
def encode(self) -> bytes: ...
197
def decode(self, data: bytes): ...
198
199
class ReadFileRecordResponse(ModbusPDU):
200
function_code = 0x14
201
def __init__(self, records=None, **kwargs): ...
202
def encode(self) -> bytes: ...
203
def decode(self, data: bytes): ...
204
205
# Write File Record (FC 21)
206
class WriteFileRecordRequest(ModbusPDU):
207
function_code = 0x15
208
def __init__(self, records=None, slave=0, **kwargs): ...
209
def encode(self) -> bytes: ...
210
def decode(self, data: bytes): ...
211
212
class WriteFileRecordResponse(ModbusPDU):
213
function_code = 0x15
214
def __init__(self, records=None, **kwargs): ...
215
def encode(self) -> bytes: ...
216
def decode(self, data: bytes): ...
217
218
# Read FIFO Queue (FC 24)
219
class ReadFifoQueueRequest(ModbusPDU):
220
function_code = 0x18
221
def __init__(self, address=None, slave=0, **kwargs): ...
222
def encode(self) -> bytes: ...
223
def decode(self, data: bytes): ...
224
225
class ReadFifoQueueResponse(ModbusPDU):
226
function_code = 0x18
227
def __init__(self, values=None, **kwargs): ...
228
def encode(self) -> bytes: ...
229
def decode(self, data: bytes): ...
230
```
231
232
### Diagnostic Operations
233
234
PDU messages for diagnostic and status operations.
235
236
```python { .api }
237
# Diagnostic Status (FC 08)
238
class DiagnosticStatusRequest(ModbusPDU):
239
function_code = 0x08
240
def __init__(self, sub_function_code=0x0000, data=None, slave=0, **kwargs): ...
241
def encode(self) -> bytes: ...
242
def decode(self, data: bytes): ...
243
244
class DiagnosticStatusResponse(ModbusPDU):
245
function_code = 0x08
246
def __init__(self, sub_function_code=0x0000, data=None, **kwargs): ...
247
def encode(self) -> bytes: ...
248
def decode(self, data: bytes): ...
249
250
# Read Exception Status (FC 07)
251
class ReadExceptionStatusRequest(ModbusPDU):
252
function_code = 0x07
253
def __init__(self, slave=0, **kwargs): ...
254
def encode(self) -> bytes: ...
255
def decode(self, data: bytes): ...
256
257
class ReadExceptionStatusResponse(ModbusPDU):
258
function_code = 0x07
259
def __init__(self, status=0x00, **kwargs): ...
260
def encode(self) -> bytes: ...
261
def decode(self, data: bytes): ...
262
263
# Get Communication Event Counter (FC 11)
264
class GetCommEventCounterRequest(ModbusPDU):
265
function_code = 0x0B
266
def __init__(self, slave=0, **kwargs): ...
267
def encode(self) -> bytes: ...
268
def decode(self, data: bytes): ...
269
270
class GetCommEventCounterResponse(ModbusPDU):
271
function_code = 0x0B
272
def __init__(self, status=0x0000, count=0x0000, **kwargs): ...
273
def encode(self) -> bytes: ...
274
def decode(self, data: bytes): ...
275
276
# Get Communication Event Log (FC 12)
277
class GetCommEventLogRequest(ModbusPDU):
278
function_code = 0x0C
279
def __init__(self, slave=0, **kwargs): ...
280
def encode(self) -> bytes: ...
281
def decode(self, data: bytes): ...
282
283
class GetCommEventLogResponse(ModbusPDU):
284
function_code = 0x0C
285
def __init__(self, status=0x0000, event_count=0x0000, message_count=0x0000,
286
events=None, **kwargs): ...
287
def encode(self) -> bytes: ...
288
def decode(self, data: bytes): ...
289
```
290
291
### Device Information Operations
292
293
PDU messages for device identification and server information.
294
295
```python { .api }
296
# Report Server ID (FC 17)
297
class ReportServerIdRequest(ModbusPDU):
298
function_code = 0x11
299
def __init__(self, slave=0, **kwargs): ...
300
def encode(self) -> bytes: ...
301
def decode(self, data: bytes): ...
302
303
class ReportServerIdResponse(ModbusPDU):
304
function_code = 0x11
305
def __init__(self, identifier=None, status=0x00, **kwargs): ...
306
def encode(self) -> bytes: ...
307
def decode(self, data: bytes): ...
308
309
# Read Device Information (FC 43)
310
class ReadDeviceInformationRequest(ModbusPDU):
311
function_code = 0x2B
312
def __init__(self, read_code=None, object_id=0x00, slave=0, **kwargs): ...
313
def encode(self) -> bytes: ...
314
def decode(self, data: bytes): ...
315
316
class ReadDeviceInformationResponse(ModbusPDU):
317
function_code = 0x2B
318
def __init__(self, read_code=None, conformity=0x01, more_follows=0x00,
319
next_object_id=0x00, number_of_objects=0x00, information=None, **kwargs): ...
320
def encode(self) -> bytes: ...
321
def decode(self, data: bytes): ...
322
```
323
324
### Device Support Classes
325
326
Supporting classes for device identification and statistics.
327
328
```python { .api }
329
class ModbusDeviceIdentification:
330
def __init__(self, info=None): ...
331
def update(self, value: dict): ...
332
def __getitem__(self, key): ...
333
def __setitem__(self, key, value): ...
334
def __iter__(self): ...
335
def summary(self) -> dict: ...
336
337
class ModbusPlusStatistics:
338
def __init__(self): ...
339
def reset(self): ...
340
def summary(self) -> dict: ...
341
```
342
343
## Usage Examples
344
345
### Direct PDU Usage
346
347
```python
348
from pymodbus.pdu.bit_message import ReadCoilsRequest, ReadCoilsResponse
349
from pymodbus.pdu.register_message import ReadHoldingRegistersRequest
350
351
# Create a read coils request
352
request = ReadCoilsRequest(address=0, count=8, slave=1)
353
encoded_request = request.encode()
354
print(f"Encoded request: {encoded_request.hex()}")
355
356
# Decode the request
357
decoded_request = ReadCoilsRequest()
358
decoded_request.decode(encoded_request)
359
print(f"Address: {decoded_request.address}, Count: {decoded_request.count}")
360
361
# Create a response
362
response = ReadCoilsResponse(values=[True, False, True, True, False, False, True, False])
363
encoded_response = response.encode()
364
print(f"Encoded response: {encoded_response.hex()}")
365
print(f"Coil bits: {response.bits}")
366
```
367
368
### Custom PDU Implementation
369
370
```python
371
from pymodbus.pdu import ModbusPDU
372
import struct
373
374
class CustomReadRequest(ModbusPDU):
375
function_code = 0x40 # Custom function code
376
377
def __init__(self, address=None, count=None, slave=0, **kwargs):
378
ModbusPDU.__init__(self, **kwargs)
379
self.address = address
380
self.count = count
381
self.slave = slave
382
383
def encode(self):
384
return struct.pack('>HH', self.address, self.count)
385
386
def decode(self, data):
387
self.address, self.count = struct.unpack('>HH', data)
388
389
class CustomReadResponse(ModbusPDU):
390
function_code = 0x40
391
392
def __init__(self, values=None, **kwargs):
393
ModbusPDU.__init__(self, **kwargs)
394
self.values = values or []
395
396
def encode(self):
397
result = struct.pack('B', len(self.values))
398
for value in self.values:
399
result += struct.pack('>H', value)
400
return result
401
402
def decode(self, data):
403
count = struct.unpack('B', data[0:1])[0]
404
self.values = []
405
for i in range(count):
406
value = struct.unpack('>H', data[1 + i*2:3 + i*2])[0]
407
self.values.append(value)
408
409
# Usage
410
request = CustomReadRequest(address=100, count=5, slave=1)
411
encoded = request.encode()
412
print(f"Custom request: {encoded.hex()}")
413
414
response = CustomReadResponse(values=[1000, 2000, 3000, 4000, 5000])
415
encoded = response.encode()
416
print(f"Custom response: {encoded.hex()}")
417
```
418
419
### Exception Response Handling
420
421
```python
422
from pymodbus.pdu.exceptionresponse import ExceptionResponse
423
from pymodbus.constants import ExcCodes
424
425
# Create exception response
426
exception = ExceptionResponse(function_code=0x03, exception_code=ExcCodes.ILLEGAL_ADDRESS)
427
encoded = exception.encode()
428
print(f"Exception response: {encoded.hex()}")
429
430
# Decode exception
431
decoded_exception = ExceptionResponse()
432
decoded_exception.decode(encoded)
433
print(f"Function code: {decoded_exception.function_code}")
434
print(f"Exception code: {decoded_exception.exception_code}")
435
```
436
437
### PDU Message Factory
438
439
```python
440
from pymodbus.pdu.decoders import DecodePDU
441
from pymodbus.pdu.bit_message import ReadCoilsRequest
442
from pymodbus.pdu.register_message import ReadHoldingRegistersRequest
443
444
# Register message types
445
DecodePDU.register(ReadCoilsRequest)
446
DecodePDU.register(ReadHoldingRegistersRequest)
447
448
# Create and encode different message types
449
coil_request = ReadCoilsRequest(address=0, count=10, slave=1)
450
register_request = ReadHoldingRegistersRequest(address=100, count=5, slave=2)
451
452
# Decode messages dynamically
453
decoder = DecodePDU()
454
decoded_coil = decoder.decode(coil_request.encode())
455
decoded_register = decoder.decode(register_request.encode())
456
457
print(f"Decoded coil request: FC={decoded_coil.function_code}, addr={decoded_coil.address}")
458
print(f"Decoded register request: FC={decoded_register.function_code}, addr={decoded_register.address}")
459
```
460
461
### File Record Operations
462
463
```python
464
from pymodbus.pdu.file_message import FileRecord, ReadFileRecordRequest, WriteFileRecordRequest
465
466
# Create file records
467
records_to_read = [
468
FileRecord(file_number=1, record_number=0, record_data=None),
469
FileRecord(file_number=1, record_number=1, record_data=None)
470
]
471
472
# Read file record request
473
read_request = ReadFileRecordRequest(records=records_to_read, slave=1)
474
encoded_read = read_request.encode()
475
print(f"Read file record request: {encoded_read.hex()}")
476
477
# Write file record request
478
records_to_write = [
479
FileRecord(file_number=1, record_number=0, record_data=[0x1234, 0x5678])
480
]
481
write_request = WriteFileRecordRequest(records=records_to_write, slave=1)
482
encoded_write = write_request.encode()
483
print(f"Write file record request: {encoded_write.hex()}")
484
```
485
486
### Device Information Queries
487
488
```python
489
from pymodbus.pdu.mei_message import ReadDeviceInformationRequest
490
from pymodbus import ModbusDeviceIdentification
491
492
# Read device information request
493
device_info_request = ReadDeviceInformationRequest(read_code=0x01, object_id=0x00, slave=1)
494
encoded = device_info_request.encode()
495
print(f"Device info request: {encoded.hex()}")
496
497
# Create device identification
498
device_id = ModbusDeviceIdentification()
499
device_id.VendorName = 'PyModbus'
500
device_id.ProductCode = 'PM'
501
device_id.VendorUrl = 'http://github.com/riptideio/pymodbus/'
502
device_id.ProductName = 'PyModbus Server'
503
device_id.ModelName = 'PyModbus Server'
504
device_id.MajorMinorRevision = '3.11.1'
505
506
print(f"Device identification: {device_id.summary()}")
507
```