Repository: zigpy/zigpy-znp (language: python)

Issue:
Develco Products "ZigBee Wallplug HA SP2" unsupported frame
I have two Wallplugs that triggers an exception in zigpy:

```
2023-10-08 05:02:02.396 ERROR (MainThread) [zigpy_znp.uart] Received an exception while passing frame to API: TransportFrame(payload=GeneralFrame(header=CommandHeader(id=0xB1, subsystem=Subsystem.ZDO, type=CommandType.AREQ), data=b'\x1F\x82\x84'))
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/zigpy_znp/types/commands.py", line 417, in from_frame
    params[param.name], data = param.type.deserialize(data)
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/zigpy/types/struct.py", line 302, in deserialize
    value, data = field.type.deserialize(data)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/zigpy/types/basic.py", line 193, in deserialize
    raise ValueError(f"Data is too short to contain {byte_size} bytes")
ValueError: Data is too short to contain 1 bytes

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/zigpy_znp/uart.py", line 72, in data_received
    self._api.frame_received(frame.payload)
  File "/usr/local/lib/python3.11/site-packages/zigpy_znp/api.py", line 830, in frame_received
    command = command_cls.from_frame(frame, align=self.nvram.align_structs)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/zigpy_znp/types/commands.py", line 424, in from_frame
    raise ValueError(
ValueError: Frame data is truncated (parsed {'Src': 0x821F, 'Status': <Status.NOT_SUPPORTED: 132>}), required parameter remains: Param(name='Neighbors', type=<class 'zigpy.zdo.types.Neighbors'>, description='Neighbors', optional=False)
```

I don't know what these frames mean. The plugs seem to operate just fine, but once in a while send a frame that zigpy doesn't understand.


Discussion / hints:

Fix patch:
diff --git a/zigpy_znp/commands/zdo.py b/zigpy_znp/commands/zdo.py
index 277ed64a..6c1abbe6 100644
--- a/zigpy_znp/commands/zdo.py
+++ b/zigpy_znp/commands/zdo.py
@@ -1181,7 +1181,7 @@ class ZDO(t.CommandsBase, subsystem=t.Subsystem.ZDO):
             t.Param(
                 "Status", t.ZDOStatus, "Status is either Success (0) or Failure (1)"
             ),
-            t.Param("Neighbors", zigpy.zdo.types.Neighbors, "Neighbors"),
+            t.Param("Neighbors", zigpy.zdo.types.Neighbors, "Neighbors", optional=True),
         ),
     )
 


Test patch:
diff --git a/tests/test_commands.py b/tests/test_commands.py
index e43e3d88..eaa44951 100644
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -543,3 +543,19 @@ class TestSubsystem(t.CommandsBase, subsystem=t.Subsystem.SYS):
     assert Test.from_frame(frames.GeneralFrame(header=Test.header, data=b"")) == Test(
         Data=t.Bytes(b"")
     )
+
+
+def test_neighbors_missing_payload():
+    frame = frames.GeneralFrame(
+        header=t.CommandHeader(
+            id=0xB1,
+            subsystem=t.Subsystem.ZDO,
+            type=t.CommandType.AREQ,
+        ),
+        data=b"\x1F\x82\x84",
+    )
+
+    assert c.ZDO.MgmtLqiRsp.Callback.from_frame(frame) == c.ZDO.MgmtLqiRsp.Callback(
+        Src=0x821F,
+        Status=t.ZDOStatus.NOT_SUPPORTED,
+    )