From 1a14a93df67cc926fa07ba1719cb98f356f99a1d Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 23 Apr 2023 16:12:52 +0200 Subject: [PATCH] HA deconz: Add support for Tuya Smart Air Housekeeper 6in1 Air Quality Monitor (#87866) * fix check for airquality sensor (was always TRUE) * import additional const required * add support for formaldehyd sensor * add support for co2 sensor * add support for pm25 sensor * sort const a-z * adapt to typo fixed function * adapt to new key names (formaldehyde) * adapt co2 sensor to new key names * Update homeassistant/components/deconz/sensor.py remove unnecessary code Co-authored-by: Robert Svensson * add device_class for air_quality_ppb * add test_air_quality_sensor_6_in_1 * fix Air quality PPB test to match device_class * remove device_class of air_quality_ppb * remove device_class test of airqualityppb * explicit units * remove device_class test of airquality_1_ppb * dependency bump pydeconz to 111 * Update homeassistant/components/deconz/sensor.py remove unnecessary device_class Co-authored-by: Robert Svensson * import formatting * formatting * Update homeassistant/components/deconz/sensor.py change key for pm2_5 Co-authored-by: Robert Svensson * add airquality co2 ch2o pm25 sensor testdata * remove test_air_quality_sensor_6_in_1 * formatting * bump pydeconz for requirements --------- Co-authored-by: Robert Svensson --- homeassistant/components/deconz/manifest.json | 2 +- homeassistant/components/deconz/sensor.py | 37 ++++- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/deconz/test_sensor.py | 131 +++++++++++++++++- 5 files changed, 168 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/deconz/manifest.json b/homeassistant/components/deconz/manifest.json index 5569f9d5e8a..61794e7c70a 100644 --- a/homeassistant/components/deconz/manifest.json +++ b/homeassistant/components/deconz/manifest.json @@ -8,7 +8,7 @@ "iot_class": "local_push", "loggers": ["pydeconz"], "quality_scale": "platinum", - "requirements": ["pydeconz==110"], + "requirements": ["pydeconz==111"], "ssdp": [ { "manufacturer": "Royal Philips Electronics", diff --git a/homeassistant/components/deconz/sensor.py b/homeassistant/components/deconz/sensor.py index e9088532754..136f582f5c7 100644 --- a/homeassistant/components/deconz/sensor.py +++ b/homeassistant/components/deconz/sensor.py @@ -33,7 +33,9 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_TEMPERATURE, ATTR_VOLTAGE, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_PARTS_PER_MILLION, LIGHT_LUX, PERCENTAGE, EntityCategory, @@ -108,7 +110,7 @@ class DeconzSensorDescription(SensorEntityDescription, DeconzSensorDescriptionMi ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = ( DeconzSensorDescription[AirQuality]( key="air_quality", - supported_fn=lambda device: device.air_quality is not None, + supported_fn=lambda device: device.supports_air_quality, update_key="airquality", value_fn=lambda device: device.air_quality, instance_check=AirQuality, @@ -124,6 +126,39 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = ( state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION, ), + DeconzSensorDescription[AirQuality]( + key="air_quality_formaldehyde", + supported_fn=lambda device: device.air_quality_formaldehyde is not None, + update_key="airquality_formaldehyde_density", + value_fn=lambda device: device.air_quality_formaldehyde, + instance_check=AirQuality, + name_suffix="CH2O", + device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS, + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + DeconzSensorDescription[AirQuality]( + key="air_quality_co2", + supported_fn=lambda device: device.air_quality_co2 is not None, + update_key="airquality_co2_density", + value_fn=lambda device: device.air_quality_co2, + instance_check=AirQuality, + name_suffix="CO2", + device_class=SensorDeviceClass.CO2, + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, + ), + DeconzSensorDescription[AirQuality]( + key="air_quality_pm2_5", + supported_fn=lambda device: device.pm_2_5 is not None, + update_key="pm2_5", + value_fn=lambda device: device.pm_2_5, + instance_check=AirQuality, + name_suffix="PM25", + device_class=SensorDeviceClass.PM25, + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), DeconzSensorDescription[Consumption]( key="consumption", supported_fn=lambda device: device.consumption is not None, diff --git a/requirements_all.txt b/requirements_all.txt index 8590192a1e9..a90f8cd61b7 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1575,7 +1575,7 @@ pydaikin==2.9.0 pydanfossair==0.1.0 # homeassistant.components.deconz -pydeconz==110 +pydeconz==111 # homeassistant.components.delijn pydelijn==1.0.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 00868ce0680..fde81c5305b 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1148,7 +1148,7 @@ pycoolmasternet-async==0.1.5 pydaikin==2.9.0 # homeassistant.components.deconz -pydeconz==110 +pydeconz==111 # homeassistant.components.dexcom pydexcom==0.2.3 diff --git a/tests/components/deconz/test_sensor.py b/tests/components/deconz/test_sensor.py index ecbf7394efd..eb27d9f68d4 100644 --- a/tests/components/deconz/test_sensor.py +++ b/tests/components/deconz/test_sensor.py @@ -14,7 +14,14 @@ from homeassistant.components.sensor import ( SensorStateClass, ) from homeassistant.config_entries import RELOAD_AFTER_UPDATE_DELAY -from homeassistant.const import ATTR_DEVICE_CLASS, STATE_UNAVAILABLE, EntityCategory +from homeassistant.const import ( + ATTR_DEVICE_CLASS, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_PARTS_PER_MILLION, + STATE_UNAVAILABLE, + EntityCategory, +) from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.util import dt @@ -106,12 +113,132 @@ TEST_DATA = [ "attributes": { "friendly_name": "BOSCH Air quality sensor PPB", "state_class": "measurement", - "unit_of_measurement": "ppb", + "unit_of_measurement": CONCENTRATION_PARTS_PER_BILLION, }, "websocket_event": {"state": {"airqualityppb": 1000}}, "next_state": "1000", }, ), + ( # Air quality 6 in 1 (without airquality) -> airquality_co2_density + { + "config": { + "on": True, + "reachable": True, + }, + "etag": "e1a406dbbe1438fa924007309ef46a01", + "lastseen": "2023-03-29T18:25Z", + "manufacturername": "_TZE200_dwcarsat", + "modelid": "TS0601", + "name": "AirQuality 1", + "state": { + "airquality_co2_density": 359, + "airquality_formaldehyde_density": 4, + "airqualityppb": 15, + "lastupdated": "2023-03-29T19:05:41.903", + "pm2_5": 8, + }, + "type": "ZHAAirQuality", + "uniqueid": "00:00:00:00:00:00:00:01-02-0113", + }, + { + "entity_count": 4, + "device_count": 3, + "entity_id": "sensor.airquality_1_co2", + "unique_id": "00:00:00:00:00:00:00:01-02-0113-air_quality_co2", + "state": "359", + "entity_category": None, + "device_class": SensorDeviceClass.CO2, + "state_class": SensorStateClass.MEASUREMENT, + "attributes": { + "friendly_name": "AirQuality 1 CO2", + "device_class": SensorDeviceClass.CO2, + "state_class": SensorStateClass.MEASUREMENT, + "unit_of_measurement": CONCENTRATION_PARTS_PER_MILLION, + }, + "websocket_event": {"state": {"airquality_co2_density": 332}}, + "next_state": "332", + }, + ), + ( # Air quality 6 in 1 (without airquality) -> airquality_formaldehyde_density + { + "config": { + "on": True, + "reachable": True, + }, + "etag": "e1a406dbbe1438fa924007309ef46a01", + "lastseen": "2023-03-29T18:25Z", + "manufacturername": "_TZE200_dwcarsat", + "modelid": "TS0601", + "name": "AirQuality 1", + "state": { + "airquality_co2_density": 359, + "airquality_formaldehyde_density": 4, + "airqualityppb": 15, + "lastupdated": "2023-03-29T19:05:41.903", + "pm2_5": 8, + }, + "type": "ZHAAirQuality", + "uniqueid": "00:00:00:00:00:00:00:01-02-0113", + }, + { + "entity_count": 4, + "device_count": 3, + "entity_id": "sensor.airquality_1_ch2o", + "unique_id": "00:00:00:00:00:00:00:01-02-0113-air_quality_formaldehyde", + "state": "4", + "entity_category": None, + "device_class": SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS, + "state_class": SensorStateClass.MEASUREMENT, + "attributes": { + "friendly_name": "AirQuality 1 CH2O", + "device_class": SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS, + "state_class": SensorStateClass.MEASUREMENT, + "unit_of_measurement": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + }, + "websocket_event": {"state": {"airquality_formaldehyde_density": 5}}, + "next_state": "5", + }, + ), + ( # Air quality 6 in 1 (without airquality) -> pm2_5 + { + "config": { + "on": True, + "reachable": True, + }, + "etag": "e1a406dbbe1438fa924007309ef46a01", + "lastseen": "2023-03-29T18:25Z", + "manufacturername": "_TZE200_dwcarsat", + "modelid": "TS0601", + "name": "AirQuality 1", + "state": { + "airquality_co2_density": 359, + "airquality_formaldehyde_density": 4, + "airqualityppb": 15, + "lastupdated": "2023-03-29T19:05:41.903", + "pm2_5": 8, + }, + "type": "ZHAAirQuality", + "uniqueid": "00:00:00:00:00:00:00:01-02-0113", + }, + { + "entity_count": 4, + "device_count": 3, + "entity_id": "sensor.airquality_1_pm25", + "unique_id": "00:00:00:00:00:00:00:01-02-0113-air_quality_pm2_5", + "state": "8", + "entity_category": None, + "device_class": SensorDeviceClass.PM25, + "state_class": SensorStateClass.MEASUREMENT, + "attributes": { + "friendly_name": "AirQuality 1 PM25", + "device_class": SensorDeviceClass.PM25, + "state_class": SensorStateClass.MEASUREMENT, + "unit_of_measurement": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + }, + "websocket_event": {"state": {"pm2_5": 11}}, + "next_state": "11", + }, + ), ( # Battery sensor { "config": {