Skip to content

Watchdog failures #171

@puddly

Description

@puddly

#170 added a watchdog command (VR) that is sent every 30s to ensure the radio is still alive. It seems that the XBee serial protocol can't handle this and the command times out, causing a restart. If I add an asyncio.Lock around _at_partial it doesn't seem to help either.

@Shulyaka Are you familiar with the serial protocol? Do you happen to know why this would be the case?

Below is my patchset to enable a send lock:

diff --git a/zigpy_xbee/api.py b/zigpy_xbee/api.py
index b4a73da..51ba61f 100644
--- a/zigpy_xbee/api.py
+++ b/zigpy_xbee/api.py
@@ -289,6 +289,7 @@ class XBee:
         self._cmd_mode_future: Optional[asyncio.Future] = None
         self._reset: asyncio.Event = asyncio.Event()
         self._running: asyncio.Event = asyncio.Event()
+        self._send_lock = asyncio.Lock()
 
     @property
     def reset_event(self):
@@ -353,12 +354,13 @@ class XBee:
         LOGGER.debug("Remote AT command: %s %s", name, args)
         data = t.serialize(args, (AT_COMMANDS[name],))
         try:
-            return await asyncio.wait_for(
-                self._command(
-                    "remote_at", ieee, nwk, options, name.encode("ascii"), data
-                ),
-                timeout=REMOTE_AT_COMMAND_TIMEOUT,
-            )
+            async with self._send_lock:
+                return await asyncio.wait_for(
+                    self._command(
+                        "remote_at", ieee, nwk, options, name.encode("ascii"), data
+                    ),
+                    timeout=REMOTE_AT_COMMAND_TIMEOUT,
+                )
         except asyncio.TimeoutError:
             LOGGER.warning("No response to %s command", name)
             raise
@@ -367,10 +369,11 @@ class XBee:
         LOGGER.debug("%s command: %s %s", cmd_type, name, args)
         data = t.serialize(args, (AT_COMMANDS[name],))
         try:
-            return await asyncio.wait_for(
-                self._command(cmd_type, name.encode("ascii"), data),
-                timeout=AT_COMMAND_TIMEOUT,
-            )
+            async with self._send_lock:
+                return await asyncio.wait_for(
+                    self._command(cmd_type, name.encode("ascii"), data),
+                    timeout=AT_COMMAND_TIMEOUT,
+                )
         except asyncio.TimeoutError:
             LOGGER.warning("%s: No response to %s command", cmd_type, name)
             raise
@@ -597,9 +600,3 @@ class XBee:
                 raise APIException("Failed to configure XBee for API mode")
         finally:
             self.close()
-
-    def __getattr__(self, item):
-        """Handle supported command requests."""
-        if item in COMMAND_REQUESTS:
-            return functools.partial(self._command, item)
-        raise AttributeError(f"Unknown command {item}")
diff --git a/zigpy_xbee/zigbee/application.py b/zigpy_xbee/zigbee/application.py
index 2158b95..4ad8e62 100644
--- a/zigpy_xbee/zigbee/application.py
+++ b/zigpy_xbee/zigbee/application.py
@@ -302,7 +302,8 @@ class ControllerApplication(zigpy.application.ControllerApplication):
                 "Cannot send a packet to a device without a known IEEE address"
             )
 
-        send_req = self._api.tx_explicit(
+        send_req = self._api._command(
+            "tx_explicit",
             long_addr,
             short_addr,
             packet.src_ep or 0,
@@ -356,7 +357,7 @@ class ControllerApplication(zigpy.application.ControllerApplication):
         # Key type:
         # 0 = Pre-configured Link Key (KY command of the joining device)
         # 1 = Install Code With CRC (I? command of the joining device)
-        await self._api.register_joining_device(node, reserved, key_type, link_key)
+        await self._api._command("register_joining_device", node, reserved, key_type, link_key)
 
     def handle_modem_status(self, status):
         """Handle changed Modem Status of the device."""

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions