915 lines
31 KiB
Python
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)
|