Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions custom_components/ble_monitor/ble_parser/xiaomi.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
0x2832: "MJWSD05MMC",
0x5BEA: "MJWSD06MMC",
0x55B5: "MJWSD06MMC",
0x9AB9: "MJWSD07MMC",
0x00DB: "MMC-T201-1",
0x0391: "MMC-W505",
0x03DD: "MUE4094RT",
Expand Down Expand Up @@ -1276,6 +1277,23 @@ def obj5414(xobj):
return {"mode": mode}


def obj5c01(xobj):
"""Temperature"""
if len(xobj) == 4:
temp = FLOAT_STRUCT.unpack(xobj)[0]
return {"temperature": temp}
else:
return {}


def obj5c02(xobj):
"""Humidity"""
if len(xobj) == 1:
return {"humidity": xobj[0]}
else:
return {}


def obj5601(xobj):
"""Low Battery"""
low_batt = xobj[0]
Expand Down Expand Up @@ -1388,6 +1406,15 @@ def obj5a16(xobj):
return {}


def obj601d(xobj):
"""CO2"""
if len(xobj) == 2:
(co2,) = H_STRUCT.unpack(xobj)
return {"co2": co2}
else:
return {}


def obj6012(xobj):
"""Humidity"""
return obj4802(xobj)
Expand Down Expand Up @@ -1506,11 +1533,14 @@ def obj6e16(xobj):
0x5011: obj5011,
0x5403: obj5403,
0x5414: obj5414,
0x5c01: obj5c01,
0x5c02: obj5c02,
0x5601: obj5601,
0x560c: obj560c,
0x560d: obj560d,
0x560e: obj560e,
0x5a16: obj5a16,
0x601d: obj601d,
0x6012: obj6012,
0x605d: obj605d,
0x6e16: obj6e16
Expand Down
2 changes: 2 additions & 0 deletions custom_components/ble_monitor/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -2126,6 +2126,7 @@ class BLEMonitorBinarySensorEntityDescription(
'SV40' : [["battery", "rssi"], [], ["lock", "door", "fingerprint", "antilock", "childlock", "armed away"]],
'MJZNMSQ01YD' : [["battery", "rssi"], [], ["lock", "fingerprint"]],
'MJWSD05MMC' : [["temperature", "humidity", "battery", "rssi"], [], []],
'MJWSD07MMC' : [["temperature", "humidity", "co2", "battery", "rssi"], [], []],
'XMZNMST02YD' : [["battery", "rssi"], [], ["lock", "door", "fingerprint"]],
'XMZNMS04LM' : [["battery", "rssi"], [], ["lock", "fingerprint"]],
'XMZNMS08LM' : [["battery", "rssi"], [], ["lock", "door"]],
Expand Down Expand Up @@ -2283,6 +2284,7 @@ class BLEMonitorBinarySensorEntityDescription(
'ZNMS17LM' : 'Xiaomi Aqara',
'MJZNMSQ01YD' : 'Xiaomi',
'MJWSD05MMC' : 'Xiaomi',
'MJWSD07MMC' : 'Xiaomi',
'MJTZC01YM' : 'Xiaomi',
'XMZNMST02YD' : 'Xiaomi',
'XMZNMS04LM' : 'Xiaomi',
Expand Down
70 changes: 67 additions & 3 deletions custom_components/ble_monitor/test/test_xiaomi_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
import os
import time

import pytest
from ble_monitor.binary_sensor import BaseBinarySensor
from ble_monitor.ble_parser import BleParser
from ble_monitor.ble_parser.xiaomi import (obj4e0c, obj4e0d, obj4e0e, obj4e16,
obj4e17, obj5a16, obj0010, obj560c,
obj560d, obj560e, obj1001, obj1017,
obj1019, obj3003, obj4810, obj4850,
obj4851, obj4852, obj5010)
from ble_monitor.const import (BINARY_SENSOR_TYPES, MEASUREMENT_DICT,
SENSOR_TYPES)
obj4851, obj4852, obj5003, obj5010)
from ble_monitor.const import (BINARY_SENSOR_TYPES, MANUFACTURER_DICT,
MEASUREMENT_DICT, SENSOR_TYPES)
from ble_monitor.sensor import StateChangedSensor
from homeassistant.components.sensor import SensorDeviceClass, SensorStateClass
from homeassistant.const import UnitOfTime
Expand All @@ -34,6 +35,12 @@ def test_obj0010_toothbrush_events(self):
assert obj0010(b"\x00\x03\xaa") == {"toothbrush": 1, "counter": 3}
assert obj0010(b"\x01\x63\xaa") == {"toothbrush": 0, "score": 99}

def test_obj5003_battery(self):
"""Test MJWSD07MMC battery parsing."""
assert obj5003(b"\x64") == {"battery": 100}
assert obj5003(b"\x3d") == {"battery": 61}
assert obj5003(b"\x3d\x00") == {"battery": 61}

def test_obj4e0c_ptx_f1_display_click(self):
"""obj4e0c PTX-F1-Display: unrecognized click is {}; recognized clicks are unchanged."""
assert obj4e0c(bytes([0]), "PTX-F1-Display") == {}
Expand Down Expand Up @@ -673,6 +680,63 @@ def test_Xiaomi_MJWSD06MMC(self):
assert sensor_msg["humidity"] == 39
assert sensor_msg["rssi"] == -58

def test_Xiaomi_MJWSD07MMC(self):
"""Test Xiaomi parser for MJWSD07MMC with encryption."""
self.aeskeys = {}
aeskey = "d779248e0d41c08dc2eeed4e22e95881"
p_mac = bytes.fromhex("A4C138094463")
p_key = bytes.fromhex(aeskey)
self.aeskeys[p_mac] = p_key

test_cases = [
(
"043E290201000163440938C1A41D020106191695FE5859B99ACF63440938C1A4"
"96A9C0A8020000ECB05864C6",
207,
{"humidity": 61},
),
(
"043E260201000163440938C1A41A020106161695FE4859B99ADD9DEBB0E417E2"
"B5020000C2C4B47EC6",
221,
{"temperature": 26.2},
),
(
"043E2A0201000163440938C1A41E0201061A1695FE5859B99ADC63440938C1A4"
"4F51577A52020000F1FF18DEC6",
220,
{"co2": 532},
),
(
"043E290201000163440938C1A41D020106191695FE5859B99A0163440938C1A4"
"3A721004040000DAACEDC3C6",
1,
{"battery": 100},
),
]

for data_string, packet, expected in test_cases:
data = bytes(bytearray.fromhex(data_string))
# pylint: disable=unused-variable
ble_parser = BleParser(aeskeys=self.aeskeys)
sensor_msg, tracker_msg = ble_parser.parse_raw_data(data)

assert sensor_msg["firmware"] == "Xiaomi (MiBeacon V5 encrypted)"
assert sensor_msg["type"] == "MJWSD07MMC"
assert sensor_msg["mac"] == "A4C138094463"
assert sensor_msg["packet"] == packet
assert sensor_msg["data"]
assert sensor_msg["rssi"] == -58
for key, value in expected.items():
if isinstance(value, float):
assert sensor_msg[key] == pytest.approx(value)
else:
assert sensor_msg[key] == value
assert MANUFACTURER_DICT["MJWSD07MMC"] == "Xiaomi"
assert MEASUREMENT_DICT["MJWSD07MMC"][0] == [
"temperature", "humidity", "co2", "battery", "rssi"
]

def test_Xiaomi_MUE4094RT(self):
"""Test Xiaomi parser for MUE4094RT."""
data_string = "043e1c020102010c39b2e870de100201060c1695fe4030dd032403000101c6"
Expand Down
19 changes: 19 additions & 0 deletions docs/_devices/Xiaomi_MJWSD07MMC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
manufacturer: Xiaomi
name: Mijia Smart Temperature and Humidity Monitor 3 Pro
model: MJWSD07MMC
image: MJWSD06MMC.png
physical_description: Compact temperature, humidity, and CO2 monitor
broadcasted_properties:
- temperature
- humidity
- co2
- battery
- rssi
broadcasted_property_notes:
broadcast_rate: once per minute
active_scan:
encryption_key: true
custom_firmware:
notes:
---
Loading