core/homeassistant/components/bosch_shc/sensor.py

232 lines
7.4 KiB
Python

"""Platform for sensor integration."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from typing import Any
from boschshcpy import SHCSession
from boschshcpy.device import SHCDevice
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONCENTRATION_PARTS_PER_MILLION,
PERCENTAGE,
UnitOfEnergy,
UnitOfPower,
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from .const import DATA_SESSION, DOMAIN
from .entity import SHCEntity
@dataclass(frozen=True, kw_only=True)
class SHCSensorEntityDescription(SensorEntityDescription):
"""Describes a SHC sensor."""
value_fn: Callable[[SHCDevice], StateType]
attributes_fn: Callable[[SHCDevice], dict[str, Any]] | None = None
TEMPERATURE_SENSOR = "temperature"
HUMIDITY_SENSOR = "humidity"
VALVE_TAPPET_SENSOR = "valvetappet"
PURITY_SENSOR = "purity"
AIR_QUALITY_SENSOR = "airquality"
TEMPERATURE_RATING_SENSOR = "temperature_rating"
HUMIDITY_RATING_SENSOR = "humidity_rating"
PURITY_RATING_SENSOR = "purity_rating"
POWER_SENSOR = "power"
ENERGY_SENSOR = "energy"
COMMUNICATION_QUALITY_SENSOR = "communication_quality"
SENSOR_DESCRIPTIONS: dict[str, SHCSensorEntityDescription] = {
TEMPERATURE_SENSOR: SHCSensorEntityDescription(
key=TEMPERATURE_SENSOR,
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
value_fn=lambda device: device.temperature,
),
HUMIDITY_SENSOR: SHCSensorEntityDescription(
key=HUMIDITY_SENSOR,
device_class=SensorDeviceClass.HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
value_fn=lambda device: device.humidity,
),
PURITY_SENSOR: SHCSensorEntityDescription(
key=PURITY_SENSOR,
translation_key=PURITY_SENSOR,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
value_fn=lambda device: device.purity,
),
AIR_QUALITY_SENSOR: SHCSensorEntityDescription(
key=AIR_QUALITY_SENSOR,
translation_key="air_quality",
value_fn=lambda device: device.combined_rating.name,
attributes_fn=lambda device: {
"rating_description": device.description,
},
),
TEMPERATURE_RATING_SENSOR: SHCSensorEntityDescription(
key=TEMPERATURE_RATING_SENSOR,
translation_key=TEMPERATURE_RATING_SENSOR,
value_fn=lambda device: device.temperature_rating.name,
),
COMMUNICATION_QUALITY_SENSOR: SHCSensorEntityDescription(
key=COMMUNICATION_QUALITY_SENSOR,
translation_key=COMMUNICATION_QUALITY_SENSOR,
value_fn=lambda device: device.communicationquality.name,
),
HUMIDITY_RATING_SENSOR: SHCSensorEntityDescription(
key=HUMIDITY_RATING_SENSOR,
translation_key=HUMIDITY_RATING_SENSOR,
value_fn=lambda device: device.humidity_rating.name,
),
PURITY_RATING_SENSOR: SHCSensorEntityDescription(
key=PURITY_RATING_SENSOR,
translation_key=PURITY_RATING_SENSOR,
value_fn=lambda device: device.purity_rating.name,
),
POWER_SENSOR: SHCSensorEntityDescription(
key=POWER_SENSOR,
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.WATT,
value_fn=lambda device: device.powerconsumption,
),
ENERGY_SENSOR: SHCSensorEntityDescription(
key=ENERGY_SENSOR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
value_fn=lambda device: device.energyconsumption / 1000.0,
),
VALVE_TAPPET_SENSOR: SHCSensorEntityDescription(
key=VALVE_TAPPET_SENSOR,
translation_key=VALVE_TAPPET_SENSOR,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
value_fn=lambda device: device.position,
attributes_fn=lambda device: {
"valve_tappet_state": device.valvestate.name,
},
),
}
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the SHC sensor platform."""
session: SHCSession = hass.data[DOMAIN][config_entry.entry_id][DATA_SESSION]
entities: list[SensorEntity] = [
SHCSensor(
device,
SENSOR_DESCRIPTIONS[sensor_type],
session.information.unique_id,
config_entry.entry_id,
)
for device in session.device_helper.thermostats
for sensor_type in (TEMPERATURE_SENSOR, VALVE_TAPPET_SENSOR)
]
entities.extend(
SHCSensor(
device,
SENSOR_DESCRIPTIONS[sensor_type],
session.information.unique_id,
config_entry.entry_id,
)
for device in session.device_helper.wallthermostats
for sensor_type in (TEMPERATURE_SENSOR, HUMIDITY_SENSOR)
)
entities.extend(
SHCSensor(
device,
SENSOR_DESCRIPTIONS[sensor_type],
session.information.unique_id,
config_entry.entry_id,
)
for device in session.device_helper.twinguards
for sensor_type in (
TEMPERATURE_SENSOR,
HUMIDITY_SENSOR,
PURITY_SENSOR,
AIR_QUALITY_SENSOR,
TEMPERATURE_RATING_SENSOR,
HUMIDITY_RATING_SENSOR,
PURITY_RATING_SENSOR,
)
)
entities.extend(
SHCSensor(
device,
SENSOR_DESCRIPTIONS[sensor_type],
session.information.unique_id,
config_entry.entry_id,
)
for device in (
session.device_helper.smart_plugs + session.device_helper.light_switches_bsm
)
for sensor_type in (POWER_SENSOR, ENERGY_SENSOR)
)
entities.extend(
SHCSensor(
device,
SENSOR_DESCRIPTIONS[sensor_type],
session.information.unique_id,
config_entry.entry_id,
)
for device in session.device_helper.smart_plugs_compact
for sensor_type in (POWER_SENSOR, ENERGY_SENSOR, COMMUNICATION_QUALITY_SENSOR)
)
async_add_entities(entities)
class SHCSensor(SHCEntity, SensorEntity):
"""Representation of a SHC sensor."""
entity_description: SHCSensorEntityDescription
def __init__(
self,
device: SHCDevice,
entity_description: SHCSensorEntityDescription,
parent_id: str,
entry_id: str,
) -> None:
"""Initialize sensor."""
super().__init__(device, parent_id, entry_id)
self.entity_description = entity_description
self._attr_unique_id = f"{device.serial}_{entity_description.key}"
@property
def native_value(self) -> StateType:
"""Return the state of the sensor."""
return self.entity_description.value_fn(self._device)
@property
def extra_state_attributes(self) -> dict[str, Any] | None:
"""Return the state attributes."""
if self.entity_description.attributes_fn is not None:
return self.entity_description.attributes_fn(self._device)
return None