Add new sensors to BThome (#77561)
This commit is contained in:
parent
7c5a5f86ee
commit
f43f440739
7 changed files with 134 additions and 21 deletions
|
@ -13,7 +13,7 @@
|
|||
"service_data_uuid": "0000181e-0000-1000-8000-00805f9b34fb"
|
||||
}
|
||||
],
|
||||
"requirements": ["bthome-ble==0.4.0"],
|
||||
"requirements": ["bthome-ble==0.5.2"],
|
||||
"dependencies": ["bluetooth"],
|
||||
"codeowners": ["@Ernst79"],
|
||||
"iot_class": "local_push"
|
||||
|
|
|
@ -25,6 +25,7 @@ from homeassistant.const import (
|
|||
ENERGY_KILO_WATT_HOUR,
|
||||
LIGHT_LUX,
|
||||
MASS_KILOGRAMS,
|
||||
MASS_POUNDS,
|
||||
PERCENTAGE,
|
||||
POWER_WATT,
|
||||
PRESSURE_MBAR,
|
||||
|
@ -132,13 +133,41 @@ SENSOR_DESCRIPTIONS = {
|
|||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
# Used for e.g. weight sensor
|
||||
# Used for mass sensor with kg unit
|
||||
(None, Units.MASS_KILOGRAMS): SensorEntityDescription(
|
||||
key=str(Units.MASS_KILOGRAMS),
|
||||
key=f"{DeviceClass.MASS}_{Units.MASS_KILOGRAMS}",
|
||||
device_class=None,
|
||||
native_unit_of_measurement=MASS_KILOGRAMS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Used for mass sensor with lb unit
|
||||
(None, Units.MASS_POUNDS): SensorEntityDescription(
|
||||
key=f"{DeviceClass.MASS}_{Units.MASS_POUNDS}",
|
||||
device_class=None,
|
||||
native_unit_of_measurement=MASS_POUNDS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Used for moisture sensor
|
||||
(None, Units.PERCENTAGE,): SensorEntityDescription(
|
||||
key=f"{DeviceClass.MOISTURE}_{Units.PERCENTAGE}",
|
||||
device_class=None,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Used for dew point sensor
|
||||
(None, Units.TEMP_CELSIUS): SensorEntityDescription(
|
||||
key=f"{DeviceClass.DEW_POINT}_{Units.TEMP_CELSIUS}",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
native_unit_of_measurement=TEMP_CELSIUS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Used for count sensor
|
||||
(None, None): SensorEntityDescription(
|
||||
key=f"{DeviceClass.COUNT}",
|
||||
device_class=None,
|
||||
native_unit_of_measurement=None,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
@ -156,7 +185,6 @@ def sensor_update_to_bluetooth_data_update(
|
|||
(description.device_class, description.native_unit_of_measurement)
|
||||
]
|
||||
for device_key, description in sensor_update.entity_descriptions.items()
|
||||
if description.native_unit_of_measurement
|
||||
},
|
||||
entity_data={
|
||||
device_key_to_bluetooth_entity_key(device_key): sensor_values.native_value
|
||||
|
|
|
@ -458,7 +458,7 @@ bsblan==0.5.0
|
|||
bt_proximity==0.2.1
|
||||
|
||||
# homeassistant.components.bthome
|
||||
bthome-ble==0.4.0
|
||||
bthome-ble==0.5.2
|
||||
|
||||
# homeassistant.components.bt_home_hub_5
|
||||
bthomehub5-devicelist==0.1.1
|
||||
|
|
|
@ -359,7 +359,7 @@ brunt==1.2.0
|
|||
bsblan==0.5.0
|
||||
|
||||
# homeassistant.components.bthome
|
||||
bthome-ble==0.4.0
|
||||
bthome-ble==0.5.2
|
||||
|
||||
# homeassistant.components.buienradar
|
||||
buienradar==1.0.5
|
||||
|
|
|
@ -37,18 +37,18 @@ TEMP_HUMI_ENCRYPTED_SERVICE_INFO = BluetoothServiceInfoBleak(
|
|||
connectable=False,
|
||||
)
|
||||
|
||||
PM_SERVICE_INFO = BluetoothServiceInfoBleak(
|
||||
name="TEST DEVICE 8F80A5",
|
||||
PRST_SERVICE_INFO = BluetoothServiceInfoBleak(
|
||||
name="prst 8F80A5",
|
||||
address="54:48:E6:8F:80:A5",
|
||||
device=BLEDevice("54:48:E6:8F:80:A5", None),
|
||||
rssi=-63,
|
||||
manufacturer_data={},
|
||||
service_data={
|
||||
"0000181c-0000-1000-8000-00805f9b34fb": b"\x03\r\x12\x0c\x03\x0e\x02\x1c"
|
||||
"0000181c-0000-1000-8000-00805f9b34fb": b'\x02\x14\x00\n"\x02\xdd\n\x02\x03{\x12\x02\x0c\n\x0b'
|
||||
},
|
||||
service_uuids=["0000181c-0000-1000-8000-00805f9b34fb"],
|
||||
source="local",
|
||||
advertisement=AdvertisementData(local_name="Not it"),
|
||||
advertisement=AdvertisementData(local_name="prst"),
|
||||
time=0,
|
||||
connectable=False,
|
||||
)
|
||||
|
|
|
@ -11,7 +11,7 @@ from homeassistant.data_entry_flow import FlowResultType
|
|||
|
||||
from . import (
|
||||
NOT_BTHOME_SERVICE_INFO,
|
||||
PM_SERVICE_INFO,
|
||||
PRST_SERVICE_INFO,
|
||||
TEMP_HUMI_ENCRYPTED_SERVICE_INFO,
|
||||
TEMP_HUMI_SERVICE_INFO,
|
||||
)
|
||||
|
@ -185,7 +185,7 @@ async def test_async_step_user_with_found_devices(hass):
|
|||
"""Test setup from service info cache with devices found."""
|
||||
with patch(
|
||||
"homeassistant.components.bthome.config_flow.async_discovered_service_info",
|
||||
return_value=[PM_SERVICE_INFO],
|
||||
return_value=[PRST_SERVICE_INFO],
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
|
@ -199,7 +199,7 @@ async def test_async_step_user_with_found_devices(hass):
|
|||
user_input={"address": "54:48:E6:8F:80:A5"},
|
||||
)
|
||||
assert result2["type"] == FlowResultType.CREATE_ENTRY
|
||||
assert result2["title"] == "TEST DEVICE 80A5"
|
||||
assert result2["title"] == "b-parasite 80A5"
|
||||
assert result2["data"] == {}
|
||||
assert result2["result"].unique_id == "54:48:E6:8F:80:A5"
|
||||
|
||||
|
@ -384,7 +384,7 @@ async def test_async_step_bluetooth_devices_already_setup(hass):
|
|||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_BLUETOOTH},
|
||||
data=PM_SERVICE_INFO,
|
||||
data=PRST_SERVICE_INFO,
|
||||
)
|
||||
assert result["type"] == FlowResultType.ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
|
@ -395,7 +395,7 @@ async def test_async_step_bluetooth_already_in_progress(hass):
|
|||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_BLUETOOTH},
|
||||
data=PM_SERVICE_INFO,
|
||||
data=PRST_SERVICE_INFO,
|
||||
)
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "bluetooth_confirm"
|
||||
|
@ -403,7 +403,7 @@ async def test_async_step_bluetooth_already_in_progress(hass):
|
|||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_BLUETOOTH},
|
||||
data=PM_SERVICE_INFO,
|
||||
data=PRST_SERVICE_INFO,
|
||||
)
|
||||
assert result["type"] == FlowResultType.ABORT
|
||||
assert result["reason"] == "already_in_progress"
|
||||
|
@ -414,14 +414,14 @@ async def test_async_step_user_takes_precedence_over_discovery(hass):
|
|||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_BLUETOOTH},
|
||||
data=PM_SERVICE_INFO,
|
||||
data=PRST_SERVICE_INFO,
|
||||
)
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "bluetooth_confirm"
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bthome.config_flow.async_discovered_service_info",
|
||||
return_value=[PM_SERVICE_INFO],
|
||||
return_value=[PRST_SERVICE_INFO],
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
|
@ -435,7 +435,7 @@ async def test_async_step_user_takes_precedence_over_discovery(hass):
|
|||
user_input={"address": "54:48:E6:8F:80:A5"},
|
||||
)
|
||||
assert result2["type"] == FlowResultType.CREATE_ENTRY
|
||||
assert result2["title"] == "TEST DEVICE 80A5"
|
||||
assert result2["title"] == "b-parasite 80A5"
|
||||
assert result2["data"] == {}
|
||||
assert result2["result"].unique_id == "54:48:E6:8F:80:A5"
|
||||
|
||||
|
|
|
@ -106,6 +106,73 @@ from tests.common import MockConfigEntry
|
|||
},
|
||||
],
|
||||
),
|
||||
(
|
||||
"A4:C1:38:8D:18:B2",
|
||||
make_advertisement(
|
||||
"A4:C1:38:8D:18:B2",
|
||||
b"\x03\x06\x5e\x1f",
|
||||
),
|
||||
None,
|
||||
[
|
||||
{
|
||||
"sensor_entity": "sensor.test_device_18b2_mass",
|
||||
"friendly_name": "Test Device 18B2 Mass",
|
||||
"unit_of_measurement": "kg",
|
||||
"state_class": "measurement",
|
||||
"expected_state": "80.3",
|
||||
},
|
||||
],
|
||||
),
|
||||
(
|
||||
"A4:C1:38:8D:18:B2",
|
||||
make_advertisement(
|
||||
"A4:C1:38:8D:18:B2",
|
||||
b"\x03\x07\x3e\x1d",
|
||||
),
|
||||
None,
|
||||
[
|
||||
{
|
||||
"sensor_entity": "sensor.test_device_18b2_mass",
|
||||
"friendly_name": "Test Device 18B2 Mass",
|
||||
"unit_of_measurement": "lb",
|
||||
"state_class": "measurement",
|
||||
"expected_state": "74.86",
|
||||
},
|
||||
],
|
||||
),
|
||||
(
|
||||
"A4:C1:38:8D:18:B2",
|
||||
make_advertisement(
|
||||
"A4:C1:38:8D:18:B2",
|
||||
b"\x23\x08\xCA\x06",
|
||||
),
|
||||
None,
|
||||
[
|
||||
{
|
||||
"sensor_entity": "sensor.test_device_18b2_dew_point",
|
||||
"friendly_name": "Test Device 18B2 Dew Point",
|
||||
"unit_of_measurement": "°C",
|
||||
"state_class": "measurement",
|
||||
"expected_state": "17.38",
|
||||
},
|
||||
],
|
||||
),
|
||||
(
|
||||
"A4:C1:38:8D:18:B2",
|
||||
make_advertisement(
|
||||
"A4:C1:38:8D:18:B2",
|
||||
b"\x02\x09\x60",
|
||||
),
|
||||
None,
|
||||
[
|
||||
{
|
||||
"sensor_entity": "sensor.test_device_18b2_count",
|
||||
"friendly_name": "Test Device 18B2 Count",
|
||||
"state_class": "measurement",
|
||||
"expected_state": "96",
|
||||
},
|
||||
],
|
||||
),
|
||||
(
|
||||
"A4:C1:38:8D:18:B2",
|
||||
make_advertisement(
|
||||
|
@ -215,6 +282,23 @@ from tests.common import MockConfigEntry
|
|||
},
|
||||
],
|
||||
),
|
||||
(
|
||||
"A4:C1:38:8D:18:B2",
|
||||
make_advertisement(
|
||||
"A4:C1:38:8D:18:B2",
|
||||
b"\x03\x14\x02\x0c",
|
||||
),
|
||||
None,
|
||||
[
|
||||
{
|
||||
"sensor_entity": "sensor.test_device_18b2_moisture",
|
||||
"friendly_name": "Test Device 18B2 Moisture",
|
||||
"unit_of_measurement": "%",
|
||||
"state_class": "measurement",
|
||||
"expected_state": "30.74",
|
||||
},
|
||||
],
|
||||
),
|
||||
(
|
||||
"54:48:E6:8F:80:A5",
|
||||
make_encrypted_advertisement(
|
||||
|
@ -283,8 +367,9 @@ async def test_sensors(
|
|||
sensor = hass.states.get(meas["sensor_entity"])
|
||||
sensor_attr = sensor.attributes
|
||||
assert sensor.state == meas["expected_state"]
|
||||
|
||||
assert sensor_attr[ATTR_FRIENDLY_NAME] == meas["friendly_name"]
|
||||
if ATTR_UNIT_OF_MEASUREMENT in sensor_attr:
|
||||
# Count sensor does not have a unit of measurement
|
||||
assert sensor_attr[ATTR_UNIT_OF_MEASUREMENT] == meas["unit_of_measurement"]
|
||||
assert sensor_attr[ATTR_STATE_CLASS] == meas["state_class"]
|
||||
assert await hass.config_entries.async_unload(entry.entry_id)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue