diff --git a/homeassistant/components/sensor/__init__.py b/homeassistant/components/sensor/__init__.py index 7beac83f059911..067adb128170a2 100644 --- a/homeassistant/components/sensor/__init__.py +++ b/homeassistant/components/sensor/__init__.py @@ -11,13 +11,8 @@ from math import floor, log10 from typing import Any, Final, cast, final -import voluptuous as vol - -from homeassistant.backports.enum import StrEnum from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( # noqa: F401, pylint: disable=[hass-deprecated-import] - CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, - CONCENTRATION_PARTS_PER_MILLION, CONF_UNIT_OF_MEASUREMENT, DEVICE_CLASS_AQI, DEVICE_CLASS_BATTERY, @@ -47,34 +42,11 @@ DEVICE_CLASS_TIMESTAMP, DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, DEVICE_CLASS_VOLTAGE, - LIGHT_LUX, - PERCENTAGE, - POWER_VOLT_AMPERE_REACTIVE, - SIGNAL_STRENGTH_DECIBELS, - SIGNAL_STRENGTH_DECIBELS_MILLIWATT, - UnitOfApparentPower, - UnitOfDataRate, - UnitOfElectricCurrent, - UnitOfElectricPotential, - UnitOfEnergy, - UnitOfFrequency, - UnitOfInformation, - UnitOfIrradiance, - UnitOfLength, - UnitOfMass, - UnitOfPower, - UnitOfPrecipitationDepth, - UnitOfPressure, - UnitOfSoundPressure, - UnitOfSpeed, UnitOfTemperature, - UnitOfTime, - UnitOfVolume, - UnitOfVolumetricFlux, ) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import entity_registry as er -from homeassistant.helpers.config_validation import ( # noqa: F401 +from homeassistant.helpers.config_validation import ( PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, ) @@ -84,475 +56,47 @@ from homeassistant.helpers.restore_state import ExtraStoredData, RestoreEntity from homeassistant.helpers.typing import ConfigType, StateType from homeassistant.util import dt as dt_util -from homeassistant.util.unit_conversion import ( - BaseUnitConverter, - DataRateConverter, - DistanceConverter, - ElectricCurrentConverter, - ElectricPotentialConverter, - InformationConverter, - MassConverter, - PressureConverter, - SpeedConverter, - TemperatureConverter, - VolumeConverter, -) -from .const import CONF_STATE_CLASS # noqa: F401 +from .const import ( # noqa: F401 + ATTR_LAST_RESET, + ATTR_OPTIONS, + ATTR_STATE_CLASS, + CONF_STATE_CLASS, + DEVICE_CLASS_UNITS, + DEVICE_CLASSES, + DEVICE_CLASSES_SCHEMA, + DOMAIN, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_TOTAL, + STATE_CLASS_TOTAL_INCREASING, + STATE_CLASSES, + STATE_CLASSES_SCHEMA, + UNIT_CONVERTERS, + SensorDeviceClass, + SensorStateClass, +) _LOGGER: Final = logging.getLogger(__name__) -ATTR_LAST_RESET: Final = "last_reset" -ATTR_STATE_CLASS: Final = "state_class" -ATTR_OPTIONS: Final = "options" - -DOMAIN: Final = "sensor" - ENTITY_ID_FORMAT: Final = DOMAIN + ".{}" SCAN_INTERVAL: Final = timedelta(seconds=30) - -class SensorDeviceClass(StrEnum): - """Device class for sensors.""" - - # Non-numerical device classes - DATE = "date" - """Date. - - Unit of measurement: `None` - - ISO8601 format: https://en.wikipedia.org/wiki/ISO_8601 - """ - - DURATION = "duration" - """Fixed duration. - - Unit of measurement: `d`, `h`, `min`, `s` - """ - - ENUM = "enum" - """Enumeration. - - Provides a fixed list of options the state of the sensor can be in. - - Unit of measurement: `None` - """ - - TIMESTAMP = "timestamp" - """Timestamp. - - Unit of measurement: `None` - - ISO8601 format: https://en.wikipedia.org/wiki/ISO_8601 - """ - - # Numerical device classes, these should be aligned with NumberDeviceClass - APPARENT_POWER = "apparent_power" - """Apparent power. - - Unit of measurement: `VA` - """ - - AQI = "aqi" - """Air Quality Index. - - Unit of measurement: `None` - """ - - ATMOSPHERIC_PRESSURE = "atmospheric_pressure" - """Atmospheric pressure. - - Unit of measurement: `UnitOfPressure` units - """ - - BATTERY = "battery" - """Percentage of battery that is left. - - Unit of measurement: `%` - """ - - CO = "carbon_monoxide" - """Carbon Monoxide gas concentration. - - Unit of measurement: `ppm` (parts per million) - """ - - CO2 = "carbon_dioxide" - """Carbon Dioxide gas concentration. - - Unit of measurement: `ppm` (parts per million) - """ - - CURRENT = "current" - """Current. - - Unit of measurement: `A`, `mA` - """ - - DATA_RATE = "data_rate" - """Data rate. - - Unit of measurement: UnitOfDataRate - """ - - DATA_SIZE = "data_size" - """Data size. - - Unit of measurement: UnitOfInformation - """ - - DISTANCE = "distance" - """Generic distance. - - Unit of measurement: `LENGTH_*` units - - SI /metric: `mm`, `cm`, `m`, `km` - - USCS / imperial: `in`, `ft`, `yd`, `mi` - """ - - ENERGY = "energy" - """Energy. - - Unit of measurement: `Wh`, `kWh`, `MWh`, `GJ` - """ - - FREQUENCY = "frequency" - """Frequency. - - Unit of measurement: `Hz`, `kHz`, `MHz`, `GHz` - """ - - GAS = "gas" - """Gas. - - Unit of measurement: - - SI / metric: `m³` - - USCS / imperial: `ft³`, `CCF` - """ - - HUMIDITY = "humidity" - """Relative humidity. - - Unit of measurement: `%` - """ - - ILLUMINANCE = "illuminance" - """Illuminance. - - Unit of measurement: `lx` - """ - - IRRADIANCE = "irradiance" - """Irradiance. - - Unit of measurement: - - SI / metric: `W/m²` - - USCS / imperial: `BTU/(h⋅ft²)` - """ - - MOISTURE = "moisture" - """Moisture. - - Unit of measurement: `%` - """ - - MONETARY = "monetary" - """Amount of money. - - Unit of measurement: ISO4217 currency code - - See https://en.wikipedia.org/wiki/ISO_4217#Active_codes for active codes - """ - - NITROGEN_DIOXIDE = "nitrogen_dioxide" - """Amount of NO2. - - Unit of measurement: `µg/m³` - """ - - NITROGEN_MONOXIDE = "nitrogen_monoxide" - """Amount of NO. - - Unit of measurement: `µg/m³` - """ - - NITROUS_OXIDE = "nitrous_oxide" - """Amount of N2O. - - Unit of measurement: `µg/m³` - """ - - OZONE = "ozone" - """Amount of O3. - - Unit of measurement: `µg/m³` - """ - - PM1 = "pm1" - """Particulate matter <= 0.1 μm. - - Unit of measurement: `µg/m³` - """ - - PM10 = "pm10" - """Particulate matter <= 10 μm. - - Unit of measurement: `µg/m³` - """ - - PM25 = "pm25" - """Particulate matter <= 2.5 μm. - - Unit of measurement: `µg/m³` - """ - - POWER_FACTOR = "power_factor" - """Power factor. - - Unit of measurement: `%` - """ - - POWER = "power" - """Power. - - Unit of measurement: `W`, `kW` - """ - - PRECIPITATION = "precipitation" - """Precipitation. - - Unit of measurement: UnitOfPrecipitationDepth - - SI / metric: `cm`, `mm` - - USCS / imperial: `in` - """ - - PRECIPITATION_INTENSITY = "precipitation_intensity" - """Precipitation intensity. - - Unit of measurement: UnitOfVolumetricFlux - - SI /metric: `mm/d`, `mm/h` - - USCS / imperial: `in/d`, `in/h` - """ - - PRESSURE = "pressure" - """Pressure. - - Unit of measurement: - - `mbar`, `cbar`, `bar` - - `Pa`, `hPa`, `kPa` - - `inHg` - - `psi` - """ - - REACTIVE_POWER = "reactive_power" - """Reactive power. - - Unit of measurement: `var` - """ - - SIGNAL_STRENGTH = "signal_strength" - """Signal strength. - - Unit of measurement: `dB`, `dBm` - """ - - SOUND_PRESSURE = "sound_pressure" - """Sound pressure. - - Unit of measurement: `dB`, `dBA` - """ - - SPEED = "speed" - """Generic speed. - - Unit of measurement: `SPEED_*` units or `UnitOfVolumetricFlux` - - SI /metric: `mm/d`, `mm/h`, `m/s`, `km/h` - - USCS / imperial: `in/d`, `in/h`, `ft/s`, `mph` - - Nautical: `kn` - """ - - SULPHUR_DIOXIDE = "sulphur_dioxide" - """Amount of SO2. - - Unit of measurement: `µg/m³` - """ - - TEMPERATURE = "temperature" - """Temperature. - - Unit of measurement: `°C`, `°F` - """ - - VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds" - """Amount of VOC. - - Unit of measurement: `µg/m³` - """ - - VOLTAGE = "voltage" - """Voltage. - - Unit of measurement: `V`, `mV` - """ - - VOLUME = "volume" - """Generic volume. - - Unit of measurement: `VOLUME_*` units - - SI / metric: `mL`, `L`, `m³` - - USCS / imperial: `ft³`, `CCF`, `fl. oz.`, `gal` (warning: volumes expressed in - USCS/imperial units are currently assumed to be US volumes) - """ - - WATER = "water" - """Water. - - Unit of measurement: - - SI / metric: `m³`, `L` - - USCS / imperial: `ft³`, `CCF`, `gal` (warning: volumes expressed in - USCS/imperial units are currently assumed to be US volumes) - """ - - WEIGHT = "weight" - """Generic weight, represents a measurement of an object's mass. - - Weight is used instead of mass to fit with every day language. - - Unit of measurement: `MASS_*` units - - SI / metric: `µg`, `mg`, `g`, `kg` - - USCS / imperial: `oz`, `lb` - """ - - WIND_SPEED = "wind_speed" - """Wind speed. - - Unit of measurement: `SPEED_*` units - - SI /metric: `m/s`, `km/h` - - USCS / imperial: `ft/s`, `mph` - - Nautical: `kn` - """ - - -DEVICE_CLASSES_SCHEMA: Final = vol.All(vol.Lower, vol.Coerce(SensorDeviceClass)) - -# DEVICE_CLASSES is deprecated as of 2021.12 -# use the SensorDeviceClass enum instead. -DEVICE_CLASSES: Final[list[str]] = [cls.value for cls in SensorDeviceClass] - - -class SensorStateClass(StrEnum): - """State class for sensors.""" - - MEASUREMENT = "measurement" - """The state represents a measurement in present time.""" - - TOTAL = "total" - """The state represents a total amount. - - For example: net energy consumption""" - - TOTAL_INCREASING = "total_increasing" - """The state represents a monotonically increasing total. - - For example: an amount of consumed gas""" - - -STATE_CLASSES_SCHEMA: Final = vol.All(vol.Lower, vol.Coerce(SensorStateClass)) - - -# STATE_CLASS* is deprecated as of 2021.12 -# use the SensorStateClass enum instead. -STATE_CLASS_MEASUREMENT: Final = "measurement" -STATE_CLASS_TOTAL: Final = "total" -STATE_CLASS_TOTAL_INCREASING: Final = "total_increasing" -STATE_CLASSES: Final[list[str]] = [cls.value for cls in SensorStateClass] - -# Note: this needs to be aligned with frontend: OVERRIDE_SENSOR_UNITS in -# `entity-registry-settings.ts` -UNIT_CONVERTERS: dict[SensorDeviceClass | str | None, type[BaseUnitConverter]] = { - SensorDeviceClass.DATA_RATE: DataRateConverter, - SensorDeviceClass.DATA_SIZE: InformationConverter, - SensorDeviceClass.DISTANCE: DistanceConverter, - SensorDeviceClass.CURRENT: ElectricCurrentConverter, - SensorDeviceClass.GAS: VolumeConverter, - SensorDeviceClass.PRECIPITATION: DistanceConverter, - SensorDeviceClass.PRESSURE: PressureConverter, - SensorDeviceClass.SPEED: SpeedConverter, - SensorDeviceClass.TEMPERATURE: TemperatureConverter, - SensorDeviceClass.VOLTAGE: ElectricPotentialConverter, - SensorDeviceClass.VOLUME: VolumeConverter, - SensorDeviceClass.WATER: VolumeConverter, - SensorDeviceClass.WEIGHT: MassConverter, - SensorDeviceClass.WIND_SPEED: SpeedConverter, -} - -DEVICE_CLASS_UNITS: dict[SensorDeviceClass, set[type[StrEnum] | str | None]] = { - SensorDeviceClass.APPARENT_POWER: set(UnitOfApparentPower), - SensorDeviceClass.AQI: {None}, - SensorDeviceClass.ATMOSPHERIC_PRESSURE: set(UnitOfPressure), - SensorDeviceClass.BATTERY: {PERCENTAGE}, - SensorDeviceClass.CO: {CONCENTRATION_PARTS_PER_MILLION}, - SensorDeviceClass.CO2: {CONCENTRATION_PARTS_PER_MILLION}, - SensorDeviceClass.CURRENT: set(UnitOfElectricCurrent), - SensorDeviceClass.DATA_RATE: set(UnitOfDataRate), - SensorDeviceClass.DATA_SIZE: set(UnitOfInformation), - SensorDeviceClass.DISTANCE: set(UnitOfLength), - SensorDeviceClass.DURATION: { - UnitOfTime.DAYS, - UnitOfTime.HOURS, - UnitOfTime.MINUTES, - UnitOfTime.SECONDS, - }, - SensorDeviceClass.ENERGY: set(UnitOfEnergy), - SensorDeviceClass.FREQUENCY: set(UnitOfFrequency), - SensorDeviceClass.GAS: { - UnitOfVolume.CENTUM_CUBIC_FEET, - UnitOfVolume.CUBIC_FEET, - UnitOfVolume.CUBIC_METERS, - }, - SensorDeviceClass.HUMIDITY: {PERCENTAGE}, - SensorDeviceClass.ILLUMINANCE: {LIGHT_LUX}, - SensorDeviceClass.IRRADIANCE: set(UnitOfIrradiance), - SensorDeviceClass.MOISTURE: {PERCENTAGE}, - SensorDeviceClass.NITROGEN_DIOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, - SensorDeviceClass.NITROGEN_MONOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, - SensorDeviceClass.NITROUS_OXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, - SensorDeviceClass.OZONE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, - SensorDeviceClass.PM1: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, - SensorDeviceClass.PM10: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, - SensorDeviceClass.PM25: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, - SensorDeviceClass.POWER_FACTOR: {PERCENTAGE}, - SensorDeviceClass.POWER: {UnitOfPower.WATT, UnitOfPower.KILO_WATT}, - SensorDeviceClass.PRECIPITATION: set(UnitOfPrecipitationDepth), - SensorDeviceClass.PRECIPITATION_INTENSITY: set(UnitOfVolumetricFlux), - SensorDeviceClass.PRESSURE: set(UnitOfPressure), - SensorDeviceClass.REACTIVE_POWER: {POWER_VOLT_AMPERE_REACTIVE}, - SensorDeviceClass.SIGNAL_STRENGTH: { - SIGNAL_STRENGTH_DECIBELS, - SIGNAL_STRENGTH_DECIBELS_MILLIWATT, - }, - SensorDeviceClass.SOUND_PRESSURE: set(UnitOfSoundPressure), - SensorDeviceClass.SPEED: set(UnitOfSpeed).union(set(UnitOfVolumetricFlux)), - SensorDeviceClass.SULPHUR_DIOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, - SensorDeviceClass.TEMPERATURE: { - UnitOfTemperature.CELSIUS, - UnitOfTemperature.FAHRENHEIT, - }, - SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS: { - CONCENTRATION_MICROGRAMS_PER_CUBIC_METER - }, - SensorDeviceClass.VOLTAGE: set(UnitOfElectricPotential), - SensorDeviceClass.VOLUME: set(UnitOfVolume), - SensorDeviceClass.WATER: { - UnitOfVolume.CENTUM_CUBIC_FEET, - UnitOfVolume.CUBIC_FEET, - UnitOfVolume.CUBIC_METERS, - UnitOfVolume.GALLONS, - UnitOfVolume.LITERS, - }, - SensorDeviceClass.WEIGHT: set(UnitOfMass), - SensorDeviceClass.WIND_SPEED: set(UnitOfSpeed), -} +__all__ = [ + "ATTR_LAST_RESET", + "ATTR_OPTIONS", + "ATTR_STATE_CLASS", + "CONF_STATE_CLASS", + "DOMAIN", + "PLATFORM_SCHEMA_BASE", + "PLATFORM_SCHEMA", + "RestoreSensor", + "SensorDeviceClass", + "SensorEntity", + "SensorEntityDescription", + "SensorExtraStoredData", + "SensorStateClass", +] # mypy: disallow-any-generics @@ -837,7 +381,7 @@ def unit_of_measurement(self) -> str | None: native_unit_of_measurement = self.native_unit_of_measurement if ( - self.device_class == DEVICE_CLASS_TEMPERATURE + self.device_class == SensorDeviceClass.TEMPERATURE and native_unit_of_measurement in {UnitOfTemperature.CELSIUS, UnitOfTemperature.FAHRENHEIT} ): @@ -856,7 +400,7 @@ def state(self) -> Any: device_class = self.device_class # Received a datetime - if value is not None and device_class == DEVICE_CLASS_TIMESTAMP: + if value is not None and device_class == SensorDeviceClass.TIMESTAMP: try: # We cast the value, to avoid using isinstance, but satisfy # typechecking. The errors are guarded in this try. @@ -878,7 +422,7 @@ def state(self) -> Any: ) from err # Received a date value - if value is not None and device_class == DEVICE_CLASS_DATE: + if value is not None and device_class == SensorDeviceClass.DATE: try: # We cast the value, to avoid using isinstance, but satisfy # typechecking. The errors are guarded in this try. diff --git a/homeassistant/components/sensor/const.py b/homeassistant/components/sensor/const.py index 54d683242ea10c..239cb36cf6e605 100644 --- a/homeassistant/components/sensor/const.py +++ b/homeassistant/components/sensor/const.py @@ -1,4 +1,499 @@ """Constants for sensor.""" +from __future__ import annotations + from typing import Final +import voluptuous as vol + +from homeassistant.backports.enum import StrEnum +from homeassistant.const import ( + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + CONCENTRATION_PARTS_PER_MILLION, + LIGHT_LUX, + PERCENTAGE, + POWER_VOLT_AMPERE_REACTIVE, + SIGNAL_STRENGTH_DECIBELS, + SIGNAL_STRENGTH_DECIBELS_MILLIWATT, + UnitOfApparentPower, + UnitOfDataRate, + UnitOfElectricCurrent, + UnitOfElectricPotential, + UnitOfEnergy, + UnitOfFrequency, + UnitOfInformation, + UnitOfIrradiance, + UnitOfLength, + UnitOfMass, + UnitOfPower, + UnitOfPrecipitationDepth, + UnitOfPressure, + UnitOfSoundPressure, + UnitOfSpeed, + UnitOfTemperature, + UnitOfTime, + UnitOfVolume, + UnitOfVolumetricFlux, +) +from homeassistant.util.unit_conversion import ( + BaseUnitConverter, + DataRateConverter, + DistanceConverter, + ElectricCurrentConverter, + ElectricPotentialConverter, + InformationConverter, + MassConverter, + PressureConverter, + SpeedConverter, + TemperatureConverter, + VolumeConverter, +) + +DOMAIN: Final = "sensor" + CONF_STATE_CLASS: Final = "state_class" + +ATTR_LAST_RESET: Final = "last_reset" +ATTR_STATE_CLASS: Final = "state_class" +ATTR_OPTIONS: Final = "options" + + +class SensorDeviceClass(StrEnum): + """Device class for sensors.""" + + # Non-numerical device classes + DATE = "date" + """Date. + + Unit of measurement: `None` + + ISO8601 format: https://en.wikipedia.org/wiki/ISO_8601 + """ + + DURATION = "duration" + """Fixed duration. + + Unit of measurement: `d`, `h`, `min`, `s` + """ + + ENUM = "enum" + """Enumeration. + + Provides a fixed list of options the state of the sensor can be in. + + Unit of measurement: `None` + """ + + TIMESTAMP = "timestamp" + """Timestamp. + + Unit of measurement: `None` + + ISO8601 format: https://en.wikipedia.org/wiki/ISO_8601 + """ + + # Numerical device classes, these should be aligned with NumberDeviceClass + APPARENT_POWER = "apparent_power" + """Apparent power. + + Unit of measurement: `VA` + """ + + AQI = "aqi" + """Air Quality Index. + + Unit of measurement: `None` + """ + + ATMOSPHERIC_PRESSURE = "atmospheric_pressure" + """Atmospheric pressure. + + Unit of measurement: `UnitOfPressure` units + """ + + BATTERY = "battery" + """Percentage of battery that is left. + + Unit of measurement: `%` + """ + + CO = "carbon_monoxide" + """Carbon Monoxide gas concentration. + + Unit of measurement: `ppm` (parts per million) + """ + + CO2 = "carbon_dioxide" + """Carbon Dioxide gas concentration. + + Unit of measurement: `ppm` (parts per million) + """ + + CURRENT = "current" + """Current. + + Unit of measurement: `A`, `mA` + """ + + DATA_RATE = "data_rate" + """Data rate. + + Unit of measurement: UnitOfDataRate + """ + + DATA_SIZE = "data_size" + """Data size. + + Unit of measurement: UnitOfInformation + """ + + DISTANCE = "distance" + """Generic distance. + + Unit of measurement: `LENGTH_*` units + - SI /metric: `mm`, `cm`, `m`, `km` + - USCS / imperial: `in`, `ft`, `yd`, `mi` + """ + + ENERGY = "energy" + """Energy. + + Unit of measurement: `Wh`, `kWh`, `MWh`, `GJ` + """ + + FREQUENCY = "frequency" + """Frequency. + + Unit of measurement: `Hz`, `kHz`, `MHz`, `GHz` + """ + + GAS = "gas" + """Gas. + + Unit of measurement: + - SI / metric: `m³` + - USCS / imperial: `ft³`, `CCF` + """ + + HUMIDITY = "humidity" + """Relative humidity. + + Unit of measurement: `%` + """ + + ILLUMINANCE = "illuminance" + """Illuminance. + + Unit of measurement: `lx` + """ + + IRRADIANCE = "irradiance" + """Irradiance. + + Unit of measurement: + - SI / metric: `W/m²` + - USCS / imperial: `BTU/(h⋅ft²)` + """ + + MOISTURE = "moisture" + """Moisture. + + Unit of measurement: `%` + """ + + MONETARY = "monetary" + """Amount of money. + + Unit of measurement: ISO4217 currency code + + See https://en.wikipedia.org/wiki/ISO_4217#Active_codes for active codes + """ + + NITROGEN_DIOXIDE = "nitrogen_dioxide" + """Amount of NO2. + + Unit of measurement: `µg/m³` + """ + + NITROGEN_MONOXIDE = "nitrogen_monoxide" + """Amount of NO. + + Unit of measurement: `µg/m³` + """ + + NITROUS_OXIDE = "nitrous_oxide" + """Amount of N2O. + + Unit of measurement: `µg/m³` + """ + + OZONE = "ozone" + """Amount of O3. + + Unit of measurement: `µg/m³` + """ + + PM1 = "pm1" + """Particulate matter <= 0.1 μm. + + Unit of measurement: `µg/m³` + """ + + PM10 = "pm10" + """Particulate matter <= 10 μm. + + Unit of measurement: `µg/m³` + """ + + PM25 = "pm25" + """Particulate matter <= 2.5 μm. + + Unit of measurement: `µg/m³` + """ + + POWER_FACTOR = "power_factor" + """Power factor. + + Unit of measurement: `%` + """ + + POWER = "power" + """Power. + + Unit of measurement: `W`, `kW` + """ + + PRECIPITATION = "precipitation" + """Precipitation. + + Unit of measurement: UnitOfPrecipitationDepth + - SI / metric: `cm`, `mm` + - USCS / imperial: `in` + """ + + PRECIPITATION_INTENSITY = "precipitation_intensity" + """Precipitation intensity. + + Unit of measurement: UnitOfVolumetricFlux + - SI /metric: `mm/d`, `mm/h` + - USCS / imperial: `in/d`, `in/h` + """ + + PRESSURE = "pressure" + """Pressure. + + Unit of measurement: + - `mbar`, `cbar`, `bar` + - `Pa`, `hPa`, `kPa` + - `inHg` + - `psi` + """ + + REACTIVE_POWER = "reactive_power" + """Reactive power. + + Unit of measurement: `var` + """ + + SIGNAL_STRENGTH = "signal_strength" + """Signal strength. + + Unit of measurement: `dB`, `dBm` + """ + + SOUND_PRESSURE = "sound_pressure" + """Sound pressure. + + Unit of measurement: `dB`, `dBA` + """ + + SPEED = "speed" + """Generic speed. + + Unit of measurement: `SPEED_*` units or `UnitOfVolumetricFlux` + - SI /metric: `mm/d`, `mm/h`, `m/s`, `km/h` + - USCS / imperial: `in/d`, `in/h`, `ft/s`, `mph` + - Nautical: `kn` + """ + + SULPHUR_DIOXIDE = "sulphur_dioxide" + """Amount of SO2. + + Unit of measurement: `µg/m³` + """ + + TEMPERATURE = "temperature" + """Temperature. + + Unit of measurement: `°C`, `°F` + """ + + VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds" + """Amount of VOC. + + Unit of measurement: `µg/m³` + """ + + VOLTAGE = "voltage" + """Voltage. + + Unit of measurement: `V`, `mV` + """ + + VOLUME = "volume" + """Generic volume. + + Unit of measurement: `VOLUME_*` units + - SI / metric: `mL`, `L`, `m³` + - USCS / imperial: `ft³`, `CCF`, `fl. oz.`, `gal` (warning: volumes expressed in + USCS/imperial units are currently assumed to be US volumes) + """ + + WATER = "water" + """Water. + + Unit of measurement: + - SI / metric: `m³`, `L` + - USCS / imperial: `ft³`, `CCF`, `gal` (warning: volumes expressed in + USCS/imperial units are currently assumed to be US volumes) + """ + + WEIGHT = "weight" + """Generic weight, represents a measurement of an object's mass. + + Weight is used instead of mass to fit with every day language. + + Unit of measurement: `MASS_*` units + - SI / metric: `µg`, `mg`, `g`, `kg` + - USCS / imperial: `oz`, `lb` + """ + + WIND_SPEED = "wind_speed" + """Wind speed. + + Unit of measurement: `SPEED_*` units + - SI /metric: `m/s`, `km/h` + - USCS / imperial: `ft/s`, `mph` + - Nautical: `kn` + """ + + +DEVICE_CLASSES_SCHEMA: Final = vol.All(vol.Lower, vol.Coerce(SensorDeviceClass)) + +# DEVICE_CLASSES is deprecated as of 2021.12 +# use the SensorDeviceClass enum instead. +DEVICE_CLASSES: Final[list[str]] = [cls.value for cls in SensorDeviceClass] + + +class SensorStateClass(StrEnum): + """State class for sensors.""" + + MEASUREMENT = "measurement" + """The state represents a measurement in present time.""" + + TOTAL = "total" + """The state represents a total amount. + + For example: net energy consumption""" + + TOTAL_INCREASING = "total_increasing" + """The state represents a monotonically increasing total. + + For example: an amount of consumed gas""" + + +STATE_CLASSES_SCHEMA: Final = vol.All(vol.Lower, vol.Coerce(SensorStateClass)) + + +# STATE_CLASS* is deprecated as of 2021.12 +# use the SensorStateClass enum instead. +STATE_CLASS_MEASUREMENT: Final = "measurement" +STATE_CLASS_TOTAL: Final = "total" +STATE_CLASS_TOTAL_INCREASING: Final = "total_increasing" +STATE_CLASSES: Final[list[str]] = [cls.value for cls in SensorStateClass] + +# Note: this needs to be aligned with frontend: OVERRIDE_SENSOR_UNITS in +# `entity-registry-settings.ts` +UNIT_CONVERTERS: dict[SensorDeviceClass | str | None, type[BaseUnitConverter]] = { + SensorDeviceClass.DATA_RATE: DataRateConverter, + SensorDeviceClass.DATA_SIZE: InformationConverter, + SensorDeviceClass.DISTANCE: DistanceConverter, + SensorDeviceClass.CURRENT: ElectricCurrentConverter, + SensorDeviceClass.GAS: VolumeConverter, + SensorDeviceClass.PRECIPITATION: DistanceConverter, + SensorDeviceClass.PRESSURE: PressureConverter, + SensorDeviceClass.SPEED: SpeedConverter, + SensorDeviceClass.TEMPERATURE: TemperatureConverter, + SensorDeviceClass.VOLTAGE: ElectricPotentialConverter, + SensorDeviceClass.VOLUME: VolumeConverter, + SensorDeviceClass.WATER: VolumeConverter, + SensorDeviceClass.WEIGHT: MassConverter, + SensorDeviceClass.WIND_SPEED: SpeedConverter, +} + +DEVICE_CLASS_UNITS: dict[SensorDeviceClass, set[type[StrEnum] | str | None]] = { + SensorDeviceClass.APPARENT_POWER: set(UnitOfApparentPower), + SensorDeviceClass.AQI: {None}, + SensorDeviceClass.ATMOSPHERIC_PRESSURE: set(UnitOfPressure), + SensorDeviceClass.BATTERY: {PERCENTAGE}, + SensorDeviceClass.CO: {CONCENTRATION_PARTS_PER_MILLION}, + SensorDeviceClass.CO2: {CONCENTRATION_PARTS_PER_MILLION}, + SensorDeviceClass.CURRENT: set(UnitOfElectricCurrent), + SensorDeviceClass.DATA_RATE: set(UnitOfDataRate), + SensorDeviceClass.DATA_SIZE: set(UnitOfInformation), + SensorDeviceClass.DISTANCE: set(UnitOfLength), + SensorDeviceClass.DURATION: { + UnitOfTime.DAYS, + UnitOfTime.HOURS, + UnitOfTime.MINUTES, + UnitOfTime.SECONDS, + }, + SensorDeviceClass.ENERGY: set(UnitOfEnergy), + SensorDeviceClass.FREQUENCY: set(UnitOfFrequency), + SensorDeviceClass.GAS: { + UnitOfVolume.CENTUM_CUBIC_FEET, + UnitOfVolume.CUBIC_FEET, + UnitOfVolume.CUBIC_METERS, + }, + SensorDeviceClass.HUMIDITY: {PERCENTAGE}, + SensorDeviceClass.ILLUMINANCE: {LIGHT_LUX}, + SensorDeviceClass.IRRADIANCE: set(UnitOfIrradiance), + SensorDeviceClass.MOISTURE: {PERCENTAGE}, + SensorDeviceClass.NITROGEN_DIOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + SensorDeviceClass.NITROGEN_MONOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + SensorDeviceClass.NITROUS_OXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + SensorDeviceClass.OZONE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + SensorDeviceClass.PM1: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + SensorDeviceClass.PM10: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + SensorDeviceClass.PM25: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + SensorDeviceClass.POWER_FACTOR: {PERCENTAGE}, + SensorDeviceClass.POWER: {UnitOfPower.WATT, UnitOfPower.KILO_WATT}, + SensorDeviceClass.PRECIPITATION: set(UnitOfPrecipitationDepth), + SensorDeviceClass.PRECIPITATION_INTENSITY: set(UnitOfVolumetricFlux), + SensorDeviceClass.PRESSURE: set(UnitOfPressure), + SensorDeviceClass.REACTIVE_POWER: {POWER_VOLT_AMPERE_REACTIVE}, + SensorDeviceClass.SIGNAL_STRENGTH: { + SIGNAL_STRENGTH_DECIBELS, + SIGNAL_STRENGTH_DECIBELS_MILLIWATT, + }, + SensorDeviceClass.SOUND_PRESSURE: set(UnitOfSoundPressure), + SensorDeviceClass.SPEED: set(UnitOfSpeed).union(set(UnitOfVolumetricFlux)), + SensorDeviceClass.SULPHUR_DIOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + SensorDeviceClass.TEMPERATURE: { + UnitOfTemperature.CELSIUS, + UnitOfTemperature.FAHRENHEIT, + }, + SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS: { + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER + }, + SensorDeviceClass.VOLTAGE: set(UnitOfElectricPotential), + SensorDeviceClass.VOLUME: set(UnitOfVolume), + SensorDeviceClass.WATER: { + UnitOfVolume.CENTUM_CUBIC_FEET, + UnitOfVolume.CUBIC_FEET, + UnitOfVolume.CUBIC_METERS, + UnitOfVolume.GALLONS, + UnitOfVolume.LITERS, + }, + SensorDeviceClass.WEIGHT: set(UnitOfMass), + SensorDeviceClass.WIND_SPEED: set(UnitOfSpeed), +}