mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Switch to dataclass from dictionary for climacell sensor definitions (#53168)
* Switch to dataclass from dictionary for climacell sensor definitions * fix post_init * fix dataclass and add test * Update homeassistant/components/climacell/sensor.py Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> * Update homeassistant/components/climacell/const.py Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> * simplify logic * use tuple * simplify unit of measurement and use class attributes * Switch from UnitT to str Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
This commit is contained in:
parent
7711ac901c
commit
562aa74c77
@ -35,7 +35,6 @@ from homeassistant.helpers.update_coordinator import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_FIELD,
|
|
||||||
ATTRIBUTION,
|
ATTRIBUTION,
|
||||||
CC_ATTR_CLOUD_COVER,
|
CC_ATTR_CLOUD_COVER,
|
||||||
CC_ATTR_CONDITION,
|
CC_ATTR_CONDITION,
|
||||||
@ -223,10 +222,7 @@ class ClimaCellDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
CC_V3_ATTR_WIND_GUST,
|
CC_V3_ATTR_WIND_GUST,
|
||||||
CC_V3_ATTR_CLOUD_COVER,
|
CC_V3_ATTR_CLOUD_COVER,
|
||||||
CC_V3_ATTR_PRECIPITATION_TYPE,
|
CC_V3_ATTR_PRECIPITATION_TYPE,
|
||||||
*(
|
*(sensor_type.field for sensor_type in CC_V3_SENSOR_TYPES),
|
||||||
sensor_type[ATTR_FIELD]
|
|
||||||
for sensor_type in CC_V3_SENSOR_TYPES
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
data[FORECASTS][HOURLY] = await self._api.forecast_hourly(
|
data[FORECASTS][HOURLY] = await self._api.forecast_hourly(
|
||||||
@ -283,7 +279,7 @@ class ClimaCellDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
CC_ATTR_WIND_GUST,
|
CC_ATTR_WIND_GUST,
|
||||||
CC_ATTR_CLOUD_COVER,
|
CC_ATTR_CLOUD_COVER,
|
||||||
CC_ATTR_PRECIPITATION_TYPE,
|
CC_ATTR_PRECIPITATION_TYPE,
|
||||||
*(sensor_type[ATTR_FIELD] for sensor_type in CC_SENSOR_TYPES),
|
*(sensor_type.field for sensor_type in CC_SENSOR_TYPES),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
CC_ATTR_TEMPERATURE_LOW,
|
CC_ATTR_TEMPERATURE_LOW,
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
"""Constants for the ClimaCell integration."""
|
"""Constants for the ClimaCell integration."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import IntEnum
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
from pyclimacell.const import (
|
from pyclimacell.const import (
|
||||||
DAILY,
|
DAILY,
|
||||||
HOURLY,
|
HOURLY,
|
||||||
@ -26,15 +32,10 @@ from homeassistant.components.weather import (
|
|||||||
ATTR_CONDITION_WINDY,
|
ATTR_CONDITION_WINDY,
|
||||||
)
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_DEVICE_CLASS,
|
|
||||||
ATTR_NAME,
|
|
||||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT,
|
CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT,
|
||||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||||
CONCENTRATION_PARTS_PER_BILLION,
|
CONCENTRATION_PARTS_PER_BILLION,
|
||||||
CONCENTRATION_PARTS_PER_MILLION,
|
CONCENTRATION_PARTS_PER_MILLION,
|
||||||
CONF_UNIT_OF_MEASUREMENT,
|
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL,
|
|
||||||
CONF_UNIT_SYSTEM_METRIC,
|
|
||||||
DEVICE_CLASS_CO,
|
DEVICE_CLASS_CO,
|
||||||
DEVICE_CLASS_PRESSURE,
|
DEVICE_CLASS_PRESSURE,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
@ -74,13 +75,6 @@ MAX_FORECASTS = {
|
|||||||
NOWCAST: 30,
|
NOWCAST: 30,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Sensor type keys
|
|
||||||
ATTR_FIELD = "field"
|
|
||||||
ATTR_METRIC_CONVERSION = "metric_conversion"
|
|
||||||
ATTR_VALUE_MAP = "value_map"
|
|
||||||
ATTR_IS_METRIC_CHECK = "is_metric_check"
|
|
||||||
ATTR_SCALE = "scale"
|
|
||||||
|
|
||||||
# Additional attributes
|
# Additional attributes
|
||||||
ATTR_WIND_GUST = "wind_gust"
|
ATTR_WIND_GUST = "wind_gust"
|
||||||
ATTR_CLOUD_COVER = "cloud_cover"
|
ATTR_CLOUD_COVER = "cloud_cover"
|
||||||
@ -155,165 +149,182 @@ CC_ATTR_SOLAR_GHI = "solarGHI"
|
|||||||
CC_ATTR_CLOUD_BASE = "cloudBase"
|
CC_ATTR_CLOUD_BASE = "cloudBase"
|
||||||
CC_ATTR_CLOUD_CEILING = "cloudCeiling"
|
CC_ATTR_CLOUD_CEILING = "cloudCeiling"
|
||||||
|
|
||||||
CC_SENSOR_TYPES = [
|
|
||||||
{
|
@dataclass
|
||||||
ATTR_FIELD: CC_ATTR_FEELS_LIKE,
|
class ClimaCellSensorMetadata:
|
||||||
ATTR_NAME: "Feels Like",
|
"""Metadata about an individual ClimaCell sensor."""
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL: TEMP_FAHRENHEIT,
|
|
||||||
CONF_UNIT_SYSTEM_METRIC: TEMP_CELSIUS,
|
field: str
|
||||||
ATTR_METRIC_CONVERSION: lambda val: temp_convert(
|
name: str
|
||||||
val, TEMP_FAHRENHEIT, TEMP_CELSIUS
|
unit_imperial: str | None = None
|
||||||
),
|
unit_metric: str | None = None
|
||||||
ATTR_IS_METRIC_CHECK: True,
|
metric_conversion: Callable | float = 1.0
|
||||||
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
|
is_metric_check: bool | None = None
|
||||||
},
|
device_class: str | None = None
|
||||||
{
|
value_map: IntEnum | None = None
|
||||||
ATTR_FIELD: CC_ATTR_DEW_POINT,
|
|
||||||
ATTR_NAME: "Dew Point",
|
def __post_init__(self) -> None:
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL: TEMP_FAHRENHEIT,
|
"""Post initialization."""
|
||||||
CONF_UNIT_SYSTEM_METRIC: TEMP_CELSIUS,
|
units = (self.unit_imperial, self.unit_metric)
|
||||||
ATTR_METRIC_CONVERSION: lambda val: temp_convert(
|
if any(u is not None for u in units) and any(u is None for u in units):
|
||||||
val, TEMP_FAHRENHEIT, TEMP_CELSIUS
|
raise RuntimeError(
|
||||||
),
|
"`unit_imperial` and `unit_metric` both need to be None or both need "
|
||||||
ATTR_IS_METRIC_CHECK: True,
|
"to be defined."
|
||||||
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
|
)
|
||||||
},
|
|
||||||
{
|
|
||||||
ATTR_FIELD: CC_ATTR_PRESSURE_SURFACE_LEVEL,
|
CC_SENSOR_TYPES = (
|
||||||
ATTR_NAME: "Pressure (Surface Level)",
|
ClimaCellSensorMetadata(
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL: PRESSURE_INHG,
|
CC_ATTR_FEELS_LIKE,
|
||||||
CONF_UNIT_SYSTEM_METRIC: PRESSURE_HPA,
|
"Feels Like",
|
||||||
ATTR_METRIC_CONVERSION: lambda val: pressure_convert(
|
unit_imperial=TEMP_FAHRENHEIT,
|
||||||
|
unit_metric=TEMP_CELSIUS,
|
||||||
|
metric_conversion=lambda val: temp_convert(val, TEMP_FAHRENHEIT, TEMP_CELSIUS),
|
||||||
|
is_metric_check=True,
|
||||||
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
|
),
|
||||||
|
ClimaCellSensorMetadata(
|
||||||
|
CC_ATTR_DEW_POINT,
|
||||||
|
"Dew Point",
|
||||||
|
unit_imperial=TEMP_FAHRENHEIT,
|
||||||
|
unit_metric=TEMP_CELSIUS,
|
||||||
|
metric_conversion=lambda val: temp_convert(val, TEMP_FAHRENHEIT, TEMP_CELSIUS),
|
||||||
|
is_metric_check=True,
|
||||||
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
|
),
|
||||||
|
ClimaCellSensorMetadata(
|
||||||
|
CC_ATTR_PRESSURE_SURFACE_LEVEL,
|
||||||
|
"Pressure (Surface Level)",
|
||||||
|
unit_imperial=PRESSURE_INHG,
|
||||||
|
unit_metric=PRESSURE_HPA,
|
||||||
|
metric_conversion=lambda val: pressure_convert(
|
||||||
val, PRESSURE_INHG, PRESSURE_HPA
|
val, PRESSURE_INHG, PRESSURE_HPA
|
||||||
),
|
),
|
||||||
ATTR_IS_METRIC_CHECK: True,
|
is_metric_check=True,
|
||||||
ATTR_DEVICE_CLASS: DEVICE_CLASS_PRESSURE,
|
device_class=DEVICE_CLASS_PRESSURE,
|
||||||
},
|
),
|
||||||
{
|
ClimaCellSensorMetadata(
|
||||||
ATTR_FIELD: CC_ATTR_SOLAR_GHI,
|
CC_ATTR_SOLAR_GHI,
|
||||||
ATTR_NAME: "Global Horizontal Irradiance",
|
"Global Horizontal Irradiance",
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL: IRRADIATION_BTUS_PER_HOUR_SQUARE_FOOT,
|
unit_imperial=IRRADIATION_BTUS_PER_HOUR_SQUARE_FOOT,
|
||||||
CONF_UNIT_SYSTEM_METRIC: IRRADIATION_WATTS_PER_SQUARE_METER,
|
unit_metric=IRRADIATION_WATTS_PER_SQUARE_METER,
|
||||||
ATTR_METRIC_CONVERSION: 3.15459,
|
metric_conversion=3.15459,
|
||||||
ATTR_IS_METRIC_CHECK: True,
|
is_metric_check=True,
|
||||||
},
|
),
|
||||||
{
|
ClimaCellSensorMetadata(
|
||||||
ATTR_FIELD: CC_ATTR_CLOUD_BASE,
|
CC_ATTR_CLOUD_BASE,
|
||||||
ATTR_NAME: "Cloud Base",
|
"Cloud Base",
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL: LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
CONF_UNIT_SYSTEM_METRIC: LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
ATTR_METRIC_CONVERSION: lambda val: distance_convert(
|
metric_conversion=lambda val: distance_convert(
|
||||||
val, LENGTH_MILES, LENGTH_KILOMETERS
|
val, LENGTH_MILES, LENGTH_KILOMETERS
|
||||||
),
|
),
|
||||||
ATTR_IS_METRIC_CHECK: True,
|
is_metric_check=True,
|
||||||
},
|
),
|
||||||
{
|
ClimaCellSensorMetadata(
|
||||||
ATTR_FIELD: CC_ATTR_CLOUD_CEILING,
|
CC_ATTR_CLOUD_CEILING,
|
||||||
ATTR_NAME: "Cloud Ceiling",
|
"Cloud Ceiling",
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL: LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
CONF_UNIT_SYSTEM_METRIC: LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
ATTR_METRIC_CONVERSION: lambda val: distance_convert(
|
metric_conversion=lambda val: distance_convert(
|
||||||
val, LENGTH_MILES, LENGTH_KILOMETERS
|
val, LENGTH_MILES, LENGTH_KILOMETERS
|
||||||
),
|
),
|
||||||
ATTR_IS_METRIC_CHECK: True,
|
is_metric_check=True,
|
||||||
},
|
),
|
||||||
{
|
ClimaCellSensorMetadata(
|
||||||
ATTR_FIELD: CC_ATTR_CLOUD_COVER,
|
CC_ATTR_CLOUD_COVER,
|
||||||
ATTR_NAME: "Cloud Cover",
|
"Cloud Cover",
|
||||||
CONF_UNIT_OF_MEASUREMENT: PERCENTAGE,
|
unit_imperial=PERCENTAGE,
|
||||||
},
|
unit_metric=PERCENTAGE,
|
||||||
{
|
),
|
||||||
ATTR_FIELD: CC_ATTR_WIND_GUST,
|
ClimaCellSensorMetadata(
|
||||||
ATTR_NAME: "Wind Gust",
|
CC_ATTR_WIND_GUST,
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL: SPEED_MILES_PER_HOUR,
|
"Wind Gust",
|
||||||
CONF_UNIT_SYSTEM_METRIC: SPEED_METERS_PER_SECOND,
|
unit_imperial=SPEED_MILES_PER_HOUR,
|
||||||
ATTR_METRIC_CONVERSION: lambda val: distance_convert(
|
unit_metric=SPEED_METERS_PER_SECOND,
|
||||||
val, LENGTH_MILES, LENGTH_METERS
|
metric_conversion=lambda val: distance_convert(val, LENGTH_MILES, LENGTH_METERS)
|
||||||
)
|
|
||||||
/ 3600,
|
/ 3600,
|
||||||
ATTR_IS_METRIC_CHECK: True,
|
is_metric_check=True,
|
||||||
},
|
),
|
||||||
{
|
ClimaCellSensorMetadata(
|
||||||
ATTR_FIELD: CC_ATTR_PRECIPITATION_TYPE,
|
CC_ATTR_PRECIPITATION_TYPE,
|
||||||
ATTR_NAME: "Precipitation Type",
|
"Precipitation Type",
|
||||||
ATTR_VALUE_MAP: PrecipitationType,
|
value_map=PrecipitationType,
|
||||||
},
|
),
|
||||||
{
|
ClimaCellSensorMetadata(
|
||||||
ATTR_FIELD: CC_ATTR_OZONE,
|
CC_ATTR_OZONE,
|
||||||
ATTR_NAME: "Ozone",
|
"Ozone",
|
||||||
CONF_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_BILLION,
|
unit_imperial=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
},
|
unit_metric=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
{
|
),
|
||||||
ATTR_FIELD: CC_ATTR_PARTICULATE_MATTER_25,
|
ClimaCellSensorMetadata(
|
||||||
ATTR_NAME: "Particulate Matter < 2.5 μm",
|
CC_ATTR_PARTICULATE_MATTER_25,
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL: CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT,
|
"Particulate Matter < 2.5 μm",
|
||||||
CONF_UNIT_SYSTEM_METRIC: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
unit_imperial=CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT,
|
||||||
ATTR_METRIC_CONVERSION: 3.2808399 ** 3,
|
unit_metric=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||||
ATTR_IS_METRIC_CHECK: True,
|
metric_conversion=3.2808399 ** 3,
|
||||||
},
|
is_metric_check=True,
|
||||||
{
|
),
|
||||||
ATTR_FIELD: CC_ATTR_PARTICULATE_MATTER_10,
|
ClimaCellSensorMetadata(
|
||||||
ATTR_NAME: "Particulate Matter < 10 μm",
|
CC_ATTR_PARTICULATE_MATTER_10,
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL: CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT,
|
"Particulate Matter < 10 μm",
|
||||||
CONF_UNIT_SYSTEM_METRIC: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
unit_imperial=CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT,
|
||||||
ATTR_METRIC_CONVERSION: 3.2808399 ** 3,
|
unit_metric=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||||
ATTR_IS_METRIC_CHECK: True,
|
metric_conversion=3.2808399 ** 3,
|
||||||
},
|
is_metric_check=True,
|
||||||
{
|
),
|
||||||
ATTR_FIELD: CC_ATTR_NITROGEN_DIOXIDE,
|
ClimaCellSensorMetadata(
|
||||||
ATTR_NAME: "Nitrogen Dioxide",
|
CC_ATTR_NITROGEN_DIOXIDE,
|
||||||
CONF_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_BILLION,
|
"Nitrogen Dioxide",
|
||||||
},
|
unit_imperial=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
{
|
unit_metric=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
ATTR_FIELD: CC_ATTR_CARBON_MONOXIDE,
|
),
|
||||||
ATTR_NAME: "Carbon Monoxide",
|
ClimaCellSensorMetadata(
|
||||||
CONF_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_BILLION,
|
CC_ATTR_CARBON_MONOXIDE,
|
||||||
ATTR_DEVICE_CLASS: DEVICE_CLASS_CO,
|
"Carbon Monoxide",
|
||||||
},
|
unit_imperial=CONCENTRATION_PARTS_PER_MILLION,
|
||||||
{
|
unit_metric=CONCENTRATION_PARTS_PER_MILLION,
|
||||||
ATTR_FIELD: CC_ATTR_SULFUR_DIOXIDE,
|
device_class=DEVICE_CLASS_CO,
|
||||||
ATTR_NAME: "Sulfur Dioxide",
|
),
|
||||||
CONF_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_BILLION,
|
ClimaCellSensorMetadata(
|
||||||
},
|
CC_ATTR_SULFUR_DIOXIDE,
|
||||||
{ATTR_FIELD: CC_ATTR_EPA_AQI, ATTR_NAME: "US EPA Air Quality Index"},
|
"Sulfur Dioxide",
|
||||||
{
|
unit_imperial=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
ATTR_FIELD: CC_ATTR_EPA_PRIMARY_POLLUTANT,
|
unit_metric=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
ATTR_NAME: "US EPA Primary Pollutant",
|
),
|
||||||
ATTR_VALUE_MAP: PrimaryPollutantType,
|
ClimaCellSensorMetadata(CC_ATTR_EPA_AQI, "US EPA Air Quality Index"),
|
||||||
},
|
ClimaCellSensorMetadata(
|
||||||
{
|
CC_ATTR_EPA_PRIMARY_POLLUTANT,
|
||||||
ATTR_FIELD: CC_ATTR_EPA_HEALTH_CONCERN,
|
"US EPA Primary Pollutant",
|
||||||
ATTR_NAME: "US EPA Health Concern",
|
value_map=PrimaryPollutantType,
|
||||||
ATTR_VALUE_MAP: HealthConcernType,
|
),
|
||||||
},
|
ClimaCellSensorMetadata(
|
||||||
{ATTR_FIELD: CC_ATTR_CHINA_AQI, ATTR_NAME: "China MEP Air Quality Index"},
|
CC_ATTR_EPA_HEALTH_CONCERN,
|
||||||
{
|
"US EPA Health Concern",
|
||||||
ATTR_FIELD: CC_ATTR_CHINA_PRIMARY_POLLUTANT,
|
value_map=HealthConcernType,
|
||||||
ATTR_NAME: "China MEP Primary Pollutant",
|
),
|
||||||
ATTR_VALUE_MAP: PrimaryPollutantType,
|
ClimaCellSensorMetadata(CC_ATTR_CHINA_AQI, "China MEP Air Quality Index"),
|
||||||
},
|
ClimaCellSensorMetadata(
|
||||||
{
|
CC_ATTR_CHINA_PRIMARY_POLLUTANT,
|
||||||
ATTR_FIELD: CC_ATTR_CHINA_HEALTH_CONCERN,
|
"China MEP Primary Pollutant",
|
||||||
ATTR_NAME: "China MEP Health Concern",
|
value_map=PrimaryPollutantType,
|
||||||
ATTR_VALUE_MAP: HealthConcernType,
|
),
|
||||||
},
|
ClimaCellSensorMetadata(
|
||||||
{
|
CC_ATTR_CHINA_HEALTH_CONCERN,
|
||||||
ATTR_FIELD: CC_ATTR_POLLEN_TREE,
|
"China MEP Health Concern",
|
||||||
ATTR_NAME: "Tree Pollen Index",
|
value_map=HealthConcernType,
|
||||||
ATTR_VALUE_MAP: PollenIndex,
|
),
|
||||||
},
|
ClimaCellSensorMetadata(
|
||||||
{
|
CC_ATTR_POLLEN_TREE, "Tree Pollen Index", value_map=PollenIndex
|
||||||
ATTR_FIELD: CC_ATTR_POLLEN_WEED,
|
),
|
||||||
ATTR_NAME: "Weed Pollen Index",
|
ClimaCellSensorMetadata(
|
||||||
ATTR_VALUE_MAP: PollenIndex,
|
CC_ATTR_POLLEN_WEED, "Weed Pollen Index", value_map=PollenIndex
|
||||||
},
|
),
|
||||||
{
|
ClimaCellSensorMetadata(
|
||||||
ATTR_FIELD: CC_ATTR_POLLEN_GRASS,
|
CC_ATTR_POLLEN_GRASS, "Grass Pollen Index", value_map=PollenIndex
|
||||||
ATTR_NAME: "Grass Pollen Index",
|
),
|
||||||
ATTR_VALUE_MAP: PollenIndex,
|
ClimaCellSensorMetadata(CC_ATTR_FIRE_INDEX, "Fire Index"),
|
||||||
},
|
)
|
||||||
{ATTR_FIELD: CC_ATTR_FIRE_INDEX, ATTR_NAME: "Fire Index"},
|
|
||||||
]
|
|
||||||
|
|
||||||
# V3 constants
|
# V3 constants
|
||||||
CONDITIONS_V3 = {
|
CONDITIONS_V3 = {
|
||||||
@ -377,73 +388,68 @@ CC_V3_ATTR_POLLEN_WEED = "pollen_weed"
|
|||||||
CC_V3_ATTR_POLLEN_GRASS = "pollen_grass"
|
CC_V3_ATTR_POLLEN_GRASS = "pollen_grass"
|
||||||
CC_V3_ATTR_FIRE_INDEX = "fire_index"
|
CC_V3_ATTR_FIRE_INDEX = "fire_index"
|
||||||
|
|
||||||
CC_V3_SENSOR_TYPES = [
|
CC_V3_SENSOR_TYPES = (
|
||||||
{
|
ClimaCellSensorMetadata(
|
||||||
ATTR_FIELD: CC_V3_ATTR_OZONE,
|
CC_V3_ATTR_OZONE,
|
||||||
ATTR_NAME: "Ozone",
|
"Ozone",
|
||||||
CONF_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_BILLION,
|
unit_imperial=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
},
|
unit_metric=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
{
|
),
|
||||||
ATTR_FIELD: CC_V3_ATTR_PARTICULATE_MATTER_25,
|
ClimaCellSensorMetadata(
|
||||||
ATTR_NAME: "Particulate Matter < 2.5 μm",
|
CC_V3_ATTR_PARTICULATE_MATTER_25,
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL: "μg/ft³",
|
"Particulate Matter < 2.5 μm",
|
||||||
CONF_UNIT_SYSTEM_METRIC: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
unit_imperial=CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT,
|
||||||
ATTR_METRIC_CONVERSION: 3.2808399 ** 3,
|
unit_metric=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||||
ATTR_IS_METRIC_CHECK: False,
|
metric_conversion=3.2808399 ** 3,
|
||||||
},
|
is_metric_check=False,
|
||||||
{
|
),
|
||||||
ATTR_FIELD: CC_V3_ATTR_PARTICULATE_MATTER_10,
|
ClimaCellSensorMetadata(
|
||||||
ATTR_NAME: "Particulate Matter < 10 μm",
|
CC_V3_ATTR_PARTICULATE_MATTER_10,
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL: "μg/ft³",
|
"Particulate Matter < 10 μm",
|
||||||
CONF_UNIT_SYSTEM_METRIC: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
unit_imperial=CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT,
|
||||||
ATTR_METRIC_CONVERSION: 3.2808399 ** 3,
|
unit_metric=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||||
ATTR_IS_METRIC_CHECK: False,
|
metric_conversion=3.2808399 ** 3,
|
||||||
},
|
is_metric_check=False,
|
||||||
{
|
),
|
||||||
ATTR_FIELD: CC_V3_ATTR_NITROGEN_DIOXIDE,
|
ClimaCellSensorMetadata(
|
||||||
ATTR_NAME: "Nitrogen Dioxide",
|
CC_V3_ATTR_NITROGEN_DIOXIDE,
|
||||||
CONF_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_BILLION,
|
"Nitrogen Dioxide",
|
||||||
},
|
unit_imperial=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
{
|
unit_metric=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
ATTR_FIELD: CC_V3_ATTR_CARBON_MONOXIDE,
|
),
|
||||||
ATTR_NAME: "Carbon Monoxide",
|
ClimaCellSensorMetadata(
|
||||||
CONF_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_MILLION,
|
CC_V3_ATTR_CARBON_MONOXIDE,
|
||||||
ATTR_DEVICE_CLASS: DEVICE_CLASS_CO,
|
"Carbon Monoxide",
|
||||||
},
|
unit_imperial=CONCENTRATION_PARTS_PER_MILLION,
|
||||||
{
|
unit_metric=CONCENTRATION_PARTS_PER_MILLION,
|
||||||
ATTR_FIELD: CC_V3_ATTR_SULFUR_DIOXIDE,
|
device_class=DEVICE_CLASS_CO,
|
||||||
ATTR_NAME: "Sulfur Dioxide",
|
),
|
||||||
CONF_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_BILLION,
|
ClimaCellSensorMetadata(
|
||||||
},
|
CC_V3_ATTR_SULFUR_DIOXIDE,
|
||||||
{ATTR_FIELD: CC_V3_ATTR_EPA_AQI, ATTR_NAME: "US EPA Air Quality Index"},
|
"Sulfur Dioxide",
|
||||||
{
|
unit_imperial=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
ATTR_FIELD: CC_V3_ATTR_EPA_PRIMARY_POLLUTANT,
|
unit_metric=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
ATTR_NAME: "US EPA Primary Pollutant",
|
),
|
||||||
},
|
ClimaCellSensorMetadata(CC_V3_ATTR_EPA_AQI, "US EPA Air Quality Index"),
|
||||||
{ATTR_FIELD: CC_V3_ATTR_EPA_HEALTH_CONCERN, ATTR_NAME: "US EPA Health Concern"},
|
ClimaCellSensorMetadata(
|
||||||
{ATTR_FIELD: CC_V3_ATTR_CHINA_AQI, ATTR_NAME: "China MEP Air Quality Index"},
|
CC_V3_ATTR_EPA_PRIMARY_POLLUTANT, "US EPA Primary Pollutant"
|
||||||
{
|
),
|
||||||
ATTR_FIELD: CC_V3_ATTR_CHINA_PRIMARY_POLLUTANT,
|
ClimaCellSensorMetadata(CC_V3_ATTR_EPA_HEALTH_CONCERN, "US EPA Health Concern"),
|
||||||
ATTR_NAME: "China MEP Primary Pollutant",
|
ClimaCellSensorMetadata(CC_V3_ATTR_CHINA_AQI, "China MEP Air Quality Index"),
|
||||||
},
|
ClimaCellSensorMetadata(
|
||||||
{
|
CC_V3_ATTR_CHINA_PRIMARY_POLLUTANT, "China MEP Primary Pollutant"
|
||||||
ATTR_FIELD: CC_V3_ATTR_CHINA_HEALTH_CONCERN,
|
),
|
||||||
ATTR_NAME: "China MEP Health Concern",
|
ClimaCellSensorMetadata(
|
||||||
},
|
CC_V3_ATTR_CHINA_HEALTH_CONCERN, "China MEP Health Concern"
|
||||||
{
|
),
|
||||||
ATTR_FIELD: CC_V3_ATTR_POLLEN_TREE,
|
ClimaCellSensorMetadata(
|
||||||
ATTR_NAME: "Tree Pollen Index",
|
CC_V3_ATTR_POLLEN_TREE, "Tree Pollen Index", value_map=V3PollenIndex
|
||||||
ATTR_VALUE_MAP: V3PollenIndex,
|
),
|
||||||
},
|
ClimaCellSensorMetadata(
|
||||||
{
|
CC_V3_ATTR_POLLEN_WEED, "Weed Pollen Index", value_map=V3PollenIndex
|
||||||
ATTR_FIELD: CC_V3_ATTR_POLLEN_WEED,
|
),
|
||||||
ATTR_NAME: "Weed Pollen Index",
|
ClimaCellSensorMetadata(
|
||||||
ATTR_VALUE_MAP: V3PollenIndex,
|
CC_V3_ATTR_POLLEN_GRASS, "Grass Pollen Index", value_map=V3PollenIndex
|
||||||
},
|
),
|
||||||
{
|
ClimaCellSensorMetadata(CC_V3_ATTR_FIRE_INDEX, "Fire Index"),
|
||||||
ATTR_FIELD: CC_V3_ATTR_POLLEN_GRASS,
|
)
|
||||||
ATTR_NAME: "Grass Pollen Index",
|
|
||||||
ATTR_VALUE_MAP: V3PollenIndex,
|
|
||||||
},
|
|
||||||
{ATTR_FIELD: CC_V3_ATTR_FIRE_INDEX, ATTR_NAME: "Fire Index"},
|
|
||||||
]
|
|
||||||
|
@ -2,39 +2,19 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from collections.abc import Mapping
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from pyclimacell.const import CURRENT
|
from pyclimacell.const import CURRENT
|
||||||
|
|
||||||
from homeassistant.components.sensor import SensorEntity
|
from homeassistant.components.sensor import SensorEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import ATTR_ATTRIBUTION, CONF_API_VERSION, CONF_NAME
|
||||||
ATTR_ATTRIBUTION,
|
|
||||||
ATTR_DEVICE_CLASS,
|
|
||||||
ATTR_NAME,
|
|
||||||
CONF_API_VERSION,
|
|
||||||
CONF_NAME,
|
|
||||||
CONF_UNIT_OF_MEASUREMENT,
|
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL,
|
|
||||||
CONF_UNIT_SYSTEM_METRIC,
|
|
||||||
)
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
from . import ClimaCellDataUpdateCoordinator, ClimaCellEntity
|
from . import ClimaCellDataUpdateCoordinator, ClimaCellEntity
|
||||||
from .const import (
|
from .const import CC_SENSOR_TYPES, CC_V3_SENSOR_TYPES, DOMAIN, ClimaCellSensorMetadata
|
||||||
ATTR_FIELD,
|
|
||||||
ATTR_IS_METRIC_CHECK,
|
|
||||||
ATTR_METRIC_CONVERSION,
|
|
||||||
ATTR_SCALE,
|
|
||||||
ATTR_VALUE_MAP,
|
|
||||||
CC_SENSOR_TYPES,
|
|
||||||
CC_V3_SENSOR_TYPES,
|
|
||||||
DOMAIN,
|
|
||||||
)
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -55,7 +35,7 @@ async def async_setup_entry(
|
|||||||
api_class = ClimaCellSensorEntity
|
api_class = ClimaCellSensorEntity
|
||||||
sensor_types = CC_SENSOR_TYPES
|
sensor_types = CC_SENSOR_TYPES
|
||||||
entities = [
|
entities = [
|
||||||
api_class(config_entry, coordinator, api_version, sensor_type)
|
api_class(hass, config_entry, coordinator, api_version, sensor_type)
|
||||||
for sensor_type in sensor_types
|
for sensor_type in sensor_types
|
||||||
]
|
]
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
@ -66,53 +46,29 @@ class BaseClimaCellSensorEntity(ClimaCellEntity, SensorEntity):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: ConfigEntry,
|
||||||
coordinator: ClimaCellDataUpdateCoordinator,
|
coordinator: ClimaCellDataUpdateCoordinator,
|
||||||
api_version: int,
|
api_version: int,
|
||||||
sensor_type: dict[str, str | float],
|
sensor_type: ClimaCellSensorMetadata,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize ClimaCell Sensor Entity."""
|
"""Initialize ClimaCell Sensor Entity."""
|
||||||
super().__init__(config_entry, coordinator, api_version)
|
super().__init__(config_entry, coordinator, api_version)
|
||||||
self.sensor_type = sensor_type
|
self.sensor_type = sensor_type
|
||||||
self._attr_device_class = self.sensor_type.get(ATTR_DEVICE_CLASS)
|
self._attr_device_class = self.sensor_type.device_class
|
||||||
|
self._attr_entity_registry_enabled_default = False
|
||||||
@property
|
self._attr_name = (
|
||||||
def entity_registry_enabled_default(self) -> bool:
|
f"{self._config_entry.data[CONF_NAME]} - {self.sensor_type.name}"
|
||||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
)
|
||||||
return False
|
self._attr_unique_id = (
|
||||||
|
f"{self._config_entry.unique_id}_{slugify(self.sensor_type.name)}"
|
||||||
@property
|
)
|
||||||
def name(self) -> str:
|
self._attr_extra_state_attributes = {ATTR_ATTRIBUTION: self.attribution}
|
||||||
"""Return the name of the entity."""
|
self._attr_unit_of_measurement = (
|
||||||
return f"{self._config_entry.data[CONF_NAME]} - {self.sensor_type[ATTR_NAME]}"
|
self.sensor_type.unit_metric
|
||||||
|
if hass.config.units.is_metric
|
||||||
@property
|
else self.sensor_type.unit_imperial
|
||||||
def unique_id(self) -> str:
|
)
|
||||||
"""Return the unique id of the entity."""
|
|
||||||
return f"{self._config_entry.unique_id}_{slugify(self.sensor_type[ATTR_NAME])}"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def extra_state_attributes(self) -> Mapping[str, Any] | None:
|
|
||||||
"""Return entity specific state attributes."""
|
|
||||||
return {ATTR_ATTRIBUTION: self.attribution}
|
|
||||||
|
|
||||||
@property
|
|
||||||
def unit_of_measurement(self) -> str | None:
|
|
||||||
"""Return the unit of measurement."""
|
|
||||||
if CONF_UNIT_OF_MEASUREMENT in self.sensor_type:
|
|
||||||
return self.sensor_type[CONF_UNIT_OF_MEASUREMENT]
|
|
||||||
|
|
||||||
if (
|
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL in self.sensor_type
|
|
||||||
and CONF_UNIT_SYSTEM_METRIC in self.sensor_type
|
|
||||||
):
|
|
||||||
return (
|
|
||||||
self.sensor_type[CONF_UNIT_SYSTEM_METRIC]
|
|
||||||
if self.hass.config.units.is_metric
|
|
||||||
else self.sensor_type[CONF_UNIT_SYSTEM_IMPERIAL]
|
|
||||||
)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@ -123,27 +79,22 @@ class BaseClimaCellSensorEntity(ClimaCellEntity, SensorEntity):
|
|||||||
def state(self) -> str | int | float | None:
|
def state(self) -> str | int | float | None:
|
||||||
"""Return the state."""
|
"""Return the state."""
|
||||||
state = self._state
|
state = self._state
|
||||||
if state and ATTR_SCALE in self.sensor_type:
|
|
||||||
state *= self.sensor_type[ATTR_SCALE]
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
state is not None
|
state is not None
|
||||||
and CONF_UNIT_SYSTEM_IMPERIAL in self.sensor_type
|
and self.sensor_type.unit_imperial is not None
|
||||||
and CONF_UNIT_SYSTEM_METRIC in self.sensor_type
|
and self.sensor_type.metric_conversion != 1.0
|
||||||
and ATTR_METRIC_CONVERSION in self.sensor_type
|
and self.sensor_type.is_metric_check is not None
|
||||||
and ATTR_IS_METRIC_CHECK in self.sensor_type
|
and self.hass.config.units.is_metric == self.sensor_type.is_metric_check
|
||||||
and self.hass.config.units.is_metric
|
|
||||||
== self.sensor_type[ATTR_IS_METRIC_CHECK]
|
|
||||||
):
|
):
|
||||||
conversion = self.sensor_type[ATTR_METRIC_CONVERSION]
|
conversion = self.sensor_type.metric_conversion
|
||||||
# When conversion is a callable, we assume it's a single input function
|
# When conversion is a callable, we assume it's a single input function
|
||||||
if callable(conversion):
|
if callable(conversion):
|
||||||
return round(conversion(state), 4)
|
return round(conversion(state), 4)
|
||||||
|
|
||||||
return round(state * conversion, 4)
|
return round(state * conversion, 4)
|
||||||
|
|
||||||
if ATTR_VALUE_MAP in self.sensor_type and state is not None:
|
if self.sensor_type.value_map is not None and state is not None:
|
||||||
return self.sensor_type[ATTR_VALUE_MAP](state).name.lower()
|
return self.sensor_type.value_map(state).name.lower()
|
||||||
|
|
||||||
return state
|
return state
|
||||||
|
|
||||||
@ -154,7 +105,7 @@ class ClimaCellSensorEntity(BaseClimaCellSensorEntity):
|
|||||||
@property
|
@property
|
||||||
def _state(self) -> str | int | float | None:
|
def _state(self) -> str | int | float | None:
|
||||||
"""Return the raw state."""
|
"""Return the raw state."""
|
||||||
return self._get_current_property(self.sensor_type[ATTR_FIELD])
|
return self._get_current_property(self.sensor_type.field)
|
||||||
|
|
||||||
|
|
||||||
class ClimaCellV3SensorEntity(BaseClimaCellSensorEntity):
|
class ClimaCellV3SensorEntity(BaseClimaCellSensorEntity):
|
||||||
@ -164,5 +115,5 @@ class ClimaCellV3SensorEntity(BaseClimaCellSensorEntity):
|
|||||||
def _state(self) -> str | int | float | None:
|
def _state(self) -> str | int | float | None:
|
||||||
"""Return the raw state."""
|
"""Return the raw state."""
|
||||||
return self._get_cc_value(
|
return self._get_cc_value(
|
||||||
self.coordinator.data[CURRENT], self.sensor_type[ATTR_FIELD]
|
self.coordinator.data[CURRENT], self.sensor_type.field
|
||||||
)
|
)
|
||||||
|
12
tests/components/climacell/test_const.py
Normal file
12
tests/components/climacell/test_const.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
"""Tests for ClimaCell const."""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.climacell.const import ClimaCellSensorMetadata
|
||||||
|
from homeassistant.const import TEMP_FAHRENHEIT
|
||||||
|
|
||||||
|
|
||||||
|
async def test_post_init():
|
||||||
|
"""Test post initiailization check for ClimaCellSensorMetadata."""
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError):
|
||||||
|
ClimaCellSensorMetadata("a", "b", unit_imperial=TEMP_FAHRENHEIT)
|
Loading…
x
Reference in New Issue
Block a user