diff --git a/homeassistant/components/demo/sensor.py b/homeassistant/components/demo/sensor.py index 413017ad2f1..ec9cc648e1a 100644 --- a/homeassistant/components/demo/sensor.py +++ b/homeassistant/components/demo/sensor.py @@ -3,17 +3,15 @@ from __future__ import annotations from typing import Any -from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT, SensorEntity +from homeassistant.components.sensor import ( + STATE_CLASS_MEASUREMENT, + SensorDeviceClass, + SensorEntity, +) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_BATTERY_LEVEL, CONCENTRATION_PARTS_PER_MILLION, - DEVICE_CLASS_CO, - DEVICE_CLASS_CO2, - DEVICE_CLASS_ENERGY, - DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_POWER, - DEVICE_CLASS_TEMPERATURE, ENERGY_KILO_WATT_HOUR, PERCENTAGE, POWER_WATT, @@ -40,7 +38,7 @@ async def async_setup_platform( "sensor_1", "Outside Temperature", 15.6, - DEVICE_CLASS_TEMPERATURE, + SensorDeviceClass.TEMPERATURE, STATE_CLASS_MEASUREMENT, TEMP_CELSIUS, 12, @@ -49,7 +47,7 @@ async def async_setup_platform( "sensor_2", "Outside Humidity", 54, - DEVICE_CLASS_HUMIDITY, + SensorDeviceClass.HUMIDITY, STATE_CLASS_MEASUREMENT, PERCENTAGE, None, @@ -58,7 +56,7 @@ async def async_setup_platform( "sensor_3", "Carbon monoxide", 54, - DEVICE_CLASS_CO, + SensorDeviceClass.CO, STATE_CLASS_MEASUREMENT, CONCENTRATION_PARTS_PER_MILLION, None, @@ -67,7 +65,7 @@ async def async_setup_platform( "sensor_4", "Carbon dioxide", 54, - DEVICE_CLASS_CO2, + SensorDeviceClass.CO2, STATE_CLASS_MEASUREMENT, CONCENTRATION_PARTS_PER_MILLION, 14, @@ -76,7 +74,7 @@ async def async_setup_platform( "sensor_5", "Power consumption", 100, - DEVICE_CLASS_POWER, + SensorDeviceClass.POWER, STATE_CLASS_MEASUREMENT, POWER_WATT, None, @@ -85,7 +83,7 @@ async def async_setup_platform( "sensor_6", "Today energy", 15, - DEVICE_CLASS_ENERGY, + SensorDeviceClass.ENERGY, STATE_CLASS_MEASUREMENT, ENERGY_KILO_WATT_HOUR, None, @@ -113,7 +111,7 @@ class DemoSensor(SensorEntity): unique_id: str, name: str, state: StateType, - device_class: str | None, + device_class: SensorDeviceClass, state_class: str | None, unit_of_measurement: str | None, battery: StateType, diff --git a/homeassistant/components/sensor/__init__.py b/homeassistant/components/sensor/__init__.py index b91b4b3051e..3abe4371bfe 100644 --- a/homeassistant/components/sensor/__init__.py +++ b/homeassistant/components/sensor/__init__.py @@ -13,7 +13,7 @@ import ciso8601 import voluptuous as vol from homeassistant.config_entries import ConfigEntry -from homeassistant.const import ( +from homeassistant.const import ( # noqa: F401 DEVICE_CLASS_AQI, DEVICE_CLASS_BATTERY, DEVICE_CLASS_CO, @@ -53,6 +53,7 @@ from homeassistant.helpers.config_validation import ( # noqa: F401 from homeassistant.helpers.entity import Entity, EntityDescription from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.typing import ConfigType, StateType +from homeassistant.util.enum import StrEnum from .const import CONF_STATE_CLASS # noqa: F401 @@ -66,38 +67,101 @@ DOMAIN: Final = "sensor" ENTITY_ID_FORMAT: Final = DOMAIN + ".{}" SCAN_INTERVAL: Final = timedelta(seconds=30) -DEVICE_CLASSES: Final[list[str]] = [ - DEVICE_CLASS_AQI, # Air Quality Index - DEVICE_CLASS_BATTERY, # % of battery that is left - DEVICE_CLASS_CO, # ppm (parts per million) Carbon Monoxide gas concentration - DEVICE_CLASS_CO2, # ppm (parts per million) Carbon Dioxide gas concentration - DEVICE_CLASS_CURRENT, # current (A) - DEVICE_CLASS_DATE, # date (ISO8601) - DEVICE_CLASS_ENERGY, # energy (kWh, Wh) - DEVICE_CLASS_FREQUENCY, # frequency (Hz, kHz, MHz, GHz) - DEVICE_CLASS_HUMIDITY, # % of humidity in the air - DEVICE_CLASS_ILLUMINANCE, # current light level (lx/lm) - DEVICE_CLASS_MONETARY, # Amount of money (currency) - DEVICE_CLASS_OZONE, # Amount of O3 (µg/m³) - DEVICE_CLASS_NITROGEN_DIOXIDE, # Amount of NO2 (µg/m³) - DEVICE_CLASS_NITROUS_OXIDE, # Amount of N2O (µg/m³) - DEVICE_CLASS_NITROGEN_MONOXIDE, # Amount of NO (µg/m³) - DEVICE_CLASS_PM1, # Particulate matter <= 0.1 μm (µg/m³) - DEVICE_CLASS_PM10, # Particulate matter <= 10 μm (µg/m³) - DEVICE_CLASS_PM25, # Particulate matter <= 2.5 μm (µg/m³) - DEVICE_CLASS_SIGNAL_STRENGTH, # signal strength (dB/dBm) - DEVICE_CLASS_SULPHUR_DIOXIDE, # Amount of SO2 (µg/m³) - DEVICE_CLASS_TEMPERATURE, # temperature (C/F) - DEVICE_CLASS_TIMESTAMP, # timestamp (ISO8601) - DEVICE_CLASS_PRESSURE, # pressure (hPa/mbar) - DEVICE_CLASS_POWER, # power (W/kW) - DEVICE_CLASS_POWER_FACTOR, # power factor (%) - DEVICE_CLASS_VOLTAGE, # voltage (V) - DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, # Amount of VOC (µg/m³) - DEVICE_CLASS_GAS, # gas (m³ or ft³) -] -DEVICE_CLASSES_SCHEMA: Final = vol.All(vol.Lower, vol.In(DEVICE_CLASSES)) + +class SensorDeviceClass(StrEnum): + """Device class for sensors.""" + + # Air Quality Index + AQI = "aqi" + + # % of battery that is left + BATTERY = "battery" + + # ppm (parts per million) Carbon Monoxide gas concentration + CO = "carbon_monoxide" + + # ppm (parts per million) Carbon Dioxide gas concentration + CO2 = "carbon_dioxide" + + # current (A) + CURRENT = "current" + + # date (ISO8601) + DATE = "date" + + # energy (kWh, Wh) + ENERGY = "energy" + + # frequency (Hz, kHz, MHz, GHz) + FREQUENCY = "frequency" + + # gas (m³ or ft³) + GAS = "gas" + + # % of humidity in the air + HUMIDITY = "humidity" + + # current light level (lx/lm) + ILLUMINANCE = "illuminance" + + # Amount of money (currency) + MONETARY = "monetary" + + # Amount of NO2 (µg/m³) + NITROGEN_DIOXIDE = "nitrogen_dioxide" + + # Amount of NO (µg/m³) + NITROGEN_MONOXIDE = "nitrogen_monoxide" + + # Amount of N2O (µg/m³) + NITROUS_OXIDE = "nitrous_oxide" + + # Amount of O3 (µg/m³) + OZONE = "ozone" + + # Particulate matter <= 0.1 μm (µg/m³) + PM1 = "pm1" + + # Particulate matter <= 10 μm (µg/m³) + PM10 = "pm10" + + # Particulate matter <= 2.5 μm (µg/m³) + PM25 = "pm25" + + # power factor (%) + POWER_FACTOR = "power_factor" + + # power (W/kW) + POWER = "power" + + # pressure (hPa/mbar) + PRESSURE = "pressure" + + # signal strength (dB/dBm) + SIGNAL_STRENGTH = "signal_strength" + + # Amount of SO2 (µg/m³) + SULPHUR_DIOXIDE = "sulphur_dioxide" + + # temperature (C/F) + TEMPERATURE = "temperature" + + # timestamp (ISO8601) + TIMESTAMP = "timestamp" + + # Amount of VOC (µg/m³) + VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds" + + # voltage (V) + VOLTAGE = "voltage" + + +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] # The state represents a measurement in present time STATE_CLASS_MEASUREMENT: Final = "measurement" @@ -141,6 +205,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: class SensorEntityDescription(EntityDescription): """A class that describes sensor entities.""" + device_class: SensorDeviceClass | str | None = None last_reset: datetime | None = None # Deprecated, to be removed in 2021.11 native_unit_of_measurement: str | None = None state_class: str | None = None @@ -172,6 +237,7 @@ class SensorEntity(Entity): """Base class for sensor entities.""" entity_description: SensorEntityDescription + _attr_device_class: SensorDeviceClass | str | None _attr_last_reset: datetime | None # Deprecated, to be removed in 2021.11 _attr_native_unit_of_measurement: str | None _attr_native_value: StateType | date | datetime = None @@ -186,6 +252,15 @@ class SensorEntity(Entity): # Temporary private attribute to track if deprecation has been logged. __datetime_as_string_deprecation_logged = False + @property + def device_class(self) -> SensorDeviceClass | str | None: + """Return the class of this entity.""" + if hasattr(self, "_attr_device_class"): + return self._attr_device_class + if hasattr(self, "entity_description"): + return self.entity_description.device_class + return None + @property def state_class(self) -> str | None: """Return the state class of this entity, from STATE_CLASSES, if any.""" diff --git a/homeassistant/const.py b/homeassistant/const.py index 45a88e2fe43..2ed777c12af 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -233,6 +233,8 @@ EVENT_TIME_CHANGED: Final = "time_changed" # #### DEVICE CLASSES #### +# DEVICE_CLASS_* below are deprecated as of 2021.12 +# use the SensorDeviceClass enum instead. DEVICE_CLASS_AQI: Final = "aqi" DEVICE_CLASS_BATTERY: Final = "battery" DEVICE_CLASS_CO: Final = "carbon_monoxide" @@ -241,6 +243,7 @@ DEVICE_CLASS_CURRENT: Final = "current" DEVICE_CLASS_DATE: Final = "date" DEVICE_CLASS_ENERGY: Final = "energy" DEVICE_CLASS_FREQUENCY: Final = "frequency" +DEVICE_CLASS_GAS: Final = "gas" DEVICE_CLASS_HUMIDITY: Final = "humidity" DEVICE_CLASS_ILLUMINANCE: Final = "illuminance" DEVICE_CLASS_MONETARY: Final = "monetary" @@ -248,19 +251,18 @@ DEVICE_CLASS_NITROGEN_DIOXIDE = "nitrogen_dioxide" DEVICE_CLASS_NITROGEN_MONOXIDE = "nitrogen_monoxide" DEVICE_CLASS_NITROUS_OXIDE = "nitrous_oxide" DEVICE_CLASS_OZONE: Final = "ozone" -DEVICE_CLASS_POWER_FACTOR: Final = "power_factor" -DEVICE_CLASS_POWER: Final = "power" -DEVICE_CLASS_PM25: Final = "pm25" DEVICE_CLASS_PM1: Final = "pm1" DEVICE_CLASS_PM10: Final = "pm10" +DEVICE_CLASS_PM25: Final = "pm25" +DEVICE_CLASS_POWER_FACTOR: Final = "power_factor" +DEVICE_CLASS_POWER: Final = "power" DEVICE_CLASS_PRESSURE: Final = "pressure" DEVICE_CLASS_SIGNAL_STRENGTH: Final = "signal_strength" DEVICE_CLASS_SULPHUR_DIOXIDE = "sulphur_dioxide" DEVICE_CLASS_TEMPERATURE: Final = "temperature" DEVICE_CLASS_TIMESTAMP: Final = "timestamp" -DEVICE_CLASS_VOLTAGE: Final = "voltage" DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds" -DEVICE_CLASS_GAS: Final = "gas" +DEVICE_CLASS_VOLTAGE: Final = "voltage" # #### STATES #### STATE_ON: Final = "on"