Skip to content

Commit 6059c1e

Browse files
committed
Use zigpy PriorityLock and deprioritize TX commands
1 parent 49def51 commit 6059c1e

File tree

2 files changed

+33
-23
lines changed

2 files changed

+33
-23
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ readme = "README.md"
1414
license = {text = "GPL-3.0"}
1515
requires-python = ">=3.8"
1616
dependencies = [
17-
"zigpy>=0.60.0",
17+
"zigpy>=0.60.2",
1818
]
1919

2020
[tool.setuptools.packages.find]

zigpy_xbee/api.py

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import serial
1010
from zigpy.config import CONF_DEVICE_PATH, SCHEMA_DEVICE
11+
from zigpy.datastructures import PriorityLock
1112
from zigpy.exceptions import APIException, DeliveryError
1213
import 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

Comments
 (0)