11import asyncio
22import logging
33
4- from zigpy .exceptions import DeliveryError
54import zigpy .device
65import zigpy .application
76import zigpy .util
87from zigpy_zigate import types as t
8+ from zigpy_zigate .api import NoResponseError
99
1010LOGGER = logging .getLogger (__name__ )
1111
@@ -18,7 +18,6 @@ def __init__(self, api, database_file=None):
1818 api .set_application (self )
1919
2020 self ._pending = {}
21- self ._zigate_seq = {}
2221
2322 self ._nwk = 0
2423 self ._ieee = 0
@@ -106,78 +105,48 @@ def zigate_callback_handler(self, msg, response, lqi):
106105 return
107106 rssi = 0
108107 device .radio_details (lqi , rssi )
109- tsn , command_id , is_reply , args = self .deserialize (device , response [3 ],
110- response [2 ], response [- 1 ])
111- if is_reply :
112- self ._handle_reply (device , response , tsn , command_id , args )
113- else :
114- self .handle_message (device , False , response [1 ],
115- response [2 ],
116- response [3 ], response [4 ],
117- tsn , command_id , args )
108+ self .handle_message (device , response [1 ],
109+ response [2 ],
110+ response [3 ], response [4 ], response [- 1 ])
118111 elif msg == 0x8702 : # APS Data confirm Fail
119112 self ._handle_frame_failure (response [4 ], response [0 ])
120113
121- def _handle_reply (self , sender , response , tsn , command_id , args ):
122- try :
123- send_fut , reply_fut = self ._pending [tsn ]
124- if send_fut .done ():
125- self ._pending .pop (tsn )
126- if reply_fut :
127- reply_fut .set_result (args )
128- return
129- except KeyError :
130- LOGGER .warning ("Unexpected response TSN=%s command=%s args=%s" , tsn , command_id , args )
131- except asyncio .futures .InvalidStateError as exc :
132- LOGGER .debug ("Invalid state on future - probably duplicate response: %s" , exc )
133- # We've already handled, don't drop through to device handler
134- # EDIT : Temporary remove return since we can receive more that one reply with the same tsn
135- # return
136-
137- self .handle_message (sender , True , response [1 ],
138- response [2 ], response [3 ], response [4 ],
139- tsn , command_id , args )
140-
141114 def _handle_frame_failure (self , message_tag , status ):
142115 try :
143- send_fut , reply_fut = self ._pending .pop (message_tag )
144- send_fut .set_exception (DeliveryError ("Message send failure: %s" % (status , )))
145- if reply_fut :
146- reply_fut .cancel ()
116+ send_fut = self ._pending .pop (message_tag )
117+ send_fut .set_result (status )
147118 except KeyError :
148119 LOGGER .warning ("Unexpected message send failure" )
149120 except asyncio .futures .InvalidStateError as exc :
150121 LOGGER .debug ("Invalid state on future - probably duplicate response: %s" , exc )
151122
152123 @zigpy .util .retryable_request
153- async def request (self , nwk , profile , cluster , src_ep , dst_ep , sequence , data , expect_reply = True , timeout = 10 ):
154- LOGGER .debug ('request %s' , (nwk , profile , cluster , src_ep , dst_ep , sequence , data , expect_reply , timeout ))
155- assert sequence not in self ._pending
124+ async def request (self , device , profile , cluster , src_ep , dst_ep , sequence , data ,
125+ expect_reply = True , use_ieee = False ):
126+ LOGGER .debug ('request %s' ,
127+ (device .nwk , profile , cluster , src_ep , dst_ep , sequence , data , expect_reply , use_ieee ))
128+ req_id = self .get_sequence ()
156129 send_fut = asyncio .Future ()
157- reply_fut = None
158- if expect_reply :
159- reply_fut = asyncio .Future ()
160- self ._pending [sequence ] = (send_fut , reply_fut )
161- v , lqi = await self ._api .raw_aps_data_request (nwk , src_ep , dst_ep , profile , cluster , data )
162- self ._zigate_seq [sequence ] = v [1 ]
130+ self ._pending [req_id ] = send_fut
131+ try :
132+ v , lqi = await self ._api .raw_aps_data_request (device .nwk , src_ep , dst_ep , profile , cluster , data )
133+ except NoResponseError :
134+ return 1 , "ZiGate doesn't answer to command"
163135
164136 if v [0 ] != 0 :
165- self ._pending .pop (sequence )
166- self ._zigate_seq .pop (sequence )
167- if expect_reply :
168- reply_fut .cancel ()
169- raise DeliveryError ("Message send failure %s" % (v [0 ], ))
170-
171- if expect_reply :
172- # Wait for reply
173- try :
174- v = await asyncio .wait_for (reply_fut , timeout )
175- except : # noqa: E722
176- # If we timeout (or fail for any reason), clear the future
177- self ._pending .pop (sequence )
178- self ._zigate_seq .pop (sequence )
179- raise
180- return v
137+ self ._pending .pop (req_id )
138+ return v [0 ], "Message send failure %s"
139+
140+ # Commented out for now
141+ # Currently (Firmware 3.1a) only send APS Data confirm in case of failure
142+ # try:
143+ # v = await asyncio.wait_for(send_fut, 120)
144+ # except asyncio.TimeoutError:
145+ # return 1, "timeout waiting for message %s send ACK" % (sequence, )
146+ # finally:
147+ # self._pending.pop(req_id)
148+ # return v, "Message sent"
149+ return 0 , "Message sent"
181150
182151 async def permit_ncp (self , time_s = 60 ):
183152 assert 0 <= time_s <= 254
0 commit comments