From ee23d79a0032456cab9633392b943e3023d4e6d8 Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Sat, 22 Apr 2023 15:19:21 +0000 Subject: [PATCH] Add air quality sensors to Accuweather integration (#91516) --- .../components/accuweather/sensor.py | 14 +++ .../components/accuweather/strings.json | 85 +++++++++++++++++ .../accuweather/fixtures/forecast_data.json | 95 ++++++++++--------- tests/components/accuweather/test_sensor.py | 29 +++++- 4 files changed, 173 insertions(+), 50 deletions(-) diff --git a/homeassistant/components/accuweather/sensor.py b/homeassistant/components/accuweather/sensor.py index 737150d4ee0..5d0c70de4e1 100644 --- a/homeassistant/components/accuweather/sensor.py +++ b/homeassistant/components/accuweather/sensor.py @@ -62,6 +62,15 @@ class AccuWeatherSensorDescription( FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = ( + AccuWeatherSensorDescription( + key="AirQuality", + icon="mdi:air-filter", + name="Air quality", + value_fn=lambda data: cast(str, data[ATTR_CATEGORY]), + device_class=SensorDeviceClass.ENUM, + options=["good", "hazardous", "high", "low", "moderate", "unhealthy"], + translation_key="air_quality", + ), AccuWeatherSensorDescription( key="CloudCoverDay", icon="mdi:weather-cloudy", @@ -86,6 +95,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = ( native_unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER, value_fn=lambda data: cast(int, data[ATTR_VALUE]), attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]}, + translation_key="grass_pollen", ), AccuWeatherSensorDescription( key="HoursOfSun", @@ -102,6 +112,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = ( native_unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER, value_fn=lambda data: cast(int, data[ATTR_VALUE]), attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]}, + translation_key="mold_pollen", ), AccuWeatherSensorDescription( key="Ragweed", @@ -111,6 +122,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = ( entity_registry_enabled_default=False, value_fn=lambda data: cast(int, data[ATTR_VALUE]), attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]}, + translation_key="ragweed_pollen", ), AccuWeatherSensorDescription( key="RealFeelTemperatureMax", @@ -164,6 +176,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = ( entity_registry_enabled_default=False, value_fn=lambda data: cast(int, data[ATTR_VALUE]), attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]}, + translation_key="tree_pollen", ), AccuWeatherSensorDescription( key="UVIndex", @@ -172,6 +185,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = ( native_unit_of_measurement=UV_INDEX, value_fn=lambda data: cast(int, data[ATTR_VALUE]), attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]}, + translation_key="uv_index", ), AccuWeatherSensorDescription( key="WindGustDay", diff --git a/homeassistant/components/accuweather/strings.json b/homeassistant/components/accuweather/strings.json index d37b5a10776..e9c4ace9b99 100644 --- a/homeassistant/components/accuweather/strings.json +++ b/homeassistant/components/accuweather/strings.json @@ -30,6 +30,91 @@ "rising": "Rising", "falling": "Falling" } + }, + "air_quality": { + "state": { + "good": "Good", + "hazardous": "Hazardous", + "high": "High", + "low": "Low", + "moderate": "Moderate", + "unhealthy": "Unhealthy" + } + }, + "grass_pollen": { + "state_attributes": { + "level": { + "name": "Level", + "state": { + "good": "[%key:component::accuweather::entity::sensor::air_quality::state::good%]", + "hazardous": "[%key:component::accuweather::entity::sensor::air_quality::state::hazardous%]", + "high": "[%key:component::accuweather::entity::sensor::air_quality::state::high%]", + "low": "[%key:component::accuweather::entity::sensor::air_quality::state::low%]", + "moderate": "[%key:component::accuweather::entity::sensor::air_quality::state::moderate%]", + "unhealthy": "[%key:component::accuweather::entity::sensor::air_quality::state::unhealthy%]" + } + } + } + }, + "mold_pollen": { + "state_attributes": { + "level": { + "name": "Level", + "state": { + "good": "[%key:component::accuweather::entity::sensor::air_quality::state::good%]", + "hazardous": "[%key:component::accuweather::entity::sensor::air_quality::state::hazardous%]", + "high": "[%key:component::accuweather::entity::sensor::air_quality::state::high%]", + "low": "[%key:component::accuweather::entity::sensor::air_quality::state::low%]", + "moderate": "[%key:component::accuweather::entity::sensor::air_quality::state::moderate%]", + "unhealthy": "[%key:component::accuweather::entity::sensor::air_quality::state::unhealthy%]" + } + } + } + }, + "ragweed_pollen": { + "state_attributes": { + "level": { + "name": "Level", + "state": { + "good": "[%key:component::accuweather::entity::sensor::air_quality::state::good%]", + "hazardous": "[%key:component::accuweather::entity::sensor::air_quality::state::hazardous%]", + "high": "[%key:component::accuweather::entity::sensor::air_quality::state::high%]", + "low": "[%key:component::accuweather::entity::sensor::air_quality::state::low%]", + "moderate": "[%key:component::accuweather::entity::sensor::air_quality::state::moderate%]", + "unhealthy": "[%key:component::accuweather::entity::sensor::air_quality::state::unhealthy%]" + } + } + } + }, + "tree_pollen": { + "state_attributes": { + "level": { + "name": "Level", + "state": { + "good": "[%key:component::accuweather::entity::sensor::air_quality::state::good%]", + "hazardous": "[%key:component::accuweather::entity::sensor::air_quality::state::hazardous%]", + "high": "[%key:component::accuweather::entity::sensor::air_quality::state::high%]", + "low": "[%key:component::accuweather::entity::sensor::air_quality::state::low%]", + "moderate": "[%key:component::accuweather::entity::sensor::air_quality::state::moderate%]", + "unhealthy": "[%key:component::accuweather::entity::sensor::air_quality::state::unhealthy%]" + } + } + } + }, + "uv_index": { + "state_attributes": { + "level": { + "name": "Level", + "state": { + "good": "[%key:component::accuweather::entity::sensor::air_quality::state::good%]", + "hazardous": "[%key:component::accuweather::entity::sensor::air_quality::state::hazardous%]", + "high": "[%key:component::accuweather::entity::sensor::air_quality::state::high%]", + "low": "[%key:component::accuweather::entity::sensor::air_quality::state::low%]", + "moderate": "[%key:component::accuweather::entity::sensor::air_quality::state::moderate%]", + "unhealthy": "[%key:component::accuweather::entity::sensor::air_quality::state::unhealthy%]" + } + } + } } } }, diff --git a/tests/components/accuweather/fixtures/forecast_data.json b/tests/components/accuweather/fixtures/forecast_data.json index 70b7bd1181b..1b432fbd075 100644 --- a/tests/components/accuweather/fixtures/forecast_data.json +++ b/tests/components/accuweather/fixtures/forecast_data.json @@ -15,34 +15,35 @@ "UnitType": 17 } }, - "Ozone": { - "Value": 32, - "Category": "Good", - "CategoryValue": 1 + "AirQuality": { + "Value": 0, + "Category": "good", + "CategoryValue": 1, + "Type": "Ozone" }, "Grass": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Mold": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Ragweed": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Tree": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "UVIndex": { "Value": 5, - "Category": "Moderate", + "Category": "moderate", "CategoryValue": 2 }, "TemperatureMin": { @@ -214,34 +215,35 @@ "UnitType": 17 } }, - "Ozone": { - "Value": 39, - "Category": "Good", - "CategoryValue": 1 + "AirQuality": { + "Value": 0, + "Category": "good", + "CategoryValue": 1, + "Type": "Ozone" }, "Grass": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Mold": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Ragweed": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Tree": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "UVIndex": { "Value": 7, - "Category": "High", + "Category": "high", "CategoryValue": 3 }, "TemperatureMin": { @@ -409,34 +411,35 @@ "UnitType": 17 } }, - "Ozone": { - "Value": 29, - "Category": "Good", - "CategoryValue": 1 + "AirQuality": { + "Value": 0, + "Category": "good", + "CategoryValue": 1, + "Type": "Ozone" }, "Grass": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Mold": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Ragweed": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Tree": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "UVIndex": { "Value": 7, - "Category": "High", + "Category": "high", "CategoryValue": 3 }, "TemperatureMin": { @@ -604,34 +607,35 @@ "UnitType": 17 } }, - "Ozone": { - "Value": 18, - "Category": "Good", - "CategoryValue": 1 + "AirQuality": { + "Value": 0, + "Category": "good", + "CategoryValue": 1, + "Type": "Ozone" }, "Grass": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Mold": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Ragweed": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Tree": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "UVIndex": { "Value": 6, - "Category": "High", + "Category": "high", "CategoryValue": 3 }, "TemperatureMin": { @@ -799,34 +803,35 @@ "UnitType": 17 } }, - "Ozone": { - "Value": 14, - "Category": "Good", - "CategoryValue": 1 + "AirQuality": { + "Value": 0, + "Category": "good", + "CategoryValue": 1, + "Type": "Ozone" }, "Grass": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Mold": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Ragweed": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "Tree": { "Value": 0, - "Category": "Low", + "Category": "low", "CategoryValue": 1 }, "UVIndex": { "Value": 7, - "Category": "High", + "Category": "high", "CategoryValue": 3 }, "TemperatureMin": { diff --git a/tests/components/accuweather/test_sensor.py b/tests/components/accuweather/test_sensor.py index 323b3ae495d..37e58504efe 100644 --- a/tests/components/accuweather/test_sensor.py +++ b/tests/components/accuweather/test_sensor.py @@ -189,13 +189,32 @@ async def test_sensor_with_forecast(hass: HomeAssistant) -> None: assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_ICON) == "mdi:weather-sunny" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UV_INDEX - assert state.attributes.get("level") == "Moderate" + assert state.attributes.get("level") == "moderate" assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_uv_index_0d") assert entry assert entry.unique_id == "0123456-uvindex-0" + state = hass.states.get("sensor.home_air_quality_0d") + assert state + assert state.state == "good" + assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION + assert state.attributes.get(ATTR_ICON) == "mdi:air-filter" + assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.ENUM + assert state.attributes.get(ATTR_OPTIONS) == [ + "good", + "hazardous", + "high", + "low", + "moderate", + "unhealthy", + ] + + entry = registry.async_get("sensor.home_air_quality_0d") + assert entry + assert entry.unique_id == "0123456-airquality-0" + async def test_sensor_disabled(hass: HomeAssistant) -> None: """Test sensor disabled by default.""" @@ -499,7 +518,7 @@ async def test_sensor_enabled_without_forecast(hass: HomeAssistant) -> None: state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == CONCENTRATION_PARTS_PER_CUBIC_METER ) - assert state.attributes.get("level") == "Low" + assert state.attributes.get("level") == "low" assert state.attributes.get(ATTR_ICON) == "mdi:grass" assert state.attributes.get(ATTR_STATE_CLASS) is None @@ -515,7 +534,7 @@ async def test_sensor_enabled_without_forecast(hass: HomeAssistant) -> None: state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == CONCENTRATION_PARTS_PER_CUBIC_METER ) - assert state.attributes.get("level") == "Low" + assert state.attributes.get("level") == "low" assert state.attributes.get(ATTR_ICON) == "mdi:blur" entry = registry.async_get("sensor.home_mold_pollen_0d") @@ -530,7 +549,7 @@ async def test_sensor_enabled_without_forecast(hass: HomeAssistant) -> None: state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == CONCENTRATION_PARTS_PER_CUBIC_METER ) - assert state.attributes.get("level") == "Low" + assert state.attributes.get("level") == "low" assert state.attributes.get(ATTR_ICON) == "mdi:sprout" entry = registry.async_get("sensor.home_ragweed_pollen_0d") @@ -568,7 +587,7 @@ async def test_sensor_enabled_without_forecast(hass: HomeAssistant) -> None: state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == CONCENTRATION_PARTS_PER_CUBIC_METER ) - assert state.attributes.get("level") == "Low" + assert state.attributes.get("level") == "low" assert state.attributes.get(ATTR_ICON) == "mdi:tree-outline" assert state.attributes.get(ATTR_STATE_CLASS) is None