15
15
16
16
from pymodbus import FramerType
17
17
from pymodbus .client import AsyncModbusTcpClient as ModbusClient
18
+ from pymodbus .datastore import (
19
+ ModbusSequentialDataBlock ,
20
+ ModbusServerContext ,
21
+ ModbusSlaveContext ,
22
+ )
18
23
from pymodbus .exceptions import ModbusIOException
19
- from pymodbus .pdu import ExceptionResponse , ModbusPDU
24
+ from pymodbus .pdu import ModbusPDU
20
25
from pymodbus .pdu .bit_message import ReadCoilsRequest
26
+ from pymodbus .server import ServerAsyncStop , StartAsyncTcpServer
21
27
22
28
23
29
# --------------------------------------------------------------------------- #
31
37
# --------------------------------------------------------------------------- #
32
38
33
39
34
- class CustomModbusPDU (ModbusPDU ):
40
+ class CustomModbusResponse (ModbusPDU ):
35
41
"""Custom modbus response."""
36
42
37
43
function_code = 55
@@ -73,7 +79,7 @@ def __init__(self, address=None, slave=1, transaction=0):
73
79
"""Initialize."""
74
80
super ().__init__ (dev_id = slave , transaction_id = transaction )
75
81
self .address = address
76
- self .count = 16
82
+ self .count = 2
77
83
78
84
def encode (self ):
79
85
"""Encode."""
@@ -83,14 +89,10 @@ def decode(self, data):
83
89
"""Decode."""
84
90
self .address , self .count = struct .unpack (">HH" , data )
85
91
86
- def execute (self , context ) :
92
+ async def update_datastore (self , context : ModbusSlaveContext ) -> ModbusPDU :
87
93
"""Execute."""
88
- if not 1 <= self .count <= 0x7D0 :
89
- return ExceptionResponse (self .function_code , ExceptionResponse .ILLEGAL_VALUE )
90
- if not context .validate (self .function_code , self .address , self .count ):
91
- return ExceptionResponse (self .function_code , ExceptionResponse .ILLEGAL_ADDRESS )
92
- values = context .getValues (self .function_code , self .address , self .count )
93
- return CustomModbusPDU (values )
94
+ _ = context
95
+ return CustomModbusResponse ()
94
96
95
97
96
98
# --------------------------------------------------------------------------- #
@@ -119,14 +121,25 @@ def __init__(self, address, slave=1, transaction=0):
119
121
120
122
async def main (host = "localhost" , port = 5020 ):
121
123
"""Run versions of read coil."""
124
+ store = ModbusServerContext (slaves = ModbusSlaveContext (
125
+ di = ModbusSequentialDataBlock (0 , [17 ] * 100 ),
126
+ co = ModbusSequentialDataBlock (0 , [17 ] * 100 ),
127
+ hr = ModbusSequentialDataBlock (0 , [17 ] * 100 ),
128
+ ir = ModbusSequentialDataBlock (0 , [17 ] * 100 ),
129
+ ),
130
+ single = True
131
+ )
132
+ task = asyncio .create_task (StartAsyncTcpServer (
133
+ context = store ,
134
+ address = (host , port ),
135
+ custom_functions = [CustomRequest ])
136
+ )
137
+ await asyncio .sleep (0.1 )
122
138
async with ModbusClient (host = host , port = port , framer = FramerType .SOCKET ) as client :
123
139
await client .connect ()
124
140
125
- # create a response object to control it works
126
- CustomModbusPDU ()
127
-
128
- # new modbus function code.
129
- client .register (CustomModbusPDU )
141
+ # add new modbus function code.
142
+ client .register (CustomModbusResponse )
130
143
slave = 1
131
144
request1 = CustomRequest (32 , slave = slave )
132
145
try :
@@ -140,6 +153,9 @@ async def main(host="localhost", port=5020):
140
153
request2 = Read16CoilsRequest (32 , slave )
141
154
result = await client .execute (False , request2 )
142
155
print (result )
156
+ await ServerAsyncStop ()
157
+ task .cancel ()
158
+ await task
143
159
144
160
145
161
if __name__ == "__main__" :
0 commit comments