Files
Victor Alexandrovich Tsyrenschikov 373ed28445 python
2026-03-30 20:25:42 +05:00

915 lines
31 KiB
Python

"""Implement the Yandex Smart Home float properties."""
from abc import ABC, abstractmethod
from contextlib import suppress
from functools import cached_property
import logging
from typing import Protocol, Self
from homeassistant.components import air_quality, climate, fan, humidifier, light, sensor, switch, water_heater
from homeassistant.components.air_quality import ATTR_CO2, ATTR_PM_0_1, ATTR_PM_2_5, ATTR_PM_10
from homeassistant.components.climate import ATTR_CURRENT_HUMIDITY, ATTR_CURRENT_TEMPERATURE, ATTR_HUMIDITY
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.const import (
ATTR_BATTERY_LEVEL,
ATTR_TEMPERATURE,
ATTR_UNIT_OF_MEASUREMENT,
ATTR_VOLTAGE,
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
PERCENTAGE,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
UnitOfElectricCurrent,
UnitOfElectricPotential,
UnitOfEnergy,
UnitOfPower,
UnitOfVolume,
)
from homeassistant.util.unit_conversion import (
BaseUnitConverter,
ElectricCurrentConverter,
ElectricPotentialConverter,
EnergyConverter,
PowerConverter,
TemperatureConverter,
VolumeConverter,
)
from .const import (
ATTR_CURRENT,
ATTR_CURRENT_CONSUMPTION,
ATTR_ILLUMINANCE,
ATTR_LOAD_POWER,
ATTR_POWER,
ATTR_TVOC,
ATTR_WATER_LEVEL,
STATE_CHARGING,
STATE_EMPTY,
STATE_LOW,
STATE_NONE,
STATE_NONE_UI,
XGW3DeviceClass,
)
from .helpers import APIError
from .property import STATE_PROPERTIES_REGISTRY, Property, StateProperty
from .schema import (
AmperageFloatPropertyParameters,
BatteryLevelFloatPropertyParameters,
CO2LevelFloatPropertyParameters,
ElectricityMeterFloatPropertyParameters,
FloatPropertyDescription,
FloatPropertyInstance,
FloatPropertyParameters,
FoodLevelFloatPropertyParameters,
GasMeterFloatPropertyParameters,
HeatMeterFloatPropertyParameters,
HumidityFloatPropertyParameters,
IlluminationFloatPropertyParameters,
MeterFloatPropertyParameters,
PM1DensityFloatPropertyParameters,
PM10DensityFloatPropertyParameters,
PM25DensityFloatPropertyParameters,
PowerFloatPropertyParameters,
PressureFloatPropertyParameters,
PropertyType,
ResponseCode,
TemperatureFloatPropertyParameters,
TVOCFloatPropertyParameters,
VoltageFloatPropertyParameters,
WaterLevelFloatPropertyParameters,
WaterMeterFloatPropertyParameters,
)
from .unit_conversion import PressureConverter, TVOCConcentrationConverter, UnitOfPressure, UnitOfTemperature
_LOGGER = logging.getLogger(__name__)
class FloatProperty(Property, Protocol):
"""Base class for float properties (sensors)."""
type: PropertyType = PropertyType.FLOAT
instance: FloatPropertyInstance
@property
@abstractmethod
def parameters(self) -> FloatPropertyParameters:
"""Return parameters for a devices list request."""
...
def get_description(self) -> FloatPropertyDescription:
"""Return a description for a device list request."""
return FloatPropertyDescription(
retrievable=self.retrievable, reportable=self.reportable, parameters=self.parameters
)
def get_value(self) -> float | None:
"""Return the current property value."""
value = self._get_native_value()
if value is None:
return None
if str(value).lower() in (STATE_UNAVAILABLE, STATE_UNKNOWN, STATE_NONE, STATE_NONE_UI, STATE_EMPTY):
return None
try:
float_value = float(value)
except (ValueError, TypeError):
raise APIError(ResponseCode.NOT_SUPPORTED_IN_CURRENT_MODE, f"Unsupported value '{value}' for {self}")
if self._native_unit_of_measurement and self.unit_of_measurement and self._unit_converter:
if self._native_unit_of_measurement in self._unit_converter.VALID_UNITS:
float_value = self._unit_converter.convert(
float_value, self._native_unit_of_measurement, self.unit_of_measurement
)
else:
_LOGGER.warning(
f"Unsupported unit of measurement '{self._native_unit_of_measurement}' for {self}. "
f"Valid units are: %s" % ", ".join(sorted(map(str, self._unit_converter.VALID_UNITS)))
)
lower_limit, upper_limit = self.parameters.range
if lower_limit is not None and float_value < lower_limit:
return lower_limit
if upper_limit is not None and float_value > upper_limit:
return upper_limit
return round(float_value, 2)
def check_value_change(self, other: Self | None) -> bool:
"""Test if the property value differs from other property."""
if other is None:
return True
value, other_value = self.get_value(), other.get_value()
if value is None:
return False
if other_value is None or value != other_value:
return True
return False
@property
def unit_of_measurement(self) -> str | None:
"""Return the unit the property value is expressed in."""
return None
@abstractmethod
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
...
@cached_property
@abstractmethod
def _native_unit_of_measurement(self) -> str | None:
"""Return the unit the native value is expressed in."""
...
@property
def _unit_converter(self) -> BaseUnitConverter | None:
"""Return the unit converter."""
return None # pragma: nocover
class TemperatureProperty(FloatProperty, ABC):
"""Base class for temperature properties."""
instance = FloatPropertyInstance.TEMPERATURE
@property
def parameters(self) -> TemperatureFloatPropertyParameters:
"""Return parameters for a devices list request."""
return TemperatureFloatPropertyParameters(unit=self.unit_of_measurement.as_property_unit)
@property
def unit_of_measurement(self) -> UnitOfTemperature:
"""Return the unit the property value is expressed in."""
if self._native_unit_of_measurement:
with suppress(ValueError):
unit = UnitOfTemperature(self._native_unit_of_measurement)
if unit.as_property_unit:
return unit
return UnitOfTemperature.CELSIUS
@property
def _unit_converter(self) -> TemperatureConverter:
"""Return the unit converter."""
return TemperatureConverter()
class HumidityProperty(FloatProperty, ABC):
"""Base class for humidity properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.HUMIDITY
@property
def parameters(self) -> HumidityFloatPropertyParameters:
"""Return parameters for a devices list request."""
return HumidityFloatPropertyParameters()
class PressureProperty(FloatProperty, ABC):
"""Base class for pressure properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.PRESSURE
@property
def parameters(self) -> PressureFloatPropertyParameters:
"""Return parameters for a devices list request."""
return PressureFloatPropertyParameters(unit=self.unit_of_measurement.as_property_unit)
@property
def unit_of_measurement(self) -> UnitOfPressure:
"""Return the unit the property value is expressed in."""
if self._native_unit_of_measurement:
with suppress(ValueError):
unit = UnitOfPressure(self._native_unit_of_measurement)
if unit.as_property_unit:
return unit
return UnitOfPressure.MMHG
@property
def _unit_converter(self) -> PressureConverter:
"""Return the unit converter."""
return PressureConverter()
class IlluminationProperty(FloatProperty, ABC):
"""Base class for illumination properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.ILLUMINATION
@property
def parameters(self) -> IlluminationFloatPropertyParameters:
"""Return parameters for a devices list request."""
return IlluminationFloatPropertyParameters()
class FoodLevelPercentageProperty(FloatProperty, Protocol):
"""Base class for food level (%) properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.FOOD_LEVEL
@property
def parameters(self) -> FoodLevelFloatPropertyParameters:
"""Return parameters for a devices list request."""
return FoodLevelFloatPropertyParameters()
class WaterLevelPercentageProperty(FloatProperty, Protocol):
"""Base class for water level (%) properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.WATER_LEVEL
@property
def parameters(self) -> WaterLevelFloatPropertyParameters:
"""Return parameters for a devices list request."""
return WaterLevelFloatPropertyParameters()
class CO2LevelProperty(FloatProperty, Protocol):
"""Base class for CO2 level properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.CO2_LEVEL
@property
def parameters(self) -> CO2LevelFloatPropertyParameters:
"""Return parameters for a devices list request."""
return CO2LevelFloatPropertyParameters()
class MeterProperty(FloatProperty, Protocol):
"""Base class for meter properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.METER
@property
def parameters(self) -> MeterFloatPropertyParameters:
"""Return parameters for a devices list request."""
return MeterFloatPropertyParameters()
class ElectricityMeterProperty(FloatProperty, Protocol):
"""Base class for electricity meter properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.ELECTRICITY_METER
@property
def parameters(self) -> ElectricityMeterFloatPropertyParameters:
"""Return parameters for a devices list request."""
return ElectricityMeterFloatPropertyParameters()
@property
def unit_of_measurement(self) -> UnitOfEnergy:
"""Return the unit the property value is expressed in."""
return UnitOfEnergy.KILO_WATT_HOUR
@property
def _unit_converter(self) -> EnergyConverter:
"""Return the unit converter."""
return EnergyConverter()
class GasMeterProperty(FloatProperty, Protocol):
"""Base class for gas meter properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.GAS_METER
@property
def parameters(self) -> GasMeterFloatPropertyParameters:
"""Return parameters for a devices list request."""
return GasMeterFloatPropertyParameters()
@property
def unit_of_measurement(self) -> UnitOfVolume:
"""Return the unit the property value is expressed in."""
return UnitOfVolume.CUBIC_METERS
@property
def _unit_converter(self) -> VolumeConverter:
"""Return the unit converter."""
return VolumeConverter()
class HeatMeterProperty(FloatProperty, Protocol):
"""Base class for heat meter properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.HEAT_METER
@property
def parameters(self) -> HeatMeterFloatPropertyParameters:
"""Return parameters for a devices list request."""
return HeatMeterFloatPropertyParameters()
class WaterMeterProperty(FloatProperty, Protocol):
"""Base class for water meter properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.WATER_METER
@property
def parameters(self) -> WaterMeterFloatPropertyParameters:
"""Return parameters for a devices list request."""
return WaterMeterFloatPropertyParameters()
@property
def unit_of_measurement(self) -> UnitOfVolume:
"""Return the unit the property value is expressed in."""
return UnitOfVolume.CUBIC_METERS
@property
def _unit_converter(self) -> VolumeConverter:
"""Return the unit converter."""
return VolumeConverter()
class PM1DensityProperty(FloatProperty, Protocol):
"""Base class for PM1 density properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.PM1_DENSITY
@property
def parameters(self) -> PM1DensityFloatPropertyParameters:
"""Return parameters for a devices list request."""
return PM1DensityFloatPropertyParameters()
class PM25DensityProperty(FloatProperty, Protocol):
"""Base class for PM2.5 density properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.PM2_5_DENSITY
@property
def parameters(self) -> PM25DensityFloatPropertyParameters:
"""Return parameters for a devices list request."""
return PM25DensityFloatPropertyParameters()
class PM10DensityProperty(FloatProperty, Protocol):
"""Base class for PM10 density properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.PM10_DENSITY
@property
def parameters(self) -> PM10DensityFloatPropertyParameters:
"""Return parameters for a devices list request."""
return PM10DensityFloatPropertyParameters()
class TVOCConcentrationProperty(FloatProperty, Protocol):
"""Base class for TVOC concentration properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.TVOC
@property
def parameters(self) -> TVOCFloatPropertyParameters:
"""Return parameters for a devices list request."""
return TVOCFloatPropertyParameters()
@property
def unit_of_measurement(self) -> str:
"""Return the unit the property value is expressed in."""
return CONCENTRATION_MICROGRAMS_PER_CUBIC_METER
@property
def _unit_converter(self) -> TVOCConcentrationConverter:
"""Return the unit converter."""
return TVOCConcentrationConverter()
class VoltageProperty(FloatProperty, Protocol):
"""Base class for voltage properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.VOLTAGE
@property
def parameters(self) -> VoltageFloatPropertyParameters:
"""Return parameters for a devices list request."""
return VoltageFloatPropertyParameters()
@property
def unit_of_measurement(self) -> str:
"""Return the unit the property value is expressed in."""
return UnitOfElectricPotential.VOLT
@property
def _unit_converter(self) -> ElectricPotentialConverter:
"""Return the unit converter."""
return ElectricPotentialConverter()
class ElectricCurrentProperty(FloatProperty, Protocol):
"""Base class for electric current properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.AMPERAGE
@property
def parameters(self) -> AmperageFloatPropertyParameters:
"""Return parameters for a devices list request."""
return AmperageFloatPropertyParameters()
@property
def unit_of_measurement(self) -> str:
"""Return the unit the property value is expressed in."""
return UnitOfElectricCurrent.AMPERE
@property
def _unit_converter(self) -> ElectricCurrentConverter:
"""Return the unit converter."""
return ElectricCurrentConverter()
class ElectricPowerProperty(FloatProperty, Protocol):
"""Base class for electric power properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.POWER
@property
def parameters(self) -> PowerFloatPropertyParameters:
"""Return parameters for a devices list request."""
return PowerFloatPropertyParameters()
@property
def unit_of_measurement(self) -> str:
"""Return the unit the property value is expressed in."""
return UnitOfPower.WATT
@property
def _unit_converter(self) -> PowerConverter:
"""Return the unit converter."""
return PowerConverter()
class BatteryLevelPercentageProperty(FloatProperty, Protocol):
"""Base class for battery level (%) properties."""
instance: FloatPropertyInstance = FloatPropertyInstance.BATTERY_LEVEL
@property
def parameters(self) -> BatteryLevelFloatPropertyParameters:
"""Return parameters for a devices list request."""
return BatteryLevelFloatPropertyParameters()
class StateFloatProperty(StateProperty, FloatProperty):
"""Base class for a float property based on the state."""
@cached_property
def _native_unit_of_measurement(self) -> str | None:
"""Return the unit the native value is expressed in."""
if self.state.domain == sensor.DOMAIN:
return self.state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
return None
class TemperatureSensor(StateFloatProperty, TemperatureProperty):
"""Representaton of the state as a temperature sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
match self.state.domain:
case sensor.DOMAIN:
if self._state_device_class == SensorDeviceClass.TEMPERATURE:
return True
if self.state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) in UnitOfTemperature.__members__.values():
return True
case air_quality.DOMAIN:
return self.state.attributes.get(ATTR_TEMPERATURE) is not None
case climate.DOMAIN | fan.DOMAIN | humidifier.DOMAIN | water_heater.DOMAIN:
return self.state.attributes.get(ATTR_CURRENT_TEMPERATURE) is not None
return False
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
match self.state.domain:
case air_quality.DOMAIN:
return self.state.attributes.get(ATTR_TEMPERATURE)
case climate.DOMAIN | fan.DOMAIN | humidifier.DOMAIN | water_heater.DOMAIN:
return self.state.attributes.get(ATTR_CURRENT_TEMPERATURE)
return self.state.state
class HumiditySensor(StateFloatProperty, HumidityProperty):
"""Representaton of the state as a humidity sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
match self.state.domain:
case sensor.DOMAIN:
return self._state_device_class in (SensorDeviceClass.HUMIDITY, SensorDeviceClass.MOISTURE)
case air_quality.DOMAIN:
return self.state.attributes.get(ATTR_HUMIDITY) is not None
case climate.DOMAIN | fan.DOMAIN | humidifier.DOMAIN:
return self.state.attributes.get(ATTR_CURRENT_HUMIDITY) is not None
return False
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
match self.state.domain:
case air_quality.DOMAIN:
return self.state.attributes.get(ATTR_HUMIDITY)
case climate.DOMAIN | fan.DOMAIN | humidifier.DOMAIN:
return self.state.attributes.get(ATTR_CURRENT_HUMIDITY)
return self.state.state
class PressureSensor(StateFloatProperty, PressureProperty):
"""Representaton of the state as a pressure sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
return self.state.domain == sensor.DOMAIN and self._state_device_class in (
SensorDeviceClass.PRESSURE,
SensorDeviceClass.ATMOSPHERIC_PRESSURE,
)
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
return self.state.state
class IlluminationSensor(StateFloatProperty, IlluminationProperty):
"""Representaton of the state as a illumination sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
if self.state.domain == sensor.DOMAIN and self._state_device_class == SensorDeviceClass.ILLUMINANCE:
return True
if self.state.domain in (sensor.DOMAIN, light.DOMAIN, fan.DOMAIN):
return ATTR_ILLUMINANCE in self.state.attributes
return False
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
if self.state.domain == sensor.DOMAIN and self._state_device_class == SensorDeviceClass.ILLUMINANCE:
return self.state.state
return self.state.attributes.get(ATTR_ILLUMINANCE)
class WaterLevelPercentageSensor(StateFloatProperty, WaterLevelPercentageProperty):
"""Representaton of the state as a water level sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
if self.state.domain in (fan.DOMAIN, humidifier.DOMAIN):
return ATTR_WATER_LEVEL in self.state.attributes
return False
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
return self.state.attributes.get(ATTR_WATER_LEVEL)
class CO2LevelSensor(StateFloatProperty, CO2LevelProperty):
"""Representaton of the state as a CO2 level sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
match self.state.domain:
case sensor.DOMAIN:
return self._state_device_class == SensorDeviceClass.CO2
case air_quality.DOMAIN | fan.DOMAIN:
return ATTR_CO2 in self.state.attributes
return False
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
if self.state.domain == sensor.DOMAIN:
return self.state.state
return self.state.attributes.get(ATTR_CO2)
class ElectricityMeterSensor(StateFloatProperty, ElectricityMeterProperty):
"""Representaton of the state as a electricity meter sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
return self.state.domain == sensor.DOMAIN and self._state_device_class == SensorDeviceClass.ENERGY
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
return self.state.state
class GasMeterSensor(StateFloatProperty, GasMeterProperty):
"""Representaton of the state as a gas meter sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
return self.state.domain == sensor.DOMAIN and self._state_device_class == SensorDeviceClass.GAS
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
return self.state.state
class WaterMeterSensor(StateFloatProperty, WaterMeterProperty):
"""Representaton of the state as a water meter sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
return self.state.domain == sensor.DOMAIN and self._state_device_class == SensorDeviceClass.WATER
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
return self.state.state
class PM1DensitySensor(StateFloatProperty, PM1DensityProperty):
"""Representaton of the state as a PM1 density sensor."""
instance = FloatPropertyInstance.PM1_DENSITY
@property
def supported(self) -> bool:
"""Test if the property is supported."""
match self.state.domain:
case sensor.DOMAIN:
return self._state_device_class == SensorDeviceClass.PM1
case air_quality.DOMAIN:
return ATTR_PM_0_1 in self.state.attributes
return False
@property
def parameters(self) -> PM1DensityFloatPropertyParameters:
"""Return parameters for a devices list request."""
return PM1DensityFloatPropertyParameters()
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
if self.state.domain == sensor.DOMAIN:
return self.state.state
return self.state.attributes.get(ATTR_PM_0_1)
class PM25DensitySensor(StateFloatProperty, PM25DensityProperty):
"""Representaton of the state as a PM2.5 density sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
match self.state.domain:
case sensor.DOMAIN:
return self._state_device_class == SensorDeviceClass.PM25
case air_quality.DOMAIN:
return ATTR_PM_2_5 in self.state.attributes
return False
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
if self.state.domain == sensor.DOMAIN:
return self.state.state
return self.state.attributes.get(ATTR_PM_2_5)
class PM10DensitySensor(StateFloatProperty, PM10DensityProperty):
"""Representaton of the state as a PM10 density sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
match self.state.domain:
case sensor.DOMAIN:
return self._state_device_class == SensorDeviceClass.PM10
case air_quality.DOMAIN:
return ATTR_PM_10 in self.state.attributes
return False
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
if self.state.domain == sensor.DOMAIN:
return self.state.state
return self.state.attributes.get(ATTR_PM_10)
class TVOCConcentrationSensor(StateFloatProperty, TVOCConcentrationProperty):
"""Representaton of the state as a TVOC concentration sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
match self.state.domain:
case sensor.DOMAIN:
return self._state_device_class in (
SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS,
XGW3DeviceClass.TVOC,
)
case air_quality.DOMAIN:
return ATTR_TVOC in self.state.attributes
return False
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
if self.state.domain == sensor.DOMAIN:
return self.state.state
return self.state.attributes.get(ATTR_TVOC)
class VOCConcentrationSensor(StateFloatProperty, TVOCConcentrationProperty):
"""Representaton of the state as a VOC concentration sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
return (
self.state.domain == sensor.DOMAIN
and self._state_device_class == SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS
)
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
return self.state.state
@property
def _native_unit_of_measurement(self) -> str | None:
return None
class VoltageSensor(StateFloatProperty, VoltageProperty):
"""Representaton of the state as a voltage sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
match self.state.domain:
case sensor.DOMAIN:
return self._state_device_class == SensorDeviceClass.VOLTAGE
case switch.DOMAIN | light.DOMAIN:
return ATTR_VOLTAGE in self.state.attributes
return False
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
if self.state.domain == sensor.DOMAIN:
return self.state.state
return self.state.attributes.get(ATTR_VOLTAGE)
class ElectricCurrentSensor(StateFloatProperty, ElectricCurrentProperty):
"""Representaton of the state as a electric current sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
match self.state.domain:
case sensor.DOMAIN:
return self._state_device_class == SensorDeviceClass.CURRENT
case switch.DOMAIN | light.DOMAIN:
return ATTR_CURRENT in self.state.attributes
return False
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
if self.state.domain == sensor.DOMAIN:
return self.state.state
return self.state.attributes.get(ATTR_CURRENT)
class ElectricPowerSensor(StateFloatProperty, ElectricPowerProperty):
"""Representaton of the state as a electric power sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
if self.state.domain == sensor.DOMAIN:
return self._state_device_class == SensorDeviceClass.POWER
if self.state.domain == switch.DOMAIN:
for attribute in (ATTR_POWER, ATTR_LOAD_POWER, ATTR_CURRENT_CONSUMPTION):
if attribute in self.state.attributes:
return True
return False
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
if self.state.domain == switch.DOMAIN:
for attribute in (ATTR_POWER, ATTR_LOAD_POWER, ATTR_CURRENT_CONSUMPTION):
if attribute in self.state.attributes:
return self.state.attributes.get(attribute)
return self.state.state
class BatteryLevelPercentageSensor(StateFloatProperty, BatteryLevelPercentageProperty):
"""Representaton of the state as battery level sensor."""
@property
def supported(self) -> bool:
"""Test if the property is supported."""
if (
self._state_device_class == SensorDeviceClass.BATTERY
and self.state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE
):
return True
return ATTR_BATTERY_LEVEL in self.state.attributes
def _get_native_value(self) -> float | str | None:
"""Return the current property value without conversion."""
value = None
if self._state_device_class == SensorDeviceClass.BATTERY:
value = self.state.state
elif ATTR_BATTERY_LEVEL in self.state.attributes:
value = self.state.attributes.get(ATTR_BATTERY_LEVEL)
if value in [STATE_LOW, STATE_CHARGING]:
return 0
return value
STATE_PROPERTIES_REGISTRY.register(TemperatureSensor)
STATE_PROPERTIES_REGISTRY.register(HumiditySensor)
STATE_PROPERTIES_REGISTRY.register(PressureSensor)
STATE_PROPERTIES_REGISTRY.register(IlluminationSensor)
STATE_PROPERTIES_REGISTRY.register(WaterLevelPercentageSensor)
STATE_PROPERTIES_REGISTRY.register(CO2LevelSensor)
STATE_PROPERTIES_REGISTRY.register(ElectricityMeterSensor)
STATE_PROPERTIES_REGISTRY.register(GasMeterSensor)
STATE_PROPERTIES_REGISTRY.register(WaterMeterSensor)
STATE_PROPERTIES_REGISTRY.register(PM1DensitySensor)
STATE_PROPERTIES_REGISTRY.register(PM25DensitySensor)
STATE_PROPERTIES_REGISTRY.register(PM10DensitySensor)
STATE_PROPERTIES_REGISTRY.register(TVOCConcentrationSensor)
STATE_PROPERTIES_REGISTRY.register(VOCConcentrationSensor)
STATE_PROPERTIES_REGISTRY.register(VoltageSensor)
STATE_PROPERTIES_REGISTRY.register(ElectricCurrentSensor)
STATE_PROPERTIES_REGISTRY.register(ElectricPowerSensor)
STATE_PROPERTIES_REGISTRY.register(BatteryLevelPercentageSensor)