|
@@ -1,3 +1,5 @@
|
|
|
+from __future__ import annotations
|
|
|
+
|
|
|
from typing import Any
|
|
|
|
|
|
from bleak.backends.device import BLEDevice
|
|
@@ -17,6 +19,34 @@ ADVERTISEMENT_DATA_DEFAULTS = {
|
|
|
"tx_power": -127,
|
|
|
}
|
|
|
|
|
|
+BLE_DEVICE_DEFAULTS = {
|
|
|
+ "name": None,
|
|
|
+ "rssi": -127,
|
|
|
+ "details": None,
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+def generate_ble_device(
|
|
|
+ address: str | None = None,
|
|
|
+ name: str | None = None,
|
|
|
+ details: Any | None = None,
|
|
|
+ rssi: int | None = None,
|
|
|
+ **kwargs: Any,
|
|
|
+) -> BLEDevice:
|
|
|
+ """Generate a BLEDevice with defaults."""
|
|
|
+ new = kwargs.copy()
|
|
|
+ if address is not None:
|
|
|
+ new["address"] = address
|
|
|
+ if name is not None:
|
|
|
+ new["name"] = name
|
|
|
+ if details is not None:
|
|
|
+ new["details"] = details
|
|
|
+ if rssi is not None:
|
|
|
+ new["rssi"] = rssi
|
|
|
+ for key, value in BLE_DEVICE_DEFAULTS.items():
|
|
|
+ new.setdefault(key, value)
|
|
|
+ return BLEDevice(**new)
|
|
|
+
|
|
|
|
|
|
def generate_advertisement_data(**kwargs: Any) -> AdvertisementData:
|
|
|
"""Generate advertisement data with defaults."""
|
|
@@ -28,7 +58,7 @@ def generate_advertisement_data(**kwargs: Any) -> AdvertisementData:
|
|
|
|
|
|
def test_parse_advertisement_data_curtain():
|
|
|
"""Test parse_advertisement_data for curtain."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xe7\xabF\xac\x8f\x92|\x0f\x00\x11\x04"},
|
|
|
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"c\xc0X\x00\x11\x04"},
|
|
@@ -60,7 +90,7 @@ def test_parse_advertisement_data_curtain():
|
|
|
|
|
|
def test_parse_advertisement_data_curtain_passive():
|
|
|
"""Test parse_advertisement_data for curtain passive."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xe7\xabF\xac\x8f\x92|\x0f\x00\x11\x04"},
|
|
|
service_data={},
|
|
@@ -92,7 +122,7 @@ def test_parse_advertisement_data_curtain_passive():
|
|
|
|
|
|
def test_parse_advertisement_data_curtain_position_zero():
|
|
|
"""Test parse_advertisement_data for curtain position zero."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
local_name="WoCurtain",
|
|
|
manufacturer_data={89: b"\xc1\xc7'}U\xab"},
|
|
@@ -130,7 +160,7 @@ def test_parse_advertisement_data_curtain_position_zero():
|
|
|
|
|
|
def test_parse_advertisement_data_curtain_firmware_six_position_100():
|
|
|
"""Test parse_advertisement_data with firmware six for curtain position 100."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
local_name="WoCurtain",
|
|
|
manufacturer_data={
|
|
@@ -174,7 +204,7 @@ def test_parse_advertisement_data_curtain_firmware_six_position_100():
|
|
|
|
|
|
def test_parse_advertisement_data_curtain_firmware_six_position_100_other_rssi():
|
|
|
"""Test parse_advertisement_data with firmware six for curtain position 100 other rssi."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
local_name="WoCurtain",
|
|
|
manufacturer_data={
|
|
@@ -218,7 +248,7 @@ def test_parse_advertisement_data_curtain_firmware_six_position_100_other_rssi()
|
|
|
|
|
|
def test_parse_advertisement_data_curtain_fully_closed():
|
|
|
"""Test parse_advertisement_data with firmware six fully closed."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
local_name="WoCurtain",
|
|
|
manufacturer_data={2409: b"\xc1\xc7'}U\xab\"\x0fd\x11\x04"},
|
|
@@ -256,7 +286,7 @@ def test_parse_advertisement_data_curtain_fully_closed():
|
|
|
|
|
|
def test_parse_advertisement_data_curtain_fully_open():
|
|
|
"""Test parse_advertisement_data with firmware six fully open."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
local_name="WoCurtain",
|
|
|
manufacturer_data={2409: b"\xc1\xc7'}U\xab%\x0f\x00\x11\x04"},
|
|
@@ -294,7 +324,7 @@ def test_parse_advertisement_data_curtain_fully_open():
|
|
|
|
|
|
def test_parse_advertisement_data_contact():
|
|
|
"""Test parse_advertisement_data for the contact sensor."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xe7\xabF\xac\x8f\x92|\x0f\x00\x11\x04"},
|
|
|
service_data={
|
|
@@ -329,7 +359,7 @@ def test_parse_advertisement_data_contact():
|
|
|
|
|
|
def test_parse_advertisement_data_empty():
|
|
|
"""Test parse_advertisement_data with empty data does not blow up."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2403: b"\xe7\xabF\xac\x8f\x92|\x0f\x00\x11\x04"},
|
|
|
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b""},
|
|
@@ -340,7 +370,7 @@ def test_parse_advertisement_data_empty():
|
|
|
|
|
|
def test_new_bot_firmware():
|
|
|
"""Test parsing adv data from new bot firmware."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={89: b"\xd8.\xad\xcd\r\x85"},
|
|
|
service_data={"00000d00-0000-1000-8000-00805f9b34fb": b"H\x10\xe1"},
|
|
@@ -366,7 +396,7 @@ def test_new_bot_firmware():
|
|
|
|
|
|
def test_parse_advertisement_data_curtain_firmware_six_fully_closed():
|
|
|
"""Test parse_advertisement_data with firmware six fully closed."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
local_name="WoCurtain",
|
|
|
manufacturer_data={
|
|
@@ -410,7 +440,7 @@ def test_parse_advertisement_data_curtain_firmware_six_fully_closed():
|
|
|
|
|
|
def test_parse_advertisement_data_curtain_firmware_six_fully_open():
|
|
|
"""Test parse_advertisement_data with firmware six fully open."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
local_name="WoCurtain",
|
|
|
manufacturer_data={
|
|
@@ -454,7 +484,7 @@ def test_parse_advertisement_data_curtain_firmware_six_fully_open():
|
|
|
|
|
|
def test_contact_sensor_mfr():
|
|
|
"""Test parsing adv data from new bot firmware."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xcb9\xcd\xc4=FA,\x00F\x01\x8f\xc4"},
|
|
|
service_data={
|
|
@@ -490,7 +520,7 @@ def test_contact_sensor_mfr():
|
|
|
|
|
|
def test_contact_sensor_mfr_no_service_data():
|
|
|
"""Test contact sensor with passive data only."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xcb9\xcd\xc4=FA,\x00F\x01\x8f\xc4"},
|
|
|
service_data={},
|
|
@@ -524,7 +554,7 @@ def test_contact_sensor_mfr_no_service_data():
|
|
|
|
|
|
def test_contact_sensor_srv():
|
|
|
"""Test parsing adv data from new bot firmware."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
service_data={
|
|
|
"0000fd3d-0000-1000-8000-00805f9b34fb": b"d\x00\xda\x04\x00F\x01\x8f\xc4"
|
|
@@ -559,7 +589,7 @@ def test_contact_sensor_srv():
|
|
|
|
|
|
def test_contact_sensor_open():
|
|
|
"""Test parsing mfr adv data from new bot firmware."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xcb9\xcd\xc4=F\x84\x9c\x00\x17\x00QD"},
|
|
|
service_data={
|
|
@@ -595,7 +625,7 @@ def test_contact_sensor_open():
|
|
|
|
|
|
def test_contact_sensor_closed():
|
|
|
"""Test parsing mfr adv data from new bot firmware."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xcb9\xcd\xc4=F\x89\x8c\x00+\x00\x19\x84"},
|
|
|
service_data={
|
|
@@ -631,7 +661,7 @@ def test_contact_sensor_closed():
|
|
|
|
|
|
def test_switchbot_passive():
|
|
|
"""Test parsing switchbot as passive."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={89: bytes.fromhex("d51cfb397856")},
|
|
|
service_data={},
|
|
@@ -661,7 +691,7 @@ def test_switchbot_passive():
|
|
|
|
|
|
def test_bulb_active():
|
|
|
"""Test parsing bulb as active."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\x84\xf7\x03\xb4\xcbz\x03\xe4!\x00\x00"},
|
|
|
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"u\x00d"},
|
|
@@ -696,7 +726,7 @@ def test_bulb_active():
|
|
|
|
|
|
def test_lightstrip_passive():
|
|
|
"""Test parsing lightstrip as passive."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={
|
|
|
2409: b"`U\xf9(\xe5\x96\x00d\x02\xb0\x00\x00\x00\x00\x00\x00"
|
|
@@ -733,7 +763,7 @@ def test_lightstrip_passive():
|
|
|
|
|
|
def test_wosensor_passive_and_active():
|
|
|
"""Test parsing wosensor as passive with active data as well."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xd7\xc1}]\xebC\xde\x03\x06\x985"},
|
|
|
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"T\x00\xe4\x06\x985"},
|
|
@@ -765,7 +795,7 @@ def test_wosensor_passive_and_active():
|
|
|
|
|
|
def test_wosensor_active():
|
|
|
"""Test parsing wosensor with active data as well."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={},
|
|
|
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"T\x00\xe4\x06\x985"},
|
|
@@ -797,7 +827,7 @@ def test_wosensor_active():
|
|
|
|
|
|
def test_wosensor_passive_only():
|
|
|
"""Test parsing wosensor with only passive data."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xd7\xc1}]\xebC\xde\x03\x06\x985"},
|
|
|
service_data={},
|
|
@@ -829,7 +859,7 @@ def test_wosensor_passive_only():
|
|
|
|
|
|
def test_motion_sensor_clear():
|
|
|
"""Test parsing motion sensor with clear data."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xc0!\x9a\xe8\xbcIj\x1c\x00f"},
|
|
|
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"s\x00\xe2\x00f\x01"},
|
|
@@ -866,7 +896,7 @@ def test_motion_sensor_clear():
|
|
|
|
|
|
def test_motion_sensor_clear_passive():
|
|
|
"""Test parsing motion sensor with clear data."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xc0!\x9a\xe8\xbcIj\x1c\x00f"},
|
|
|
service_data={},
|
|
@@ -903,7 +933,7 @@ def test_motion_sensor_clear_passive():
|
|
|
|
|
|
def test_motion_sensor_motion():
|
|
|
"""Test parsing motion sensor with motion data."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xc0!\x9a\xe8\xbcIi\\\x008"},
|
|
|
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"s@\xe2\x008\x01"},
|
|
@@ -940,7 +970,7 @@ def test_motion_sensor_motion():
|
|
|
|
|
|
def test_motion_sensor_motion_passive():
|
|
|
"""Test parsing motion sensor with motion data."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xc0!\x9a\xe8\xbcIi\\\x008"},
|
|
|
service_data={},
|
|
@@ -977,7 +1007,7 @@ def test_motion_sensor_motion_passive():
|
|
|
|
|
|
def test_motion_sensor_is_light_passive():
|
|
|
"""Test parsing motion sensor with motion data."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xc0!\x9a\xe8\xbcIs,\x04g"},
|
|
|
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"s\x00\xe2\x04g\x02"},
|
|
@@ -1014,7 +1044,7 @@ def test_motion_sensor_is_light_passive():
|
|
|
|
|
|
def test_motion_sensor_is_light_active():
|
|
|
"""Test parsing motion sensor with motion data."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={},
|
|
|
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"s\x00\xe2\x04g\x02"},
|
|
@@ -1050,7 +1080,7 @@ def test_motion_sensor_is_light_active():
|
|
|
|
|
|
|
|
|
def test_motion_with_light_detected():
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xc0!\x9a\xe8\xbcIvl\x00,"},
|
|
|
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"s@\xe2\x00,\x02"},
|
|
@@ -1087,7 +1117,7 @@ def test_motion_with_light_detected():
|
|
|
|
|
|
def test_motion_sensor_motion_passive():
|
|
|
"""Test parsing motion sensor with motion data."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xc0!\x9a\xe8\xbcIi\\\x008"},
|
|
|
service_data={},
|
|
@@ -1124,7 +1154,7 @@ def test_motion_sensor_motion_passive():
|
|
|
|
|
|
def test_parsing_lock_active():
|
|
|
"""Test parsing lock with active data."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xf1\t\x9fE\x1a]\x07\x83\x00 "},
|
|
|
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"o\x80d"},
|
|
@@ -1159,7 +1189,7 @@ def test_parsing_lock_active():
|
|
|
|
|
|
def test_parsing_lock_passive():
|
|
|
"""Test parsing lock with active data."""
|
|
|
- ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
|
|
|
+ ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
|
adv_data = generate_advertisement_data(
|
|
|
manufacturer_data={2409: b"\xf1\t\x9fE\x1a]\x07\x83\x00 "}, rssi=-67
|
|
|
)
|