From c7787f767139878ef32e28e6f86c2973a65b6375 Mon Sep 17 00:00:00 2001 From: Regin Larsen Date: Sun, 5 May 2024 12:26:38 +0200 Subject: [PATCH 1/9] feat: add support for RS1BB --- src/xiaomi_ble/devices.py | 4 ++++ src/xiaomi_ble/parser.py | 8 +++++++ tests/test_parser.py | 45 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/src/xiaomi_ble/devices.py b/src/xiaomi_ble/devices.py index 53d01a9..d1b8352 100644 --- a/src/xiaomi_ble/devices.py +++ b/src/xiaomi_ble/devices.py @@ -253,6 +253,10 @@ class DeviceEntry: name="Odor Eliminator", model="SU001-T", ), + 0x3F0F: DeviceEntry( + name="Flood and Rain Sensor", + model="RS1BB" + ), } diff --git a/src/xiaomi_ble/parser.py b/src/xiaomi_ble/parser.py index 04d3aa8..8c10bfd 100644 --- a/src/xiaomi_ble/parser.py +++ b/src/xiaomi_ble/parser.py @@ -1044,6 +1044,13 @@ def obj4805( return {} +def obj4806(xobj): + """Moisture""" + device.update_predefined_binary_sensor( + BinarySensorDeviceClass.MOISTURE, xobj[0] > 0 + ) + return {} + def obj4818( xobj: bytes, device: XiaomiBluetoothDeviceData, device_type: str ) -> dict[str, Any]: @@ -1428,6 +1435,7 @@ def obj4e1c( 0x4803: obj4803, 0x4804: obj4804, 0x4805: obj4805, + 0x4806: obj4806, 0x4818: obj4818, 0x4A01: obj4a01, 0x4A08: obj4a08, diff --git a/tests/test_parser.py b/tests/test_parser.py index fd763ef..e492d35 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -2482,6 +2482,51 @@ def test_Xiaomi_MS1BB_MI_obj4a13(): }, ) +def test_Xiaomi_RS1BB_MI_obj4806(): + """Test Xiaomi parser for Linptech RS1BB(MI) with obj4806.""" + data_string = b"\x04>)\x02\x01\x00\x00gL\xb98\xc1\xa4\x1d\x02\x01\x06\x19\x16\x95\xfeXY\x0f?JgL\xb98\xc1\xa4\xd6\xe5{\x83\x04\x00\x00\xd0\x1e\x0bK\xc0" + advertisement = bytes_to_service_info(data_string, address="A4:C1:38:66:E5:67") + bindkey = "33ede53321bc73c790a8daae4581f3d5" + + device = XiaomiBluetoothDeviceData(bindkey=bytes.fromhex(bindkey)) + assert device.supported(advertisement) + assert device.bindkey_verified + assert device.update(advertisement) == SensorUpdate( + title="Flood and Rain Sensor (RS1BB(MI))", + devices={ + None: SensorDeviceInfo( + name="Flood and Rain Sensor", + manufacturer="Xiaomi", + model="RS1BB(MI)", + hw_version=None, + sw_version="Xiaomi (MiBeacon V5 encrypted)", + ) + }, + entity_descriptions={ + KEY_SIGNAL_STRENGTH: SensorDescription( + device_key=KEY_SIGNAL_STRENGTH, + device_class=DeviceClass.SIGNAL_STRENGTH, + native_unit_of_measurement="dBm", + ), + }, + entity_values={ + KEY_SIGNAL_STRENGTH: SensorValue( + name="Signal Strength", device_key=KEY_SIGNAL_STRENGTH, native_value=-64 + ), + }, + binary_entity_descriptions={ + KEY_SMOKE: BinarySensorDescription( + device_key=KEY_MOISTURE, + device_class=BinarySensorDeviceClass.MOISTURE, + ), + }, + binary_entity_values={ + KEY_SMOKE: BinarySensorValue( + name="Moisture", device_key=KEY_MOISTURE, native_value=False + ), + }, + ) + def test_Xiaomi_XMWXKG01YL(): """Test Xiaomi parser for XMWXKG01YL Switch (double button).""" From 3650fdd8eafc94d21a9468cbee45bb5a2568832e Mon Sep 17 00:00:00 2001 From: Regin Larsen Date: Sun, 5 May 2024 12:57:54 +0200 Subject: [PATCH 2/9] fix: test data --- tests/test_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_parser.py b/tests/test_parser.py index e492d35..13b080b 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -2484,7 +2484,7 @@ def test_Xiaomi_MS1BB_MI_obj4a13(): def test_Xiaomi_RS1BB_MI_obj4806(): """Test Xiaomi parser for Linptech RS1BB(MI) with obj4806.""" - data_string = b"\x04>)\x02\x01\x00\x00gL\xb98\xc1\xa4\x1d\x02\x01\x06\x19\x16\x95\xfeXY\x0f?JgL\xb98\xc1\xa4\xd6\xe5{\x83\x04\x00\x00\xd0\x1e\x0bK\xc0" + data_string = b"XY\x0f?JgL\xb98\xc1\xa4\xd6\xe5{\x83\x04\x00\x00\xd0\x1e\x0bK" advertisement = bytes_to_service_info(data_string, address="A4:C1:38:66:E5:67") bindkey = "33ede53321bc73c790a8daae4581f3d5" From 58242e319186a1151976e0d84e93532864ffb71b Mon Sep 17 00:00:00 2001 From: Regin Larsen Date: Sun, 5 May 2024 12:59:23 +0200 Subject: [PATCH 3/9] fix: xobj method signature --- src/xiaomi_ble/parser.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/xiaomi_ble/parser.py b/src/xiaomi_ble/parser.py index 8c10bfd..38c8569 100644 --- a/src/xiaomi_ble/parser.py +++ b/src/xiaomi_ble/parser.py @@ -1044,7 +1044,9 @@ def obj4805( return {} -def obj4806(xobj): +def obj4806( + xobj: bytes, device: XiaomiBluetoothDeviceData, device_type: str +) -> dict[str, Any]: """Moisture""" device.update_predefined_binary_sensor( BinarySensorDeviceClass.MOISTURE, xobj[0] > 0 From 5c1bae1cb7f18931f5d20629596c6b3c71edc23d Mon Sep 17 00:00:00 2001 From: Regin Larsen Date: Sun, 5 May 2024 13:11:13 +0200 Subject: [PATCH 4/9] fix: mac address --- tests/test_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_parser.py b/tests/test_parser.py index 13b080b..1ec388d 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -2485,7 +2485,7 @@ def test_Xiaomi_MS1BB_MI_obj4a13(): def test_Xiaomi_RS1BB_MI_obj4806(): """Test Xiaomi parser for Linptech RS1BB(MI) with obj4806.""" data_string = b"XY\x0f?JgL\xb98\xc1\xa4\xd6\xe5{\x83\x04\x00\x00\xd0\x1e\x0bK" - advertisement = bytes_to_service_info(data_string, address="A4:C1:38:66:E5:67") + advertisement = bytes_to_service_info(data_string, address="A4:C1:38:B9:4C:67") bindkey = "33ede53321bc73c790a8daae4581f3d5" device = XiaomiBluetoothDeviceData(bindkey=bytes.fromhex(bindkey)) From 1390d5ff31317d5327aa01710f76644965eaaf00 Mon Sep 17 00:00:00 2001 From: Regin Larsen Date: Sun, 5 May 2024 13:15:57 +0200 Subject: [PATCH 5/9] fix: debug log for MAC address --- src/xiaomi_ble/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xiaomi_ble/parser.py b/src/xiaomi_ble/parser.py index 38c8569..ce7987f 100644 --- a/src/xiaomi_ble/parser.py +++ b/src/xiaomi_ble/parser.py @@ -1630,7 +1630,7 @@ def _parse_xiaomi( xiaomi_mac = xiaomi_mac_reversed[::-1] if xiaomi_mac != source_mac: _LOGGER.debug( - "MAC address doesn't match data frame. Expected: %s, Got: %s)", + "MAC address doesn't match data frame. Expected: %s, Got: %s", to_mac(xiaomi_mac), to_mac(source_mac), ) From 082eecedf4ff284714edafd947a8a33429444699 Mon Sep 17 00:00:00 2001 From: Regin Larsen Date: Sun, 5 May 2024 13:16:10 +0200 Subject: [PATCH 6/9] fix: expected test values --- tests/test_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_parser.py b/tests/test_parser.py index 1ec388d..972e07d 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -2492,7 +2492,7 @@ def test_Xiaomi_RS1BB_MI_obj4806(): assert device.supported(advertisement) assert device.bindkey_verified assert device.update(advertisement) == SensorUpdate( - title="Flood and Rain Sensor (RS1BB(MI))", + title="Flood and Rain Sensor 4C67 (RS1BB)", devices={ None: SensorDeviceInfo( name="Flood and Rain Sensor", @@ -2511,7 +2511,7 @@ def test_Xiaomi_RS1BB_MI_obj4806(): }, entity_values={ KEY_SIGNAL_STRENGTH: SensorValue( - name="Signal Strength", device_key=KEY_SIGNAL_STRENGTH, native_value=-64 + name="Signal Strength", device_key=KEY_SIGNAL_STRENGTH, native_value=-60 ), }, binary_entity_descriptions={ From 16d24439af6dd350540f3ccc5126e469ab9645f0 Mon Sep 17 00:00:00 2001 From: Regin Larsen Date: Sun, 5 May 2024 13:17:44 +0200 Subject: [PATCH 7/9] fix: change type from SMOKE to MOISTURE --- tests/test_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_parser.py b/tests/test_parser.py index 972e07d..2f655f5 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -2515,13 +2515,13 @@ def test_Xiaomi_RS1BB_MI_obj4806(): ), }, binary_entity_descriptions={ - KEY_SMOKE: BinarySensorDescription( + KEY_MOISTURE: BinarySensorDescription( device_key=KEY_MOISTURE, device_class=BinarySensorDeviceClass.MOISTURE, ), }, binary_entity_values={ - KEY_SMOKE: BinarySensorValue( + KEY_MOISTURE: BinarySensorValue( name="Moisture", device_key=KEY_MOISTURE, native_value=False ), }, From cd061e160f1708b25f8eb88c6c19d13941d9b2ab Mon Sep 17 00:00:00 2001 From: Regin Larsen Date: Sun, 5 May 2024 13:22:42 +0200 Subject: [PATCH 8/9] fix: device name --- src/xiaomi_ble/devices.py | 8 ++++---- tests/test_parser.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/xiaomi_ble/devices.py b/src/xiaomi_ble/devices.py index d1b8352..446d9d9 100644 --- a/src/xiaomi_ble/devices.py +++ b/src/xiaomi_ble/devices.py @@ -80,6 +80,10 @@ class DeviceEntry: 0x2AEB: DeviceEntry( name="Motion Sensor", model="HS1BB(MI)", + ), + 0x3F0F: DeviceEntry( + name="Flood and Rain Sensor", + model="RS1BB(MI)" ), 0x01AA: DeviceEntry( name="Temperature/Humidity Sensor", @@ -253,10 +257,6 @@ class DeviceEntry: name="Odor Eliminator", model="SU001-T", ), - 0x3F0F: DeviceEntry( - name="Flood and Rain Sensor", - model="RS1BB" - ), } diff --git a/tests/test_parser.py b/tests/test_parser.py index 2f655f5..078cb08 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -2492,10 +2492,10 @@ def test_Xiaomi_RS1BB_MI_obj4806(): assert device.supported(advertisement) assert device.bindkey_verified assert device.update(advertisement) == SensorUpdate( - title="Flood and Rain Sensor 4C67 (RS1BB)", + title="Flood and Rain Sensor 4C67 (RS1BB(MI))", devices={ None: SensorDeviceInfo( - name="Flood and Rain Sensor", + name="Flood and Rain Sensor 4C67", manufacturer="Xiaomi", model="RS1BB(MI)", hw_version=None, From 5c05efdb5a6b516199815c51479bd1798d16cae4 Mon Sep 17 00:00:00 2001 From: Regin Larsen Date: Sun, 5 May 2024 13:32:11 +0200 Subject: [PATCH 9/9] style: correct style issues --- src/xiaomi_ble/devices.py | 5 +---- src/xiaomi_ble/parser.py | 3 ++- tests/test_parser.py | 1 + 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/xiaomi_ble/devices.py b/src/xiaomi_ble/devices.py index 446d9d9..431d350 100644 --- a/src/xiaomi_ble/devices.py +++ b/src/xiaomi_ble/devices.py @@ -81,10 +81,7 @@ class DeviceEntry: name="Motion Sensor", model="HS1BB(MI)", ), - 0x3F0F: DeviceEntry( - name="Flood and Rain Sensor", - model="RS1BB(MI)" - ), + 0x3F0F: DeviceEntry(name="Flood and Rain Sensor", model="RS1BB(MI)"), 0x01AA: DeviceEntry( name="Temperature/Humidity Sensor", model="LYWSDCGQ", diff --git a/src/xiaomi_ble/parser.py b/src/xiaomi_ble/parser.py index ce7987f..1416ef4 100644 --- a/src/xiaomi_ble/parser.py +++ b/src/xiaomi_ble/parser.py @@ -1045,7 +1045,7 @@ def obj4805( def obj4806( - xobj: bytes, device: XiaomiBluetoothDeviceData, device_type: str + xobj: bytes, device: XiaomiBluetoothDeviceData, device_type: str ) -> dict[str, Any]: """Moisture""" device.update_predefined_binary_sensor( @@ -1053,6 +1053,7 @@ def obj4806( ) return {} + def obj4818( xobj: bytes, device: XiaomiBluetoothDeviceData, device_type: str ) -> dict[str, Any]: diff --git a/tests/test_parser.py b/tests/test_parser.py index 078cb08..05eb95f 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -2482,6 +2482,7 @@ def test_Xiaomi_MS1BB_MI_obj4a13(): }, ) + def test_Xiaomi_RS1BB_MI_obj4806(): """Test Xiaomi parser for Linptech RS1BB(MI) with obj4806.""" data_string = b"XY\x0f?JgL\xb98\xc1\xa4\xd6\xe5{\x83\x04\x00\x00\xd0\x1e\x0bK"