@@ -31,163 +31,13 @@ async def run():
3131
3232from pymodbus .client .base import ModbusBaseClient
3333from pymodbus .transaction import ModbusSocketFramer
34- # from pymodbus.client.helper_async import ModbusClientProtocol
35- from pymodbus .exceptions import ConnectionException
36- from pymodbus .utilities import hexlify_packets
34+ from pymodbus .client .base import ModbusClientProtocol
3735
3836_logger = logging .getLogger (__name__ )
3937
4038DGRAM_TYPE = socket .SOCK_DGRAM
4139
4240
43- class ModbusUdpClientProtocol (ModbusBaseClient , asyncio .DatagramProtocol ):
44- """Asyncio specific implementation of asynchronous modbus udp client protocol."""
45-
46- #: Factory that created this instance.
47- factory = None
48- transport = None
49-
50- def __init__ (
51- self ,
52- host = "127.0.0.1" ,
53- port = 502 ,
54- framer = None ,
55- source_address = None ,
56- timeout = 10 ,
57- ** kwargs ,
58- ):
59- """Initialize a Modbus TCP/UDP asynchronous client
60-
61- :param host: Host IP address
62- :param port: Port
63- :param framer: Framer to use
64- :param source_address: Specific to underlying client being used
65- :param timeout: Timeout in seconds
66- :param kwargs: Extra arguments
67- """
68- self .host = host
69- self .port = port
70- self .source_address = source_address or ("" , 0 )
71- self ._timeout = timeout
72- self ._connected = False
73- super ().__init__ (framer = framer or ModbusSocketFramer , ** kwargs )
74-
75- def datagram_received (self , data , addr ):
76- """Receive datagram."""
77- self ._data_received (data )
78-
79- def write_transport (self , packet ):
80- """Write transport."""
81- return self .transport .sendto (packet )
82-
83- async def execute (self , request = None ): # pylint: disable=invalid-overridden-method
84- """Execute requests asynchronously."""
85- req = self ._execute (request )
86- if self .params .broadcast_enable and not request .unit_id :
87- resp = b"Broadcast write sent - no response expected"
88- else :
89- resp = await asyncio .wait_for (req , timeout = self ._timeout )
90- return resp
91-
92- def connection_made (self , transport ):
93- """Call when a connection is made.
94-
95- The transport argument is the transport representing the connection.
96- """
97- self .transport = transport
98- self ._connection_made ()
99-
100- if self .factory :
101- self .factory .protocol_made_connection (self ) # pylint: disable=no-member
102-
103- def connection_lost (self , reason ):
104- """Call when the connection is lost or closed."""
105- self .transport = None
106- self ._connection_lost (reason )
107-
108- if self .factory :
109- self .factory .protocol_lost_connection (self ) # pylint: disable=no-member
110-
111- def data_received (self , data ):
112- """Call when some data is received."""
113- self ._data_received (data )
114-
115- def create_future (self ):
116- """Create asyncio Future object."""
117- return asyncio .Future ()
118-
119- def resolve_future (self , my_future , result ):
120- """Resolve future."""
121- if not my_future .done ():
122- my_future .set_result (result )
123-
124- def raise_future (self , my_future , exc ):
125- """Set exception of a future if not done."""
126- if not my_future .done ():
127- my_future .set_exception (exc )
128-
129- def _connection_made (self ):
130- """Call upon a successful client connection."""
131- _logger .debug ("Client connected to modbus server" )
132- self ._connected = True
133-
134- def _connection_lost (self , reason ):
135- """Call upon a client disconnect."""
136- txt = f"Client disconnected from modbus server: { reason } "
137- _logger .debug (txt )
138- self ._connected = False
139- for tid in list (self .transaction ):
140- self .raise_future (
141- self .transaction .getTransaction (tid ),
142- ConnectionException ("Connection lost during request" ),
143- )
144-
145- @property
146- def connected (self ):
147- """Return connection status."""
148- return self ._connected
149-
150- def _execute (self , request , ** kwargs ): # NOSONAR pylint: disable=unused-argument
151- """Start the producer to send the next request to consumer.write(Frame(request))."""
152- request .transaction_id = self .transaction .getNextTID ()
153- packet = self .framer .buildPacket (request )
154- txt = f"send: { hexlify_packets (packet )} "
155- _logger .debug (txt )
156- self .write_transport (packet )
157- return self ._build_response (request .transaction_id )
158-
159- def _data_received (self , data ):
160- """Get response, check for valid message, decode result."""
161- txt = f"recv: { hexlify_packets (data )} "
162- _logger .debug (txt )
163- unit = self .framer .decode_data (data ).get ("unit" , 0 )
164- self .framer .processIncomingPacket (data , self ._handle_response , unit = unit )
165-
166- def _handle_response (self , reply , ** kwargs ): # pylint: disable=unused-argument
167- """Handle the processed response and link to correct deferred."""
168- if reply is not None :
169- tid = reply .transaction_id
170- if handler := self .transaction .getTransaction (tid ):
171- self .resolve_future (handler , reply )
172- else :
173- txt = f"Unrequested message: { str (reply )} "
174- _logger .debug (txt )
175-
176- def _build_response (self , tid ):
177- """Return a deferred response for the current request."""
178- my_future = self .create_future ()
179- if not self ._connected :
180- self .raise_future (my_future , ConnectionException ("Client is not connected" ))
181- else :
182- self .transaction .addTransaction (my_future , tid )
183- return my_future
184-
185- def close (self ):
186- """Close."""
187- self .transport .close ()
188- self ._connected = False
189-
190-
19141class AsyncModbusUdpClient (ModbusBaseClient ):
19242 r"""Modbus client for async UDP communication.
19343
@@ -258,7 +108,7 @@ async def aClose(self):
258108
259109 def _create_protocol (self , host = None , port = 0 ):
260110 """Create initialized protocol instance with factory function."""
261- protocol = ModbusUdpClientProtocol (
111+ protocol = ModbusClientProtocol (
262112 use_udp = True ,
263113 framer = self .params .framer ,
264114 ** self .params .kwargs
0 commit comments