diff --git a/homeassistant/components/xiaomi_ble/manifest.json b/homeassistant/components/xiaomi_ble/manifest.json index 69a95ea8a9c..73b22ddab9f 100644 --- a/homeassistant/components/xiaomi_ble/manifest.json +++ b/homeassistant/components/xiaomi_ble/manifest.json @@ -2,6 +2,10 @@ "domain": "xiaomi_ble", "name": "Xiaomi BLE", "bluetooth": [ + { + "connectable": false, + "service_data_uuid": "0000181b-0000-1000-8000-00805f9b34fb" + }, { "connectable": false, "service_data_uuid": "0000fd50-0000-1000-8000-00805f9b34fb" @@ -16,5 +20,5 @@ "dependencies": ["bluetooth_adapters"], "documentation": "https://www.home-assistant.io/integrations/xiaomi_ble", "iot_class": "local_push", - "requirements": ["xiaomi-ble==0.17.2"] + "requirements": ["xiaomi-ble==0.18.2"] } diff --git a/homeassistant/components/xiaomi_ble/sensor.py b/homeassistant/components/xiaomi_ble/sensor.py index 81739db4d11..84ef91bf5a8 100644 --- a/homeassistant/components/xiaomi_ble/sensor.py +++ b/homeassistant/components/xiaomi_ble/sensor.py @@ -24,6 +24,7 @@ from homeassistant.const import ( SIGNAL_STRENGTH_DECIBELS_MILLIWATT, EntityCategory, UnitOfElectricPotential, + UnitOfMass, UnitOfPressure, UnitOfTemperature, ) @@ -68,6 +69,28 @@ SENSOR_DESCRIPTIONS = { native_unit_of_measurement=LIGHT_LUX, state_class=SensorStateClass.MEASUREMENT, ), + # Impedance sensor (ohm) + (DeviceClass.IMPEDANCE, Units.OHM): SensorEntityDescription( + key=f"{DeviceClass.IMPEDANCE}_{Units.OHM}", + icon="mdi:omega", + native_unit_of_measurement=Units.OHM, + state_class=SensorStateClass.MEASUREMENT, + ), + # Mass sensor (kg) + (DeviceClass.MASS, Units.MASS_KILOGRAMS): SensorEntityDescription( + key=f"{DeviceClass.MASS}_{Units.MASS_KILOGRAMS}", + device_class=SensorDeviceClass.WEIGHT, + native_unit_of_measurement=UnitOfMass.KILOGRAMS, + state_class=SensorStateClass.MEASUREMENT, + ), + # Mass non stabilized sensor (kg) + (DeviceClass.MASS_NON_STABILIZED, Units.MASS_KILOGRAMS): SensorEntityDescription( + key=f"{DeviceClass.MASS_NON_STABILIZED}_{Units.MASS_KILOGRAMS}", + device_class=SensorDeviceClass.WEIGHT, + native_unit_of_measurement=UnitOfMass.KILOGRAMS, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + ), (DeviceClass.MOISTURE, Units.PERCENTAGE): SensorEntityDescription( key=f"{DeviceClass.MOISTURE}_{Units.PERCENTAGE}", device_class=SensorDeviceClass.MOISTURE, diff --git a/homeassistant/generated/bluetooth.py b/homeassistant/generated/bluetooth.py index 64fae252975..aba97c8ea8c 100644 --- a/homeassistant/generated/bluetooth.py +++ b/homeassistant/generated/bluetooth.py @@ -504,6 +504,11 @@ BLUETOOTH: list[dict[str, bool | str | int | list[int]]] = [ ], "manufacturer_id": 76, }, + { + "connectable": False, + "domain": "xiaomi_ble", + "service_data_uuid": "0000181b-0000-1000-8000-00805f9b34fb", + }, { "connectable": False, "domain": "xiaomi_ble", diff --git a/requirements_all.txt b/requirements_all.txt index 5d4d9648d71..d57d0cc1c69 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2684,7 +2684,7 @@ wyoming==1.1.0 xbox-webapi==2.0.11 # homeassistant.components.xiaomi_ble -xiaomi-ble==0.17.2 +xiaomi-ble==0.18.2 # homeassistant.components.knx xknx==2.11.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 649c25c4d6b..bc665abf4c8 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1966,7 +1966,7 @@ wyoming==1.1.0 xbox-webapi==2.0.11 # homeassistant.components.xiaomi_ble -xiaomi-ble==0.17.2 +xiaomi-ble==0.18.2 # homeassistant.components.knx xknx==2.11.1 diff --git a/tests/components/xiaomi_ble/__init__.py b/tests/components/xiaomi_ble/__init__.py index ea11feab9c2..879ab4f7bc4 100644 --- a/tests/components/xiaomi_ble/__init__.py +++ b/tests/components/xiaomi_ble/__init__.py @@ -105,6 +105,22 @@ HHCCJCY10_SERVICE_INFO = BluetoothServiceInfoBleak( connectable=False, ) +MISCALE_V2_SERVICE_INFO = BluetoothServiceInfoBleak( + name="MIBFS", + address="50:FB:19:1B:B5:DC", + device=generate_ble_device("00:00:00:00:00:00", None), + rssi=-60, + manufacturer_data={}, + service_data={ + "0000181b-0000-1000-8000-00805f9b34fb": b"\x02\xa6\xe7\x07\x07\x07\x0b\x1f\x1d\x1f\x02\xfa-" + }, + service_uuids=["0000181b-0000-1000-8000-00805f9b34fb"], + source="local", + advertisement=generate_advertisement_data(local_name="Not it"), + time=0, + connectable=False, +) + MISSING_PAYLOAD_ENCRYPTED = BluetoothServiceInfoBleak( name="LYWSD02MMC", address="A4:C1:38:56:53:84", diff --git a/tests/components/xiaomi_ble/test_sensor.py b/tests/components/xiaomi_ble/test_sensor.py index 1d6344063b5..40d89a8214d 100644 --- a/tests/components/xiaomi_ble/test_sensor.py +++ b/tests/components/xiaomi_ble/test_sensor.py @@ -4,7 +4,12 @@ from homeassistant.components.xiaomi_ble.const import DOMAIN from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT from homeassistant.core import HomeAssistant -from . import HHCCJCY10_SERVICE_INFO, MMC_T201_1_SERVICE_INFO, make_advertisement +from . import ( + HHCCJCY10_SERVICE_INFO, + MISCALE_V2_SERVICE_INFO, + MMC_T201_1_SERVICE_INFO, + make_advertisement, +) from tests.common import MockConfigEntry from tests.components.bluetooth import inject_bluetooth_service_info_bleak @@ -506,3 +511,60 @@ async def test_hhccjcy10_uuid(hass: HomeAssistant) -> None: assert await hass.config_entries.async_unload(entry.entry_id) await hass.async_block_till_done() + + +async def test_miscale_v2_uuid(hass: HomeAssistant) -> None: + """Test MiScale V2 UUID. + + This device uses a different UUID compared to the other Xiaomi sensors. + """ + entry = MockConfigEntry( + domain=DOMAIN, + unique_id="50:FB:19:1B:B5:DC", + ) + entry.add_to_hass(hass) + + assert await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + inject_bluetooth_service_info_bleak(hass, MISCALE_V2_SERVICE_INFO) + + await hass.async_block_till_done() + assert len(hass.states.async_all()) == 3 + + mass_non_stabilized_sensor = hass.states.get( + "sensor.mi_body_composition_scale_2_b5dc_mass_non_stabilized" + ) + mass_non_stabilized_sensor_attr = mass_non_stabilized_sensor.attributes + assert mass_non_stabilized_sensor.state == "58.85" + assert ( + mass_non_stabilized_sensor_attr[ATTR_FRIENDLY_NAME] + == "Mi Body Composition Scale 2 (B5DC) Mass Non Stabilized" + ) + assert mass_non_stabilized_sensor_attr[ATTR_UNIT_OF_MEASUREMENT] == "kg" + assert mass_non_stabilized_sensor_attr[ATTR_STATE_CLASS] == "measurement" + + mass_sensor = hass.states.get("sensor.mi_body_composition_scale_2_b5dc_mass") + mass_sensor_attr = mass_sensor.attributes + assert mass_sensor.state == "58.85" + assert ( + mass_sensor_attr[ATTR_FRIENDLY_NAME] + == "Mi Body Composition Scale 2 (B5DC) Mass" + ) + assert mass_sensor_attr[ATTR_UNIT_OF_MEASUREMENT] == "kg" + assert mass_sensor_attr[ATTR_STATE_CLASS] == "measurement" + + impedance_sensor = hass.states.get( + "sensor.mi_body_composition_scale_2_b5dc_impedance" + ) + impedance_sensor_attr = impedance_sensor.attributes + assert impedance_sensor.state == "543" + assert ( + impedance_sensor_attr[ATTR_FRIENDLY_NAME] + == "Mi Body Composition Scale 2 (B5DC) Impedance" + ) + assert impedance_sensor_attr[ATTR_UNIT_OF_MEASUREMENT] == "ohm" + assert impedance_sensor_attr[ATTR_STATE_CLASS] == "measurement" + + assert await hass.config_entries.async_unload(entry.entry_id) + await hass.async_block_till_done()