mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 16:27:08 +00:00
Matter sensors for air quality measurements (#108173)
* Matter sensors for air quality measurements Add sensors for CO2, PM1, PM2.5, PM10 and TVOC * Add initial tests for matter air quality sensor * Remove VOC data as requires unit extraction from cluster
This commit is contained in:
parent
f35e0d8a55
commit
dec9eb9ae4
@ -15,6 +15,8 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
@ -207,4 +209,56 @@ DISCOVERY_SCHEMAS = [
|
||||
optional_attributes=(clusters.OnOff.Attributes.OnOff,),
|
||||
should_poll=True,
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.SENSOR,
|
||||
entity_description=MatterSensorEntityDescription(
|
||||
key="CarbonDioxideSensor",
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
entity_class=MatterSensor,
|
||||
required_attributes=(
|
||||
clusters.CarbonDioxideConcentrationMeasurement.Attributes.MeasuredValue,
|
||||
),
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.SENSOR,
|
||||
entity_description=MatterSensorEntityDescription(
|
||||
key="PM1Sensor",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
entity_class=MatterSensor,
|
||||
required_attributes=(
|
||||
clusters.Pm1ConcentrationMeasurement.Attributes.MeasuredValue,
|
||||
),
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.SENSOR,
|
||||
entity_description=MatterSensorEntityDescription(
|
||||
key="PM25Sensor",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
entity_class=MatterSensor,
|
||||
required_attributes=(
|
||||
clusters.Pm25ConcentrationMeasurement.Attributes.MeasuredValue,
|
||||
),
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.SENSOR,
|
||||
entity_description=MatterSensorEntityDescription(
|
||||
key="PM10Sensor",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
entity_class=MatterSensor,
|
||||
required_attributes=(
|
||||
clusters.Pm10ConcentrationMeasurement.Attributes.MeasuredValue,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
288
tests/components/matter/fixtures/nodes/air-quality-sensor.json
Normal file
288
tests/components/matter/fixtures/nodes/air-quality-sensor.json
Normal file
@ -0,0 +1,288 @@
|
||||
{
|
||||
"node_id": 1,
|
||||
"date_commissioned": "2024-01-13T20:12:42.853855",
|
||||
"last_interview": "2024-01-13T20:12:42.853862",
|
||||
"interview_version": 6,
|
||||
"available": true,
|
||||
"is_bridge": false,
|
||||
"attributes": {
|
||||
"0/29/0": [
|
||||
{
|
||||
"0": 22,
|
||||
"1": 1
|
||||
}
|
||||
],
|
||||
"0/29/1": [29, 31, 40, 42, 48, 49, 51, 60, 62, 63],
|
||||
"0/29/2": [41],
|
||||
"0/29/3": [1],
|
||||
"0/29/65532": 0,
|
||||
"0/29/65533": 2,
|
||||
"0/29/65528": [],
|
||||
"0/29/65529": [],
|
||||
"0/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/31/0": [
|
||||
{
|
||||
"254": 2
|
||||
},
|
||||
{
|
||||
"1": 5,
|
||||
"2": 2,
|
||||
"3": [112233],
|
||||
"4": null,
|
||||
"254": 3
|
||||
}
|
||||
],
|
||||
"0/31/1": [],
|
||||
"0/31/2": 4,
|
||||
"0/31/3": 3,
|
||||
"0/31/4": 4,
|
||||
"0/31/65532": 0,
|
||||
"0/31/65533": 1,
|
||||
"0/31/65528": [],
|
||||
"0/31/65529": [],
|
||||
"0/31/65531": [0, 1, 2, 3, 4, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/40/0": 17,
|
||||
"0/40/1": "Nordic Semiconductor ASA",
|
||||
"0/40/2": 65521,
|
||||
"0/40/3": "lightfi-aq1-air-quality-sensor",
|
||||
"0/40/4": 32768,
|
||||
"0/40/5": "",
|
||||
"0/40/6": "**REDACTED**",
|
||||
"0/40/7": 0,
|
||||
"0/40/8": "prerelease",
|
||||
"0/40/9": 0,
|
||||
"0/40/10": "prerelease",
|
||||
"0/40/19": {
|
||||
"caseSessionsPerFabric": 3,
|
||||
"subscriptionsPerFabric": 3
|
||||
},
|
||||
"0/40/21": null,
|
||||
"0/40/22": null,
|
||||
"0/40/65532": 0,
|
||||
"0/40/65533": 3,
|
||||
"0/40/65528": [],
|
||||
"0/40/65529": [],
|
||||
"0/40/65531": [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 19, 21, 22, 65528, 65529, 65531, 65532,
|
||||
65533
|
||||
],
|
||||
"0/42/0": [],
|
||||
"0/42/1": true,
|
||||
"0/42/2": 1,
|
||||
"0/42/3": null,
|
||||
"0/42/65532": 0,
|
||||
"0/42/65533": 1,
|
||||
"0/42/65528": [],
|
||||
"0/42/65529": [],
|
||||
"0/42/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/48/0": 0,
|
||||
"0/48/1": {
|
||||
"0": 60,
|
||||
"1": 900
|
||||
},
|
||||
"0/48/2": 0,
|
||||
"0/48/3": 0,
|
||||
"0/48/4": true,
|
||||
"0/48/65532": 0,
|
||||
"0/48/65533": 1,
|
||||
"0/48/65528": [1, 3, 5],
|
||||
"0/48/65529": [0, 2, 4],
|
||||
"0/48/65531": [0, 1, 2, 3, 4, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/49/0": 1,
|
||||
"0/49/1": [
|
||||
{
|
||||
"0": "q/UPJlJtKwk=",
|
||||
"1": true
|
||||
}
|
||||
],
|
||||
"0/49/4": true,
|
||||
"0/49/5": 0,
|
||||
"0/49/6": "q/UPJlJtKwk=",
|
||||
"0/49/7": null,
|
||||
"0/49/65532": 2,
|
||||
"0/49/65533": 1,
|
||||
"0/49/65528": [1, 5, 7],
|
||||
"0/49/65529": [0, 3, 4, 6, 8],
|
||||
"0/49/65531": [0, 1, 4, 5, 6, 7, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/51/0": [
|
||||
{
|
||||
"0": "ieee802154",
|
||||
"1": true,
|
||||
"2": null,
|
||||
"3": null,
|
||||
"4": "SrFuqi7GOA0=",
|
||||
"5": [],
|
||||
"6": [
|
||||
"/oAAAAAAAABIsW6qLsY4DQ==",
|
||||
"/a2BRTrZUShjZ6Plq5dszA==",
|
||||
"/R/knXM6xXGK6bPqGglOHw=="
|
||||
],
|
||||
"7": 4
|
||||
}
|
||||
],
|
||||
"0/51/1": 12,
|
||||
"0/51/8": false,
|
||||
"0/51/65532": 0,
|
||||
"0/51/65533": 1,
|
||||
"0/51/65528": [],
|
||||
"0/51/65529": [],
|
||||
"0/51/65531": [0, 1, 8, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/60/0": 0,
|
||||
"0/60/1": null,
|
||||
"0/60/2": null,
|
||||
"0/60/65532": 0,
|
||||
"0/60/65533": 1,
|
||||
"0/60/65528": [],
|
||||
"0/60/65529": [0, 2],
|
||||
"0/60/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/62/0": [
|
||||
{
|
||||
"254": 2
|
||||
},
|
||||
{
|
||||
"1": "FTABAQEkAgE3AyQTAhgmBIAigScmBYAlTTo3BiQVASQRARgkBwEkCAEwCUEEVW22H4oSAH8ygJxeAehOa+Fy5OvrpZP1+OsUuhMOHK8xRrUY021wlmdjeKyX3Fnax3+QU5eXXNyJl8B4KDS8wTcKNQEoARgkAgE2AwQCBAEYMAQUwvHAaN24tRt6l5HJQbyntNkVQZIwBRRje8c2OVfVDK5m9OcVHaS51jcEChgwC0A5oKtEonnnHfT+Ut+H359m/kiVNMmVkroDCeBWKItO6T28kladkvO0iHB8J1L7QFLEsDxv9YuCBOPa0T7fUHb6GA==",
|
||||
"2": "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQTAhgkBwEkCAEwCUEEa/1FpraZtnACK49eqDofsCGh7KwwBIKj28CVug2c1v7Nk+jy6Alq83vfKRc1MR6+9Lp31clVfzhOpCsX0vYiXjcKNQEpARgkAmAwBBRje8c2OVfVDK5m9OcVHaS51jcECjAFFBM9Maievp4UKHYUW3dZjm1BsGxwGDALQPa5FY9kZ/Ii83D0I4eCXwdSUEQWPIYeCyodb/eO1p0gtUzTbRxYmYFBTaE2bMVQHoZ7KFnC1uBvv6T/ELrxTD0Y",
|
||||
"254": 3
|
||||
}
|
||||
],
|
||||
"0/62/1": [
|
||||
{
|
||||
"1": "BBfkzpqcInPpJmIWMy2yckRYs4V/CHeqvr7ObEtvRywP9sQSuJ2vIIJer+Af5gA/5sld0ZRaOCdBksUK3b5g4/w=",
|
||||
"2": 24582,
|
||||
"3": 4448312386606703954,
|
||||
"4": 11636151610245023439,
|
||||
"5": "",
|
||||
"254": 2
|
||||
},
|
||||
{
|
||||
"1": "BJSwLCRLiMCNDkJINo2xgNg4Q4DQOnPH/UjP6AVITT6YFza4r9itL7nPg3TJo7quKWfdZ1aksO7doJZvFo5WyUU=",
|
||||
"2": 65521,
|
||||
"3": 1,
|
||||
"4": 1,
|
||||
"5": "",
|
||||
"254": 3
|
||||
}
|
||||
],
|
||||
"0/62/2": 5,
|
||||
"0/62/3": 2,
|
||||
"0/62/4": [
|
||||
"FTABAQEkAgE3AycU2fdVLSD8xXAYJgSAVCstJgWAWsNSNwYnFNn3VS0g/MVwGCQHASQIATAJQQQX5M6anCJz6SZiFjMtsnJEWLOFfwh3qr6+zmxLb0csD/bEEridryCCXq/gH+YAP+bJXdGUWjgnQZLFCt2+YOP8Nwo1ASkBGCQCYDAEFEMcdLs9Y7GImXEqgx7gT7WdJXEmMAUUQxx0uz1jsYiZcSqDHuBPtZ0lcSYYMAtA8OCKQmQJSw32MwkiKh2yCqXwqPo5ZFqC5KIju6EhVyic45AZqc8XooMha/G87qtjpG4X6zh4aEdwOJGgMVoewxg=",
|
||||
"FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEElLAsJEuIwI0OQkg2jbGA2DhDgNA6c8f9SM/oBUhNPpgXNriv2K0vuc+DdMmjuq4pZ91nVqSw7t2glm8WjlbJRTcKNQEpARgkAmAwBBQTPTGonr6eFCh2FFt3WY5tQbBscDAFFBM9Maievp4UKHYUW3dZjm1BsGxwGDALQEoomYkckgebSt7QekvI/9ZPf9y5pCFq7Vi+3bWwduTHa560n9hFZ01anVu4UxOsx1cn8erdu/dVdkHIBtfCKrcY"
|
||||
],
|
||||
"0/62/5": 3,
|
||||
"0/62/65532": 0,
|
||||
"0/62/65533": 1,
|
||||
"0/62/65528": [1, 3, 5, 8],
|
||||
"0/62/65529": [0, 2, 4, 6, 7, 9, 10, 11],
|
||||
"0/62/65531": [0, 1, 2, 3, 4, 5, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/63/0": [],
|
||||
"0/63/1": [],
|
||||
"0/63/2": 4,
|
||||
"0/63/3": 3,
|
||||
"0/63/65532": 0,
|
||||
"0/63/65533": 2,
|
||||
"0/63/65528": [2, 5],
|
||||
"0/63/65529": [0, 1, 3, 4],
|
||||
"0/63/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/3/0": 0,
|
||||
"1/3/1": 0,
|
||||
"1/3/65532": 0,
|
||||
"1/3/65533": 4,
|
||||
"1/3/65528": [],
|
||||
"1/3/65529": [0],
|
||||
"1/3/65531": [0, 1, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/29/0": [
|
||||
{
|
||||
"0": 44,
|
||||
"1": 1
|
||||
}
|
||||
],
|
||||
"1/29/1": [3, 29, 91, 1026, 1029, 1037, 1043, 1066, 1068, 1069, 1070],
|
||||
"1/29/2": [],
|
||||
"1/29/3": [],
|
||||
"1/29/65532": 0,
|
||||
"1/29/65533": 2,
|
||||
"1/29/65528": [],
|
||||
"1/29/65529": [],
|
||||
"1/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/91/0": null,
|
||||
"1/91/65532": null,
|
||||
"1/91/65533": 1,
|
||||
"1/91/65528": [],
|
||||
"1/91/65529": [],
|
||||
"1/91/65531": [0, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/1026/0": 2008,
|
||||
"1/1026/1": null,
|
||||
"1/1026/2": null,
|
||||
"1/1026/65532": 0,
|
||||
"1/1026/65533": 1,
|
||||
"1/1026/65528": [],
|
||||
"1/1026/65529": [],
|
||||
"1/1026/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/1029/0": 2875,
|
||||
"1/1029/1": 0,
|
||||
"1/1029/2": 0,
|
||||
"1/1029/65532": 0,
|
||||
"1/1029/65533": 3,
|
||||
"1/1029/65528": [],
|
||||
"1/1029/65529": [],
|
||||
"1/1029/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/1037/0": 678.0,
|
||||
"1/1037/1": 0.0,
|
||||
"1/1037/2": 5000.0,
|
||||
"1/1037/65532": 1,
|
||||
"1/1037/65533": 3,
|
||||
"1/1037/65528": [],
|
||||
"1/1037/65529": [],
|
||||
"1/1037/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/1043/0": 0.0,
|
||||
"1/1043/1": 0.0,
|
||||
"1/1043/2": 500.0,
|
||||
"1/1043/65532": 1,
|
||||
"1/1043/65533": 3,
|
||||
"1/1043/65528": [],
|
||||
"1/1043/65529": [],
|
||||
"1/1043/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/1066/0": 3.0,
|
||||
"1/1066/1": 0.0,
|
||||
"1/1066/2": 1000.0,
|
||||
"1/1066/65532": 1,
|
||||
"1/1066/65533": 3,
|
||||
"1/1066/65528": [],
|
||||
"1/1066/65529": [],
|
||||
"1/1066/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/1068/0": 3.0,
|
||||
"1/1068/1": 0.0,
|
||||
"1/1068/2": 1000.0,
|
||||
"1/1068/65532": 1,
|
||||
"1/1068/65533": 3,
|
||||
"1/1068/65528": [],
|
||||
"1/1068/65529": [],
|
||||
"1/1068/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/1069/0": 3.0,
|
||||
"1/1069/1": 0.0,
|
||||
"1/1069/2": 1000.0,
|
||||
"1/1069/65532": 1,
|
||||
"1/1069/65533": 3,
|
||||
"1/1069/65528": [],
|
||||
"1/1069/65529": [],
|
||||
"1/1069/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/1070/0": 189.0,
|
||||
"1/1070/1": 0.0,
|
||||
"1/1070/2": 500.0,
|
||||
"1/1070/65532": 1,
|
||||
"1/1070/65533": 3,
|
||||
"1/1070/65528": [],
|
||||
"1/1070/65529": [],
|
||||
"1/1070/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"attribute_subscriptions": [
|
||||
[1, 1037, 0],
|
||||
[1, 1070, 0],
|
||||
[1, 1066, 0],
|
||||
[1, 1068, 0],
|
||||
[1, 1069, 0],
|
||||
[1, 1026, 0],
|
||||
[1, 1029, 0]
|
||||
]
|
||||
}
|
@ -76,6 +76,16 @@ async def eve_energy_plug_node_fixture(
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="air_quality_sensor_node")
|
||||
async def air_quality_sensor_node_fixture(
|
||||
hass: HomeAssistant, matter_client: MagicMock
|
||||
) -> MatterNode:
|
||||
"""Fixture for an air quality sensor (LightFi AQ1) node."""
|
||||
return await setup_integration_with_node_fixture(
|
||||
hass, "air-quality-sensor", matter_client
|
||||
)
|
||||
|
||||
|
||||
# This tests needs to be adjusted to remove lingering tasks
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
async def test_sensor_null_value(
|
||||
@ -288,3 +298,60 @@ async def test_eve_energy_sensors(
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert state.state == "5.0"
|
||||
|
||||
|
||||
# This tests needs to be adjusted to remove lingering tasks
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
async def test_air_quality_sensor(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
air_quality_sensor_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test air quality sensor."""
|
||||
# Carbon Dioxide
|
||||
state = hass.states.get("sensor.lightfi_aq1_air_quality_sensor_carbon_dioxide")
|
||||
assert state
|
||||
assert state.state == "678.0"
|
||||
|
||||
set_node_attribute(air_quality_sensor_node, 1, 1037, 0, 789)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("sensor.lightfi_aq1_air_quality_sensor_carbon_dioxide")
|
||||
assert state
|
||||
assert state.state == "789.0"
|
||||
|
||||
# PM1
|
||||
state = hass.states.get("sensor.lightfi_aq1_air_quality_sensor_pm1")
|
||||
assert state
|
||||
assert state.state == "3.0"
|
||||
|
||||
set_node_attribute(air_quality_sensor_node, 1, 1068, 0, 50)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("sensor.lightfi_aq1_air_quality_sensor_pm1")
|
||||
assert state
|
||||
assert state.state == "50.0"
|
||||
|
||||
# PM2.5
|
||||
state = hass.states.get("sensor.lightfi_aq1_air_quality_sensor_pm2_5")
|
||||
assert state
|
||||
assert state.state == "3.0"
|
||||
|
||||
set_node_attribute(air_quality_sensor_node, 1, 1066, 0, 50)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("sensor.lightfi_aq1_air_quality_sensor_pm2_5")
|
||||
assert state
|
||||
assert state.state == "50.0"
|
||||
|
||||
# PM10
|
||||
state = hass.states.get("sensor.lightfi_aq1_air_quality_sensor_pm10")
|
||||
assert state
|
||||
assert state.state == "3.0"
|
||||
|
||||
set_node_attribute(air_quality_sensor_node, 1, 1069, 0, 50)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("sensor.lightfi_aq1_air_quality_sensor_pm10")
|
||||
assert state
|
||||
assert state.state == "50.0"
|
||||
|
Loading…
x
Reference in New Issue
Block a user