mirror of
https://github.com/home-assistant/core.git
synced 2026-05-08 17:49:37 +01:00
Add new sensors for Airthings Wave Enhance (#153879)
This commit is contained in:
committed by
GitHub
parent
b46097a7fc
commit
4587c286bb
@@ -16,10 +16,12 @@ from homeassistant.components.sensor import (
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
Platform,
|
||||
UnitOfPressure,
|
||||
UnitOfSoundPressure,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
@@ -112,6 +114,21 @@ SENSORS_MAPPING_TEMPLATE: dict[str, SensorEntityDescription] = {
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"lux": SensorEntityDescription(
|
||||
key="lux",
|
||||
device_class=SensorDeviceClass.ILLUMINANCE,
|
||||
native_unit_of_measurement=LIGHT_LUX,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"noise": SensorEntityDescription(
|
||||
key="noise",
|
||||
translation_key="ambient_noise",
|
||||
device_class=SensorDeviceClass.SOUND_PRESSURE,
|
||||
native_unit_of_measurement=UnitOfSoundPressure.WEIGHTED_DECIBEL_A,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
}
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@@ -41,6 +41,9 @@
|
||||
},
|
||||
"illuminance": {
|
||||
"name": "[%key:component::sensor::entity_component::illuminance::name%]"
|
||||
},
|
||||
"ambient_noise": {
|
||||
"name": "Ambient noise"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,17 @@ from airthings_ble import (
|
||||
AirthingsDevice,
|
||||
AirthingsDeviceType,
|
||||
)
|
||||
from bleak.backends.device import BLEDevice
|
||||
|
||||
from homeassistant.components.airthings_ble.const import DOMAIN
|
||||
from homeassistant.components.bluetooth.models import BluetoothServiceInfoBleak
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import CONNECTION_BLUETOOTH, DeviceRegistry
|
||||
from homeassistant.helpers.device_registry import (
|
||||
CONNECTION_BLUETOOTH,
|
||||
DeviceEntry,
|
||||
DeviceRegistry,
|
||||
)
|
||||
|
||||
from tests.common import MockConfigEntry, MockEntity
|
||||
from tests.components.bluetooth import generate_advertisement_data, generate_ble_device
|
||||
@@ -28,7 +33,15 @@ def patch_async_setup_entry(return_value=True):
|
||||
)
|
||||
|
||||
|
||||
def patch_async_ble_device_from_address(return_value: BluetoothServiceInfoBleak | None):
|
||||
def patch_async_discovered_service_info(return_value: list[BluetoothServiceInfoBleak]):
|
||||
"""Patch async_discovered_service_info to return given list."""
|
||||
return patch(
|
||||
"homeassistant.components.bluetooth.async_discovered_service_info",
|
||||
return_value=return_value,
|
||||
)
|
||||
|
||||
|
||||
def patch_async_ble_device_from_address(return_value: BLEDevice | None):
|
||||
"""Patch async ble device from address to return a given value."""
|
||||
return patch(
|
||||
"homeassistant.components.bluetooth.async_ble_device_from_address",
|
||||
@@ -101,6 +114,27 @@ WAVE_SERVICE_INFO = BluetoothServiceInfoBleak(
|
||||
tx_power=0,
|
||||
)
|
||||
|
||||
WAVE_ENHANCE_SERVICE_INFO = BluetoothServiceInfoBleak(
|
||||
name="cc-cc-cc-cc-cc-cc",
|
||||
address="cc:cc:cc:cc:cc:cc",
|
||||
device=generate_ble_device(
|
||||
address="cc:cc:cc:cc:cc:cc",
|
||||
name="Airthings Wave Enhance",
|
||||
),
|
||||
rssi=-61,
|
||||
manufacturer_data={820: b"\xe4/\xa5\xae\t\x00"},
|
||||
service_data={},
|
||||
service_uuids=[],
|
||||
source="local",
|
||||
advertisement=generate_advertisement_data(
|
||||
manufacturer_data={820: b"\xe4/\xa5\xae\t\x00"},
|
||||
service_uuids=[],
|
||||
),
|
||||
connectable=True,
|
||||
time=0,
|
||||
tx_power=0,
|
||||
)
|
||||
|
||||
VIEW_PLUS_SERVICE_INFO = BluetoothServiceInfoBleak(
|
||||
name="cc-cc-cc-cc-cc-cc",
|
||||
address="cc:cc:cc:cc:cc:cc",
|
||||
@@ -211,6 +245,26 @@ WAVE_DEVICE_INFO = AirthingsDevice(
|
||||
address="cc:cc:cc:cc:cc:cc",
|
||||
)
|
||||
|
||||
WAVE_ENHANCE_DEVICE_INFO = AirthingsDevice(
|
||||
manufacturer="Airthings AS",
|
||||
hw_version="REV X",
|
||||
sw_version="T-SUB-2.6.2-master+0",
|
||||
model=AirthingsDeviceType.WAVE_ENHANCE_EU,
|
||||
name="Airthings Wave Enhance",
|
||||
identifier="123456",
|
||||
sensors={
|
||||
"lux": 25,
|
||||
"battery": 85,
|
||||
"humidity": 60.0,
|
||||
"temperature": 21.0,
|
||||
"co2": 500.0,
|
||||
"voc": 155.0,
|
||||
"pressure": 1020,
|
||||
"noise": 40,
|
||||
},
|
||||
address="cc:cc:cc:cc:cc:cc",
|
||||
)
|
||||
|
||||
TEMPERATURE_V1 = MockEntity(
|
||||
unique_id="Airthings Wave Plus 123456_temperature",
|
||||
name="Airthings Wave Plus 123456 Temperature",
|
||||
@@ -247,23 +301,32 @@ VOC_V3 = MockEntity(
|
||||
)
|
||||
|
||||
|
||||
def create_entry(hass: HomeAssistant) -> MockConfigEntry:
|
||||
def create_entry(
|
||||
hass: HomeAssistant,
|
||||
service_info: BluetoothServiceInfoBleak,
|
||||
device_info: AirthingsDevice,
|
||||
) -> MockConfigEntry:
|
||||
"""Create a config entry."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id=WAVE_SERVICE_INFO.address,
|
||||
title="Airthings Wave Plus (123456)",
|
||||
unique_id=service_info.address,
|
||||
title=f"{device_info.name} ({device_info.identifier})",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
return entry
|
||||
|
||||
|
||||
def create_device(entry: ConfigEntry, device_registry: DeviceRegistry):
|
||||
def create_device(
|
||||
entry: ConfigEntry,
|
||||
device_registry: DeviceRegistry,
|
||||
service_info: BluetoothServiceInfoBleak,
|
||||
device_info: AirthingsDevice,
|
||||
) -> DeviceEntry:
|
||||
"""Create a device for the given entry."""
|
||||
return device_registry.async_get_or_create(
|
||||
config_entry_id=entry.entry_id,
|
||||
connections={(CONNECTION_BLUETOOTH, WAVE_SERVICE_INFO.address)},
|
||||
connections={(CONNECTION_BLUETOOTH, service_info.address)},
|
||||
manufacturer="Airthings AS",
|
||||
name="Airthings Wave Plus (123456)",
|
||||
model="Wave Plus",
|
||||
name=f"{device_info.name} ({device_info.identifier})",
|
||||
model=device_info.model.product_name,
|
||||
)
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.airthings_ble.const import DOMAIN
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -16,10 +18,15 @@ from . import (
|
||||
VOC_V2,
|
||||
VOC_V3,
|
||||
WAVE_DEVICE_INFO,
|
||||
WAVE_ENHANCE_DEVICE_INFO,
|
||||
WAVE_ENHANCE_SERVICE_INFO,
|
||||
WAVE_SERVICE_INFO,
|
||||
create_device,
|
||||
create_entry,
|
||||
patch_airthings_ble,
|
||||
patch_airthings_device_update,
|
||||
patch_async_ble_device_from_address,
|
||||
patch_async_discovered_service_info,
|
||||
)
|
||||
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
@@ -33,8 +40,8 @@ async def test_migration_from_v1_to_v3_unique_id(
|
||||
device_registry: dr.DeviceRegistry,
|
||||
) -> None:
|
||||
"""Verify that we can migrate from v1 (pre 2023.9.0) to the latest unique id format."""
|
||||
entry = create_entry(hass)
|
||||
device = create_device(entry, device_registry)
|
||||
entry = create_entry(hass, WAVE_SERVICE_INFO, WAVE_DEVICE_INFO)
|
||||
device = create_device(entry, device_registry, WAVE_SERVICE_INFO, WAVE_DEVICE_INFO)
|
||||
|
||||
assert entry is not None
|
||||
assert device is not None
|
||||
@@ -74,8 +81,8 @@ async def test_migration_from_v2_to_v3_unique_id(
|
||||
device_registry: dr.DeviceRegistry,
|
||||
) -> None:
|
||||
"""Verify that we can migrate from v2 (introduced in 2023.9.0) to the latest unique id format."""
|
||||
entry = create_entry(hass)
|
||||
device = create_device(entry, device_registry)
|
||||
entry = create_entry(hass, WAVE_SERVICE_INFO, WAVE_DEVICE_INFO)
|
||||
device = create_device(entry, device_registry, WAVE_SERVICE_INFO, WAVE_DEVICE_INFO)
|
||||
|
||||
assert entry is not None
|
||||
assert device is not None
|
||||
@@ -115,8 +122,8 @@ async def test_migration_from_v1_and_v2_to_v3_unique_id(
|
||||
device_registry: dr.DeviceRegistry,
|
||||
) -> None:
|
||||
"""Test if migration works when we have both v1 (pre 2023.9.0) and v2 (introduced in 2023.9.0) unique ids."""
|
||||
entry = create_entry(hass)
|
||||
device = create_device(entry, device_registry)
|
||||
entry = create_entry(hass, WAVE_SERVICE_INFO, WAVE_DEVICE_INFO)
|
||||
device = create_device(entry, device_registry, WAVE_SERVICE_INFO, WAVE_DEVICE_INFO)
|
||||
|
||||
assert entry is not None
|
||||
assert device is not None
|
||||
@@ -165,8 +172,8 @@ async def test_migration_with_all_unique_ids(
|
||||
device_registry: dr.DeviceRegistry,
|
||||
) -> None:
|
||||
"""Test if migration works when we have all unique ids."""
|
||||
entry = create_entry(hass)
|
||||
device = create_device(entry, device_registry)
|
||||
entry = create_entry(hass, WAVE_SERVICE_INFO, WAVE_DEVICE_INFO)
|
||||
device = create_device(entry, device_registry, WAVE_SERVICE_INFO, WAVE_DEVICE_INFO)
|
||||
|
||||
assert entry is not None
|
||||
assert device is not None
|
||||
@@ -215,3 +222,48 @@ async def test_migration_with_all_unique_ids(
|
||||
assert entity_registry.async_get(v1.entity_id).unique_id == VOC_V1.unique_id
|
||||
assert entity_registry.async_get(v2.entity_id).unique_id == VOC_V2.unique_id
|
||||
assert entity_registry.async_get(v3.entity_id).unique_id == VOC_V3.unique_id
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("unique_suffix", "expected_sensor_name"),
|
||||
[
|
||||
("lux", "Illuminance"),
|
||||
("noise", "Ambient noise"),
|
||||
],
|
||||
)
|
||||
async def test_translation_keys(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
unique_suffix: str,
|
||||
expected_sensor_name: str,
|
||||
) -> None:
|
||||
"""Test that translated sensor names are correct."""
|
||||
entry = create_entry(hass, WAVE_ENHANCE_SERVICE_INFO, WAVE_DEVICE_INFO)
|
||||
device = create_device(
|
||||
entry, device_registry, WAVE_ENHANCE_SERVICE_INFO, WAVE_ENHANCE_DEVICE_INFO
|
||||
)
|
||||
|
||||
with (
|
||||
patch_async_ble_device_from_address(WAVE_ENHANCE_SERVICE_INFO.device),
|
||||
patch_async_discovered_service_info([WAVE_ENHANCE_SERVICE_INFO]),
|
||||
patch_airthings_ble(WAVE_ENHANCE_DEVICE_INFO),
|
||||
):
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert device is not None
|
||||
assert device.name == "Airthings Wave Enhance (123456)"
|
||||
|
||||
unique_id = f"{WAVE_ENHANCE_DEVICE_INFO.address}_{unique_suffix}"
|
||||
entity_id = entity_registry.async_get_entity_id(Platform.SENSOR, DOMAIN, unique_id)
|
||||
assert entity_id is not None
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state is not None
|
||||
|
||||
expected_value = WAVE_ENHANCE_DEVICE_INFO.sensors[unique_suffix]
|
||||
assert state.state == str(expected_value)
|
||||
|
||||
expected_name = f"Airthings Wave Enhance (123456) {expected_sensor_name}"
|
||||
assert state.attributes.get("friendly_name") == expected_name
|
||||
|
||||
Reference in New Issue
Block a user