Repository: Jc2k/aiohomekit

Issue:
struct.error: unpack error
hello

Noticed this log while running HA Core 2025.8.0b0 (but this is NOT a beta issue):

```
Logger: habluetooth.manager
Source: /usr/local/lib/python3.13/asyncio/selector_events.py:1019
First occurred: 9:57:07 PM (6 occurrences)
Last logged: 9:57:57 PM

Error in callback: <bound method BleController._device_detected of <aiohomekit.controller.ble.controller.BleController object at 0x7fe5dbf70050>>
Traceback (most recent call last):
  File "src/habluetooth/manager.py", line 85, in habluetooth.manager._dispatch_bleak_callback
  File "/usr/local/lib/python3.13/site-packages/aiohomekit/controller/ble/controller.py", line 73, in _device_detected
    data = HomeKitAdvertisement.from_manufacturer_data(device.name, device.address, manufacturer_data)
  File "/usr/local/lib/python3.13/site-packages/aiohomekit/controller/ble/manufacturer_data.py", line 42, in from_manufacturer_data
    acid, gsn, cn, cv = UNPACK_HHBB(data[9:15])
                        ~~~~~~~~~~~^^^^^^^^^^^^
struct.error: unpack requires a buffer of 6 bytes
```

thanks!

Discussion:

Fix (patch):
diff --git a/aiohomekit/controller/ble/manufacturer_data.py b/aiohomekit/controller/ble/manufacturer_data.py
index d9d7ca2..e9d738f 100644
--- a/aiohomekit/controller/ble/manufacturer_data.py
+++ b/aiohomekit/controller/ble/manufacturer_data.py
@@ -37,6 +37,9 @@ class HomeKitAdvertisement(AbstractDescription):
         if data[0] != HOMEKIT_ADVERTISEMENT_TYPE:
             raise ValueError("Not a HomeKit device")
 
+        if len(data) < 19:
+            raise ValueError("HomeKit advertisement data too short")
+
         sf = data[2]
         device_id = ":".join(data[3:9].hex()[0 + i : 2 + i] for i in range(0, 12, 2)).lower()
         acid, gsn, cn, cv = UNPACK_HHBB(data[9:15])


Test changes:
diff --git a/tests/test_controller_ble_manufacturer_data.py b/tests/test_controller_ble_manufacturer_data.py
new file mode 100644
index 0000000..aaa3f52
--- /dev/null
+++ b/tests/test_controller_ble_manufacturer_data.py
@@ -0,0 +1,41 @@
+from __future__ import annotations
+
+import pytest
+
+from aiohomekit.controller.ble.manufacturer_data import HomeKitAdvertisement
+
+
+def test_manufacturer_data_too_short() -> None:
+    """Test that short manufacturer data raises appropriate error."""
+    # Valid HomeKit advertisement type but buffer too short (less than 19 bytes)
+    short_data = b"\x06\x00\x00\x01\x02\x03\x04\x05\x06"  # Only 9 bytes
+
+    with pytest.raises(ValueError, match="HomeKit advertisement data too short"):
+        HomeKitAdvertisement.from_manufacturer_data(
+            name="Test", address="00:00:00:00:00:00", manufacturer_data={76: short_data}
+        )
+
+
+def test_manufacturer_data_almost_enough() -> None:
+    """Test with exactly 18 bytes (one less than required)."""
+    almost_data = b"\x06" + b"\x00" * 17  # 18 bytes total
+
+    with pytest.raises(ValueError, match="HomeKit advertisement data too short"):
+        HomeKitAdvertisement.from_manufacturer_data(
+            name="Test", address="00:00:00:00:00:00", manufacturer_data={76: almost_data}
+        )
+
+
+def test_manufacturer_data_exactly_enough() -> None:
+    """Test with exactly 19 bytes (minimum required)."""
+    valid_data = (
+        b"\x06\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x00\x00\x00\x00\x00\x11\x22\x33"  # 19 bytes total
+    )
+
+    result = HomeKitAdvertisement.from_manufacturer_data(
+        name="Test", address="00:00:00:00:00:00", manufacturer_data={76: valid_data}
+    )
+
+    assert result is not None
+    assert result.address == "00:00:00:00:00:00"
+    assert result.name == "Test"