mirror of
https://github.com/home-assistant/core.git
synced 2026-09-26 17:31:15 -04:00
Use radon device class for Aranet sensors (#182952)
This commit is contained in:
@@ -25,6 +25,7 @@ from homeassistant.const import (
|
||||
ATTR_SW_VERSION,
|
||||
EntityCategory,
|
||||
UnitOfPressure,
|
||||
UnitOfRadiationConcentration,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
@@ -107,7 +108,8 @@ SENSOR_DESCRIPTIONS = {
|
||||
key="radon_concentration",
|
||||
translation_key="radon_concentration",
|
||||
name="Radon Concentration",
|
||||
native_unit_of_measurement="Bq/m³",
|
||||
device_class=SensorDeviceClass.RADON,
|
||||
native_unit_of_measurement=UnitOfRadiationConcentration.BECQUEREL_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"battery": AranetSensorEntityDescription(
|
||||
@@ -209,6 +211,17 @@ class Aranet4BluetoothSensorEntity(
|
||||
):
|
||||
"""Representation of an Aranet sensor."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
processor: PassiveBluetoothDataProcessor[
|
||||
float | int | None, Aranet4Advertisement
|
||||
],
|
||||
entity_key: PassiveBluetoothEntityKey,
|
||||
description: EntityDescription,
|
||||
) -> None:
|
||||
"""Initialize with current metadata instead of a cached description."""
|
||||
super().__init__(processor, entity_key, SENSOR_DESCRIPTIONS[entity_key.key])
|
||||
|
||||
@property
|
||||
@override
|
||||
def available(self) -> bool:
|
||||
|
||||
@@ -105,3 +105,14 @@ VALID_ARANET_RADON_DATA_SERVICE_INFO = fake_service_info(
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
VALID_ARANET_RADON1_DATA_SERVICE_INFO = fake_service_info(
|
||||
"AranetRn1 12345",
|
||||
"0000fce0-0000-1000-8000-00805f9b34fb",
|
||||
{
|
||||
1794: (
|
||||
b"\x03!\x04\x06\x01\x00\x00\x00\x07\x00"
|
||||
b"\x00\x00\xc9'\x00\x00\x00d\x01X\x02\xf6\x01\x08"
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
"""Aranet session fixtures."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_bluetooth_storage(
|
||||
hass_storage: dict[str, Any], request: pytest.FixtureRequest
|
||||
) -> None:
|
||||
"""Load Bluetooth storage before setting up the integration."""
|
||||
hass_storage.update(getattr(request, "param", {}))
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_bluetooth(enable_bluetooth: None) -> None:
|
||||
def mock_bluetooth(mock_bluetooth_storage: None, enable_bluetooth: None) -> None:
|
||||
"""Auto mock bluetooth."""
|
||||
|
||||
@@ -3,15 +3,33 @@
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.aranet.const import DOMAIN
|
||||
from homeassistant.components.sensor import ATTR_OPTIONS, ATTR_STATE_CLASS
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
||||
from homeassistant.components.bluetooth import BluetoothServiceInfoBleak
|
||||
from homeassistant.components.bluetooth.passive_update_processor import STORAGE_KEY
|
||||
from homeassistant.components.sensor import (
|
||||
ATTR_OPTIONS,
|
||||
ATTR_STATE_CLASS,
|
||||
SensorDeviceClass,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_DEVICE_CLASS,
|
||||
ATTR_FRIENDLY_NAME,
|
||||
ATTR_UNIT_OF_MEASUREMENT,
|
||||
UnitOfRadiationConcentration,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.util.unit_system import (
|
||||
METRIC_SYSTEM,
|
||||
US_CUSTOMARY_SYSTEM,
|
||||
UnitSystem,
|
||||
)
|
||||
|
||||
from . import (
|
||||
DISABLED_INTEGRATIONS_SERVICE_INFO,
|
||||
VALID_ARANET2_DATA_SERVICE_INFO,
|
||||
VALID_ARANET_RADIATION_DATA_SERVICE_INFO,
|
||||
VALID_ARANET_RADON1_DATA_SERVICE_INFO,
|
||||
VALID_ARANET_RADON_DATA_SERVICE_INFO,
|
||||
VALID_DATA_SERVICE_INFO,
|
||||
)
|
||||
@@ -19,6 +37,9 @@ from . import (
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
RADON_ENTITY_ID = "sensor.aranetrn_12345_radon_concentration"
|
||||
RADON_UNIQUE_ID = "aa:bb:cc:dd:ee:ff-radon_concentration-aa:bb:cc:dd:ee:ff"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_sensors_aranet_radiation(
|
||||
@@ -263,7 +284,7 @@ async def test_sensors_aranetrn(
|
||||
assert batt_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "%"
|
||||
assert batt_sensor_attrs[ATTR_STATE_CLASS] == "measurement"
|
||||
|
||||
co2_sensor = hass.states.get("sensor.aranetrn_12345_radon_concentration")
|
||||
co2_sensor = hass.states.get(RADON_ENTITY_ID)
|
||||
co2_sensor_attrs = co2_sensor.attributes
|
||||
assert co2_sensor.state == "7"
|
||||
assert co2_sensor_attrs[ATTR_FRIENDLY_NAME] == "AranetRn+ 12345 Radon Concentration"
|
||||
@@ -319,6 +340,170 @@ async def test_sensors_aranetrn(
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("service_info", "entity_id"),
|
||||
[
|
||||
pytest.param(
|
||||
VALID_ARANET_RADON_DATA_SERVICE_INFO,
|
||||
RADON_ENTITY_ID,
|
||||
id="aranetrn_plus",
|
||||
),
|
||||
pytest.param(
|
||||
VALID_ARANET_RADON1_DATA_SERVICE_INFO,
|
||||
"sensor.aranetrn1_12345_radon_concentration",
|
||||
id="aranetrn1",
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("unit_system", "expected_unit", "expected_value"),
|
||||
[
|
||||
pytest.param(
|
||||
METRIC_SYSTEM,
|
||||
UnitOfRadiationConcentration.BECQUEREL_PER_CUBIC_METER,
|
||||
7,
|
||||
id="metric",
|
||||
),
|
||||
pytest.param(
|
||||
US_CUSTOMARY_SYSTEM,
|
||||
UnitOfRadiationConcentration.PICOCURIES_PER_LITER,
|
||||
7 / 37,
|
||||
id="us_customary",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_radon_device_class_and_units(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
service_info: BluetoothServiceInfoBleak,
|
||||
entity_id: str,
|
||||
unit_system: UnitSystem,
|
||||
expected_unit: UnitOfRadiationConcentration,
|
||||
expected_value: float,
|
||||
) -> None:
|
||||
"""Test radon metadata and default units."""
|
||||
hass.config.units = unit_system
|
||||
entry = MockConfigEntry(domain=DOMAIN, unique_id=service_info.address)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
inject_bluetooth_service_info(hass, service_info)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state is not None
|
||||
assert float(state.state) == pytest.approx(expected_value)
|
||||
assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.RADON
|
||||
assert state.attributes[ATTR_STATE_CLASS] == SensorStateClass.MEASUREMENT
|
||||
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == expected_unit
|
||||
assert (
|
||||
state.attributes[ATTR_FRIENDLY_NAME]
|
||||
== f"{service_info.name} Radon Concentration"
|
||||
)
|
||||
entity = entity_registry.async_get(entity_id)
|
||||
assert entity is not None
|
||||
assert entity.unique_id == RADON_UNIQUE_ID
|
||||
assert entity.original_device_class == SensorDeviceClass.RADON
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("mock_bluetooth_storage", "restored_device_classes"),
|
||||
[
|
||||
pytest.param({}, {}, id="without_cache"),
|
||||
pytest.param(
|
||||
{
|
||||
STORAGE_KEY: {
|
||||
"version": 1,
|
||||
"minor_version": 1,
|
||||
"key": STORAGE_KEY,
|
||||
"data": {
|
||||
"aranet_radon": {
|
||||
"sensor": {
|
||||
"devices": {
|
||||
"aa:bb:cc:dd:ee:ff": {
|
||||
"name": "AranetRn+ 12345",
|
||||
"connections": [
|
||||
["bluetooth", "aa:bb:cc:dd:ee:ff"]
|
||||
],
|
||||
}
|
||||
},
|
||||
"entity_descriptions": {
|
||||
"radon_concentration___aa:bb:cc:dd:ee:ff": {
|
||||
"key": "radon_concentration",
|
||||
"translation_key": "radon_concentration",
|
||||
"name": "Radon Concentration",
|
||||
"native_unit_of_measurement": "Bq/m³",
|
||||
"state_class": "measurement",
|
||||
}
|
||||
},
|
||||
"entity_names": {
|
||||
"radon_concentration___aa:bb:cc:dd:ee:ff": (
|
||||
"Radon Concentration"
|
||||
)
|
||||
},
|
||||
"entity_data": {
|
||||
"radon_concentration___aa:bb:cc:dd:ee:ff": 7
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
{RADON_ENTITY_ID: SensorDeviceClass.RADON},
|
||||
id="cached_without_device_class",
|
||||
),
|
||||
],
|
||||
indirect=["mock_bluetooth_storage"],
|
||||
)
|
||||
async def test_existing_radon_sensor(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
restored_device_classes: dict[str, SensorDeviceClass],
|
||||
) -> None:
|
||||
"""Test existing radon sensors gain the class without changing identity or units."""
|
||||
hass.config.units = US_CUSTOMARY_SYSTEM
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
entry_id="aranet_radon",
|
||||
unique_id="aa:bb:cc:dd:ee:ff",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
entity = entity_registry.async_get_or_create(
|
||||
"sensor",
|
||||
DOMAIN,
|
||||
RADON_UNIQUE_ID,
|
||||
config_entry=entry,
|
||||
suggested_object_id="aranetrn_12345_radon_concentration",
|
||||
original_name="Radon Concentration",
|
||||
unit_of_measurement=UnitOfRadiationConcentration.BECQUEREL_PER_CUBIC_METER,
|
||||
)
|
||||
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert {
|
||||
state.entity_id: state.attributes[ATTR_DEVICE_CLASS]
|
||||
for state in hass.states.async_all("sensor")
|
||||
} == restored_device_classes
|
||||
|
||||
inject_bluetooth_service_info(hass, VALID_ARANET_RADON_DATA_SERVICE_INFO)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(RADON_ENTITY_ID)
|
||||
assert state is not None
|
||||
assert state.state == "7"
|
||||
assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.RADON
|
||||
assert (
|
||||
state.attributes[ATTR_UNIT_OF_MEASUREMENT]
|
||||
== UnitOfRadiationConcentration.BECQUEREL_PER_CUBIC_METER
|
||||
)
|
||||
assert state.attributes[ATTR_FRIENDLY_NAME] == "AranetRn+ 12345 Radon Concentration"
|
||||
updated_entity = entity_registry.async_get(RADON_ENTITY_ID)
|
||||
assert updated_entity is not None
|
||||
assert updated_entity.id == entity.id
|
||||
assert updated_entity.unique_id == RADON_UNIQUE_ID
|
||||
assert updated_entity.original_device_class == SensorDeviceClass.RADON
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_smart_home_integration_disabled(hass: HomeAssistant) -> None:
|
||||
"""Test disabling smart home integration marks entities as unavailable."""
|
||||
|
||||
Reference in New Issue
Block a user