88
99import  serial 
1010from  zigpy .config  import  CONF_DEVICE_PATH , SCHEMA_DEVICE 
11+ from  zigpy .datastructures  import  PriorityLock 
1112from  zigpy .exceptions  import  APIException , DeliveryError 
1213import  zigpy .types  as  t 
1314
@@ -289,7 +290,7 @@ def __init__(self, device_config: Dict[str, Any]) -> None:
289290        self ._cmd_mode_future : Optional [asyncio .Future ] =  None 
290291        self ._reset : asyncio .Event  =  asyncio .Event ()
291292        self ._running : asyncio .Event  =  asyncio .Event ()
292-         self ._send_lock  =  asyncio . Lock ()
293+         self ._send_lock  =  PriorityLock ()
293294
294295    @property  
295296    def  reset_event (self ):
@@ -334,33 +335,43 @@ def close(self):
334335            self ._uart .close ()
335336            self ._uart  =  None 
336337
337-     def  _command (self , name , * args , mask_frame_id = False ):
338+     def  _get_command_priority (self , name : str , * args ) ->  int :
339+         return  {
340+             "tx_explicit" : - 1 ,
341+             "remote_at" : - 1 ,
342+         }.get (name , 0 )
343+ 
344+     async  def  _command (self , name , * args , mask_frame_id = False ):
338345        """Send API frame to the device.""" 
339-         LOGGER .debug ("Command %s %s" , name , args )
340346        if  self ._uart  is  None :
341347            raise  APIException ("API is not running" )
342-         frame_id  =  0  if  mask_frame_id  else  self ._seq 
343-         data , needs_response  =  self ._api_frame (name , frame_id , * args )
344-         self ._uart .send (data )
345-         future  =  None 
346-         if  needs_response  and  frame_id :
348+ 
349+         async  with  self ._send_lock (priority = self ._get_command_priority (name )):
350+             LOGGER .debug ("Command %s %s" , name , args )
351+             frame_id  =  0  if  mask_frame_id  else  self ._seq 
352+             data , needs_response  =  self ._api_frame (name , frame_id , * args )
353+             self ._uart .send (data )
354+ 
355+             if  not  needs_response  or  not  frame_id :
356+                 return 
357+ 
347358            future  =  asyncio .Future ()
348359            self ._awaiting [frame_id ] =  (future ,)
349-         self ._seq  =  (self ._seq  %  255 ) +  1 
350-         return  future 
360+             self ._seq  =  (self ._seq  %  255 ) +  1 
361+ 
362+             return  await  future 
351363
352364    async  def  _remote_at_command (self , ieee , nwk , options , name , * args ):
353365        """Execute AT command on a different XBee module in the network.""" 
354366        LOGGER .debug ("Remote AT command: %s %s" , name , args )
355367        data  =  t .serialize (args , (AT_COMMANDS [name ],))
356368        try :
357-             async  with  self ._send_lock :
358-                 return  await  asyncio .wait_for (
359-                     self ._command (
360-                         "remote_at" , ieee , nwk , options , name .encode ("ascii" ), data 
361-                     ),
362-                     timeout = REMOTE_AT_COMMAND_TIMEOUT ,
363-                 )
369+             return  await  asyncio .wait_for (
370+                 self ._command (
371+                     "remote_at" , ieee , nwk , options , name .encode ("ascii" ), data 
372+                 ),
373+                 timeout = REMOTE_AT_COMMAND_TIMEOUT ,
374+             )
364375        except  asyncio .TimeoutError :
365376            LOGGER .warning ("No response to %s command" , name )
366377            raise 
@@ -369,11 +380,10 @@ async def _at_partial(self, cmd_type, name, *args):
369380        LOGGER .debug ("%s command: %s %s" , cmd_type , name , args )
370381        data  =  t .serialize (args , (AT_COMMANDS [name ],))
371382        try :
372-             async  with  self ._send_lock :
373-                 return  await  asyncio .wait_for (
374-                     self ._command (cmd_type , name .encode ("ascii" ), data ),
375-                     timeout = AT_COMMAND_TIMEOUT ,
376-                 )
383+             return  await  asyncio .wait_for (
384+                 self ._command (cmd_type , name .encode ("ascii" ), data ),
385+                 timeout = AT_COMMAND_TIMEOUT ,
386+             )
377387        except  asyncio .TimeoutError :
378388            LOGGER .warning ("%s: No response to %s command" , cmd_type , name )
379389            raise 
0 commit comments