"""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 ( DAILY, HOURLY, NOWCAST, HealthConcernType, PollenIndex, PrecipitationType, PrimaryPollutantType, V3PollenIndex, WeatherCode, ) from homeassistant.components.sensor import SensorEntityDescription from homeassistant.components.weather import ( ATTR_CONDITION_CLEAR_NIGHT, ATTR_CONDITION_CLOUDY, ATTR_CONDITION_FOG, ATTR_CONDITION_HAIL, ATTR_CONDITION_LIGHTNING, ATTR_CONDITION_PARTLYCLOUDY, ATTR_CONDITION_POURING, ATTR_CONDITION_RAINY, ATTR_CONDITION_SNOWY, ATTR_CONDITION_SNOWY_RAINY, ATTR_CONDITION_SUNNY, ATTR_CONDITION_WINDY, ) from homeassistant.const import ( CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT, CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, CONCENTRATION_PARTS_PER_BILLION, CONCENTRATION_PARTS_PER_MILLION, DEVICE_CLASS_CO, DEVICE_CLASS_PRESSURE, DEVICE_CLASS_TEMPERATURE, IRRADIATION_BTUS_PER_HOUR_SQUARE_FOOT, IRRADIATION_WATTS_PER_SQUARE_METER, LENGTH_KILOMETERS, LENGTH_METERS, LENGTH_MILES, PERCENTAGE, PRESSURE_HPA, PRESSURE_INHG, SPEED_METERS_PER_SECOND, SPEED_MILES_PER_HOUR, TEMP_CELSIUS, TEMP_FAHRENHEIT, ) from homeassistant.util.distance import convert as distance_convert from homeassistant.util.pressure import convert as pressure_convert from homeassistant.util.temperature import convert as temp_convert CONF_TIMESTEP = "timestep" FORECAST_TYPES = [DAILY, HOURLY, NOWCAST] DEFAULT_NAME = "ClimaCell" DEFAULT_TIMESTEP = 15 DEFAULT_FORECAST_TYPE = DAILY DOMAIN = "climacell" ATTRIBUTION = "Powered by ClimaCell" MAX_REQUESTS_PER_DAY = 100 CLEAR_CONDITIONS = {"night": ATTR_CONDITION_CLEAR_NIGHT, "day": ATTR_CONDITION_SUNNY} MAX_FORECASTS = { DAILY: 14, HOURLY: 24, NOWCAST: 30, } # Additional attributes ATTR_WIND_GUST = "wind_gust" ATTR_CLOUD_COVER = "cloud_cover" ATTR_PRECIPITATION_TYPE = "precipitation_type" # V4 constants CONDITIONS = { WeatherCode.WIND: ATTR_CONDITION_WINDY, WeatherCode.LIGHT_WIND: ATTR_CONDITION_WINDY, WeatherCode.STRONG_WIND: ATTR_CONDITION_WINDY, WeatherCode.FREEZING_RAIN: ATTR_CONDITION_SNOWY_RAINY, WeatherCode.HEAVY_FREEZING_RAIN: ATTR_CONDITION_SNOWY_RAINY, WeatherCode.LIGHT_FREEZING_RAIN: ATTR_CONDITION_SNOWY_RAINY, WeatherCode.FREEZING_DRIZZLE: ATTR_CONDITION_SNOWY_RAINY, WeatherCode.ICE_PELLETS: ATTR_CONDITION_HAIL, WeatherCode.HEAVY_ICE_PELLETS: ATTR_CONDITION_HAIL, WeatherCode.LIGHT_ICE_PELLETS: ATTR_CONDITION_HAIL, WeatherCode.SNOW: ATTR_CONDITION_SNOWY, WeatherCode.HEAVY_SNOW: ATTR_CONDITION_SNOWY, WeatherCode.LIGHT_SNOW: ATTR_CONDITION_SNOWY, WeatherCode.FLURRIES: ATTR_CONDITION_SNOWY, WeatherCode.THUNDERSTORM: ATTR_CONDITION_LIGHTNING, WeatherCode.RAIN: ATTR_CONDITION_POURING, WeatherCode.HEAVY_RAIN: ATTR_CONDITION_RAINY, WeatherCode.LIGHT_RAIN: ATTR_CONDITION_RAINY, WeatherCode.DRIZZLE: ATTR_CONDITION_RAINY, WeatherCode.FOG: ATTR_CONDITION_FOG, WeatherCode.LIGHT_FOG: ATTR_CONDITION_FOG, WeatherCode.CLOUDY: ATTR_CONDITION_CLOUDY, WeatherCode.MOSTLY_CLOUDY: ATTR_CONDITION_CLOUDY, WeatherCode.PARTLY_CLOUDY: ATTR_CONDITION_PARTLYCLOUDY, } # Weather constants CC_ATTR_TIMESTAMP = "startTime" CC_ATTR_TEMPERATURE = "temperature" CC_ATTR_TEMPERATURE_HIGH = "temperatureMax" CC_ATTR_TEMPERATURE_LOW = "temperatureMin" CC_ATTR_PRESSURE = "pressureSeaLevel" CC_ATTR_HUMIDITY = "humidity" CC_ATTR_WIND_SPEED = "windSpeed" CC_ATTR_WIND_DIRECTION = "windDirection" CC_ATTR_OZONE = "pollutantO3" CC_ATTR_CONDITION = "weatherCode" CC_ATTR_VISIBILITY = "visibility" CC_ATTR_PRECIPITATION = "precipitationIntensityAvg" CC_ATTR_PRECIPITATION_PROBABILITY = "precipitationProbability" CC_ATTR_WIND_GUST = "windGust" CC_ATTR_CLOUD_COVER = "cloudCover" CC_ATTR_PRECIPITATION_TYPE = "precipitationType" # Sensor attributes CC_ATTR_PARTICULATE_MATTER_25 = "particulateMatter25" CC_ATTR_PARTICULATE_MATTER_10 = "particulateMatter10" CC_ATTR_NITROGEN_DIOXIDE = "pollutantNO2" CC_ATTR_CARBON_MONOXIDE = "pollutantCO" CC_ATTR_SULFUR_DIOXIDE = "pollutantSO2" CC_ATTR_EPA_AQI = "epaIndex" CC_ATTR_EPA_PRIMARY_POLLUTANT = "epaPrimaryPollutant" CC_ATTR_EPA_HEALTH_CONCERN = "epaHealthConcern" CC_ATTR_CHINA_AQI = "mepIndex" CC_ATTR_CHINA_PRIMARY_POLLUTANT = "mepPrimaryPollutant" CC_ATTR_CHINA_HEALTH_CONCERN = "mepHealthConcern" CC_ATTR_POLLEN_TREE = "treeIndex" CC_ATTR_POLLEN_WEED = "weedIndex" CC_ATTR_POLLEN_GRASS = "grassIndex" CC_ATTR_FIRE_INDEX = "fireIndex" CC_ATTR_FEELS_LIKE = "temperatureApparent" CC_ATTR_DEW_POINT = "dewPoint" CC_ATTR_PRESSURE_SURFACE_LEVEL = "pressureSurfaceLevel" CC_ATTR_SOLAR_GHI = "solarGHI" CC_ATTR_CLOUD_BASE = "cloudBase" CC_ATTR_CLOUD_CEILING = "cloudCeiling" @dataclass class ClimaCellSensorEntityDescription(SensorEntityDescription): """Describes a ClimaCell sensor entity.""" unit_imperial: str | None = None unit_metric: str | None = None metric_conversion: Callable[[float], float] | float = 1.0 is_metric_check: bool | None = None device_class: str | None = None value_map: IntEnum | None = None def __post_init__(self) -> None: """Post initialization.""" units = (self.unit_imperial, self.unit_metric) if any(u is not None for u in units) and any(u is None for u in units): raise RuntimeError( "`unit_imperial` and `unit_metric` both need to be None or both need " "to be defined." ) CC_SENSOR_TYPES = ( ClimaCellSensorEntityDescription( key=CC_ATTR_FEELS_LIKE, name="Feels Like", 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, ), ClimaCellSensorEntityDescription( key=CC_ATTR_DEW_POINT, name="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, ), ClimaCellSensorEntityDescription( key=CC_ATTR_PRESSURE_SURFACE_LEVEL, name="Pressure (Surface Level)", unit_imperial=PRESSURE_INHG, unit_metric=PRESSURE_HPA, metric_conversion=lambda val: pressure_convert( val, PRESSURE_INHG, PRESSURE_HPA ), is_metric_check=True, device_class=DEVICE_CLASS_PRESSURE, ), ClimaCellSensorEntityDescription( key=CC_ATTR_SOLAR_GHI, name="Global Horizontal Irradiance", unit_imperial=IRRADIATION_BTUS_PER_HOUR_SQUARE_FOOT, unit_metric=IRRADIATION_WATTS_PER_SQUARE_METER, metric_conversion=3.15459, is_metric_check=True, ), ClimaCellSensorEntityDescription( key=CC_ATTR_CLOUD_BASE, name="Cloud Base", unit_imperial=LENGTH_MILES, unit_metric=LENGTH_KILOMETERS, metric_conversion=lambda val: distance_convert( val, LENGTH_MILES, LENGTH_KILOMETERS ), is_metric_check=True, ), ClimaCellSensorEntityDescription( key=CC_ATTR_CLOUD_CEILING, name="Cloud Ceiling", unit_imperial=LENGTH_MILES, unit_metric=LENGTH_KILOMETERS, metric_conversion=lambda val: distance_convert( val, LENGTH_MILES, LENGTH_KILOMETERS ), is_metric_check=True, ), ClimaCellSensorEntityDescription( key=CC_ATTR_CLOUD_COVER, name="Cloud Cover", unit_imperial=PERCENTAGE, unit_metric=PERCENTAGE, ), ClimaCellSensorEntityDescription( key=CC_ATTR_WIND_GUST, name="Wind Gust", unit_imperial=SPEED_MILES_PER_HOUR, unit_metric=SPEED_METERS_PER_SECOND, metric_conversion=lambda val: distance_convert(val, LENGTH_MILES, LENGTH_METERS) / 3600, is_metric_check=True, ), ClimaCellSensorEntityDescription( key=CC_ATTR_PRECIPITATION_TYPE, name="Precipitation Type", value_map=PrecipitationType, ), ClimaCellSensorEntityDescription( key=CC_ATTR_OZONE, name="Ozone", unit_imperial=CONCENTRATION_PARTS_PER_BILLION, unit_metric=CONCENTRATION_PARTS_PER_BILLION, ), ClimaCellSensorEntityDescription( key=CC_ATTR_PARTICULATE_MATTER_25, name="Particulate Matter < 2.5 μm", unit_imperial=CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT, unit_metric=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, metric_conversion=3.2808399 ** 3, is_metric_check=True, ), ClimaCellSensorEntityDescription( key=CC_ATTR_PARTICULATE_MATTER_10, name="Particulate Matter < 10 μm", unit_imperial=CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT, unit_metric=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, metric_conversion=3.2808399 ** 3, is_metric_check=True, ), ClimaCellSensorEntityDescription( key=CC_ATTR_NITROGEN_DIOXIDE, name="Nitrogen Dioxide", unit_imperial=CONCENTRATION_PARTS_PER_BILLION, unit_metric=CONCENTRATION_PARTS_PER_BILLION, ), ClimaCellSensorEntityDescription( key=CC_ATTR_CARBON_MONOXIDE, name="Carbon Monoxide", unit_imperial=CONCENTRATION_PARTS_PER_MILLION, unit_metric=CONCENTRATION_PARTS_PER_MILLION, device_class=DEVICE_CLASS_CO, ), ClimaCellSensorEntityDescription( key=CC_ATTR_SULFUR_DIOXIDE, name="Sulfur Dioxide", unit_imperial=CONCENTRATION_PARTS_PER_BILLION, unit_metric=CONCENTRATION_PARTS_PER_BILLION, ), ClimaCellSensorEntityDescription( key=CC_ATTR_EPA_AQI, name="US EPA Air Quality Index", ), ClimaCellSensorEntityDescription( key=CC_ATTR_EPA_PRIMARY_POLLUTANT, name="US EPA Primary Pollutant", value_map=PrimaryPollutantType, ), ClimaCellSensorEntityDescription( key=CC_ATTR_EPA_HEALTH_CONCERN, name="US EPA Health Concern", value_map=HealthConcernType, ), ClimaCellSensorEntityDescription( key=CC_ATTR_CHINA_AQI, name="China MEP Air Quality Index", ), ClimaCellSensorEntityDescription( key=CC_ATTR_CHINA_PRIMARY_POLLUTANT, name="China MEP Primary Pollutant", value_map=PrimaryPollutantType, ), ClimaCellSensorEntityDescription( key=CC_ATTR_CHINA_HEALTH_CONCERN, name="China MEP Health Concern", value_map=HealthConcernType, ), ClimaCellSensorEntityDescription( key=CC_ATTR_POLLEN_TREE, name="Tree Pollen Index", value_map=PollenIndex, ), ClimaCellSensorEntityDescription( key=CC_ATTR_POLLEN_WEED, name="Weed Pollen Index", value_map=PollenIndex, ), ClimaCellSensorEntityDescription( key=CC_ATTR_POLLEN_GRASS, name="Grass Pollen Index", value_map=PollenIndex, ), ClimaCellSensorEntityDescription( CC_ATTR_FIRE_INDEX, name="Fire Index", ), ) # V3 constants CONDITIONS_V3 = { "breezy": ATTR_CONDITION_WINDY, "freezing_rain_heavy": ATTR_CONDITION_SNOWY_RAINY, "freezing_rain": ATTR_CONDITION_SNOWY_RAINY, "freezing_rain_light": ATTR_CONDITION_SNOWY_RAINY, "freezing_drizzle": ATTR_CONDITION_SNOWY_RAINY, "ice_pellets_heavy": ATTR_CONDITION_HAIL, "ice_pellets": ATTR_CONDITION_HAIL, "ice_pellets_light": ATTR_CONDITION_HAIL, "snow_heavy": ATTR_CONDITION_SNOWY, "snow": ATTR_CONDITION_SNOWY, "snow_light": ATTR_CONDITION_SNOWY, "flurries": ATTR_CONDITION_SNOWY, "tstorm": ATTR_CONDITION_LIGHTNING, "rain_heavy": ATTR_CONDITION_POURING, "rain": ATTR_CONDITION_RAINY, "rain_light": ATTR_CONDITION_RAINY, "drizzle": ATTR_CONDITION_RAINY, "fog_light": ATTR_CONDITION_FOG, "fog": ATTR_CONDITION_FOG, "cloudy": ATTR_CONDITION_CLOUDY, "mostly_cloudy": ATTR_CONDITION_CLOUDY, "partly_cloudy": ATTR_CONDITION_PARTLYCLOUDY, } # Weather attributes CC_V3_ATTR_TIMESTAMP = "observation_time" CC_V3_ATTR_TEMPERATURE = "temp" CC_V3_ATTR_TEMPERATURE_HIGH = "max" CC_V3_ATTR_TEMPERATURE_LOW = "min" CC_V3_ATTR_PRESSURE = "baro_pressure" CC_V3_ATTR_HUMIDITY = "humidity" CC_V3_ATTR_WIND_SPEED = "wind_speed" CC_V3_ATTR_WIND_DIRECTION = "wind_direction" CC_V3_ATTR_OZONE = "o3" CC_V3_ATTR_CONDITION = "weather_code" CC_V3_ATTR_VISIBILITY = "visibility" CC_V3_ATTR_PRECIPITATION = "precipitation" CC_V3_ATTR_PRECIPITATION_DAILY = "precipitation_accumulation" CC_V3_ATTR_PRECIPITATION_PROBABILITY = "precipitation_probability" CC_V3_ATTR_WIND_GUST = "wind_gust" CC_V3_ATTR_CLOUD_COVER = "cloud_cover" CC_V3_ATTR_PRECIPITATION_TYPE = "precipitation_type" # Sensor attributes CC_V3_ATTR_PARTICULATE_MATTER_25 = "pm25" CC_V3_ATTR_PARTICULATE_MATTER_10 = "pm10" CC_V3_ATTR_NITROGEN_DIOXIDE = "no2" CC_V3_ATTR_CARBON_MONOXIDE = "co" CC_V3_ATTR_SULFUR_DIOXIDE = "so2" CC_V3_ATTR_EPA_AQI = "epa_aqi" CC_V3_ATTR_EPA_PRIMARY_POLLUTANT = "epa_primary_pollutant" CC_V3_ATTR_EPA_HEALTH_CONCERN = "epa_health_concern" CC_V3_ATTR_CHINA_AQI = "china_aqi" CC_V3_ATTR_CHINA_PRIMARY_POLLUTANT = "china_primary_pollutant" CC_V3_ATTR_CHINA_HEALTH_CONCERN = "china_health_concern" CC_V3_ATTR_POLLEN_TREE = "pollen_tree" CC_V3_ATTR_POLLEN_WEED = "pollen_weed" CC_V3_ATTR_POLLEN_GRASS = "pollen_grass" CC_V3_ATTR_FIRE_INDEX = "fire_index" CC_V3_SENSOR_TYPES = ( ClimaCellSensorEntityDescription( key=CC_V3_ATTR_OZONE, name="Ozone", unit_imperial=CONCENTRATION_PARTS_PER_BILLION, unit_metric=CONCENTRATION_PARTS_PER_BILLION, ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_PARTICULATE_MATTER_25, name="Particulate Matter < 2.5 μm", unit_imperial=CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT, unit_metric=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, metric_conversion=3.2808399 ** 3, is_metric_check=False, ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_PARTICULATE_MATTER_10, name="Particulate Matter < 10 μm", unit_imperial=CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT, unit_metric=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, metric_conversion=3.2808399 ** 3, is_metric_check=False, ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_NITROGEN_DIOXIDE, name="Nitrogen Dioxide", unit_imperial=CONCENTRATION_PARTS_PER_BILLION, unit_metric=CONCENTRATION_PARTS_PER_BILLION, ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_CARBON_MONOXIDE, name="Carbon Monoxide", unit_imperial=CONCENTRATION_PARTS_PER_MILLION, unit_metric=CONCENTRATION_PARTS_PER_MILLION, device_class=DEVICE_CLASS_CO, ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_SULFUR_DIOXIDE, name="Sulfur Dioxide", unit_imperial=CONCENTRATION_PARTS_PER_BILLION, unit_metric=CONCENTRATION_PARTS_PER_BILLION, ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_EPA_AQI, name="US EPA Air Quality Index", ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_EPA_PRIMARY_POLLUTANT, name="US EPA Primary Pollutant", ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_EPA_HEALTH_CONCERN, name="US EPA Health Concern", ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_CHINA_AQI, name="China MEP Air Quality Index", ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_CHINA_PRIMARY_POLLUTANT, name="China MEP Primary Pollutant", ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_CHINA_HEALTH_CONCERN, name="China MEP Health Concern", ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_POLLEN_TREE, name="Tree Pollen Index", value_map=V3PollenIndex, ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_POLLEN_WEED, name="Weed Pollen Index", value_map=V3PollenIndex, ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_POLLEN_GRASS, name="Grass Pollen Index", value_map=V3PollenIndex, ), ClimaCellSensorEntityDescription( key=CC_V3_ATTR_FIRE_INDEX, name="Fire Index", ), )