diff --git a/custom_components/ble_monitor/const.py b/custom_components/ble_monitor/const.py index 388184e3..67efa9d8 100644 --- a/custom_components/ble_monitor/const.py +++ b/custom_components/ble_monitor/const.py @@ -403,6 +403,16 @@ class BLEMonitorBinarySensorEntityDescription( device_class=None, force_update=False, ), + BLEMonitorBinarySensorEntityDescription( + key="stabilized", + sensor_class="BaseBinarySensor", + update_behavior="Instantly", + name="ble stabilized", + icon="mdi:scale-bathroom", + unique_id="stabilized_", + device_class=None, + force_update=False, + ), BLEMonitorBinarySensorEntityDescription( key="fingerprint", sensor_class="BaseBinarySensor", @@ -2158,8 +2168,8 @@ class BLEMonitorBinarySensorEntityDescription( 'YLKG07YL/YLKG08YL' : [["rssi"], ["dimmer"], []], 'SU001-T' : [["battery", "rssi"], [], ["motion", "switch"]], 'ATC' : [["temperature", "humidity", "battery", "voltage", "rssi"], [], ["switch", "opening"]], - 'Mi Scale V1' : [["rssi"], ["weight", "non-stabilized weight"], ["weight removed"]], - 'Mi Scale V2' : [["rssi"], ["weight", "stabilized weight", "non-stabilized weight", "impedance"], ["weight removed"]], + 'Mi Scale V1' : [["rssi"], ["weight", "non-stabilized weight"], ["weight removed", "stabilized"]], + 'Mi Scale V2' : [["rssi"], ["weight", "stabilized weight", "non-stabilized weight", "impedance"], ["weight removed", "stabilized"]], 'Mi Band' : [["rssi", "heart rate", "steps"], [], []], 'TZC4' : [["rssi"], ["weight", "non-stabilized weight", "impedance"], []], 'QJ-J' : [["rssi"], ["weight", "non-stabilized weight", "impedance"], []], diff --git a/custom_components/ble_monitor/test/test_miscale_parser.py b/custom_components/ble_monitor/test/test_miscale_parser.py index 41a556f4..1f43b7c9 100644 --- a/custom_components/ble_monitor/test/test_miscale_parser.py +++ b/custom_components/ble_monitor/test/test_miscale_parser.py @@ -1,5 +1,10 @@ """The tests for the Mi Scale ble_parser.""" +from types import SimpleNamespace + +from ble_monitor.binary_sensor import BaseBinarySensor from ble_monitor.ble_parser import BleParser +from ble_monitor.const import BINARY_SENSOR_TYPES, MEASUREMENT_DICT +from ble_monitor.sensor import WeightSensor # Real Mi Scale V1 advertisements from # https://github.com/custom-components/ble_monitor/issues/366 @@ -50,6 +55,17 @@ def test_miscale_v1(self): assert sensor_msg["stabilized"] == 1 assert sensor_msg["rssi"] == -59 + weight_removed_sensor = BaseBinarySensor.__new__(BaseBinarySensor) + weight_removed_sensor._type = "mac" + weight_removed_sensor._device_type = "Mi Scale V1" + weight_removed_sensor.entity_description = SimpleNamespace( + key="weight removed" + ) + weight_removed_sensor._extra_state_attributes = {} + weight_removed_sensor.collect(sensor_msg) + assert weight_removed_sensor._newstate == 1 + assert weight_removed_sensor._extra_state_attributes["weight"] == 87.2 + def test_miscale_v1_ext(self): """Test Mi Scale v1 parser (extended advertisement).""" data_string = "043e390d011300008995c08c47c80100ff7fc70000000000000000001f02010603021d1809ff5701c8478cc095890d161d18821400e507040b101708" @@ -129,9 +145,37 @@ def test_miscale_v2_impedance(self): assert sensor_msg["weight unit"] == "kg" assert sensor_msg["weight removed"] == 0 assert sensor_msg["stabilized"] == 1 + assert sensor_msg["stabilized weight"] == 85.15 + assert sensor_msg["weight"] == 85.15 assert sensor_msg["impedance"] == 428 assert sensor_msg["rssi"] == -66 + weight_sensor = WeightSensor.__new__(WeightSensor) + weight_sensor._type = "mac" + weight_sensor.entity_description = SimpleNamespace( + key="non-stabilized weight" + ) + weight_sensor._extra_state_attributes = {} + weight_sensor.pending_update = False + weight_sensor.collect(sensor_msg, period_cnt=0) + assert weight_sensor._extra_state_attributes["stabilized"] is True + + def test_miscale_stabilized_binary_sensor_mapping(self): + """Test Mi Scale V1 and V2 expose the parsed stabilization flag.""" + for device_type in ("Mi Scale V1", "Mi Scale V2"): + assert MEASUREMENT_DICT[device_type][2] == [ + "weight removed", + "stabilized", + ] + + description = next( + item for item in BINARY_SENSOR_TYPES if item.key == "stabilized" + ) + assert description.sensor_class == "BaseBinarySensor" + assert description.update_behavior == "Instantly" + assert description.unique_id == "stabilized_" + assert description.device_class is None + def test_miscale_v1_stale_first_packet(self): """Test that the stale first packet from issue 366 remains suppressed.""" ble_parser = BleParser(filter_duplicates=True) diff --git a/docs/_devices/Xiaomi_XMTZC01HM_XMTZC04HM.md b/docs/_devices/Xiaomi_XMTZC01HM_XMTZC04HM.md index c1c39540..b78d2ad2 100644 --- a/docs/_devices/Xiaomi_XMTZC01HM_XMTZC04HM.md +++ b/docs/_devices/Xiaomi_XMTZC01HM_XMTZC04HM.md @@ -7,6 +7,7 @@ physical_description: broadcasted_properties: - weight - non-stabilized weight + - stabilized - weight removed - rssi broadcasted_property_notes: @@ -14,6 +15,8 @@ broadcasted_property_notes: note: is only reported after the scale is stabilized - property: non-stabilized weight note: is reporting all weight measurements + - property: stabilized + note: reports the stabilization flag transmitted by the scale broadcast_rate: active_scan: encryption_key: diff --git a/docs/_devices/Xiaomi_XMTZC02HM_XMTZC05HM_NUN4049CN.md b/docs/_devices/Xiaomi_XMTZC02HM_XMTZC05HM_NUN4049CN.md index 618080d4..0af5e180 100644 --- a/docs/_devices/Xiaomi_XMTZC02HM_XMTZC05HM_NUN4049CN.md +++ b/docs/_devices/Xiaomi_XMTZC02HM_XMTZC05HM_NUN4049CN.md @@ -8,6 +8,7 @@ broadcasted_properties: - weight - non-stabilized weight - stabilized weight + - stabilized - weight removed - impedance - rssi @@ -18,6 +19,8 @@ broadcasted_property_notes: note: is updated, even if the impedance has not been calculated and send by the scale. This sensor is updated slightly before the weight sensor, even if you step off the scale before the white line starts flashing, but the `weight` measurement does not always correspond to the `impedance` measurement. - property: non-stabilized weight note: this sensor is reporting all weight measurements + - property: stabilized + note: reports the stabilization flag transmitted by the scale broadcast_rate: active_scan: encryption_key: