2021-05-03 10:52:22 +00:00
|
|
|
"""Support for AVM FRITZ!SmartHome temperature sensor only devices."""
|
2021-05-15 05:54:11 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2021-09-29 12:06:51 +00:00
|
|
|
from collections.abc import Callable
|
2021-08-28 21:07:06 +00:00
|
|
|
from dataclasses import dataclass
|
2021-11-25 11:34:04 +00:00
|
|
|
from datetime import datetime
|
2021-09-29 12:06:51 +00:00
|
|
|
from typing import Final
|
2021-08-28 21:07:06 +00:00
|
|
|
|
|
|
|
from pyfritzhome.fritzhomedevice import FritzhomeDevice
|
|
|
|
|
2022-09-10 21:39:52 +00:00
|
|
|
from homeassistant.components.climate import PRESET_COMFORT, PRESET_ECO
|
2021-08-28 21:07:06 +00:00
|
|
|
from homeassistant.components.sensor import (
|
2021-12-10 13:58:23 +00:00
|
|
|
SensorDeviceClass,
|
2021-08-28 21:07:06 +00:00
|
|
|
SensorEntity,
|
|
|
|
SensorEntityDescription,
|
2021-12-10 13:58:23 +00:00
|
|
|
SensorStateClass,
|
2021-08-28 21:07:06 +00:00
|
|
|
)
|
2021-04-25 00:40:12 +00:00
|
|
|
from homeassistant.config_entries import ConfigEntry
|
2021-08-28 21:07:06 +00:00
|
|
|
from homeassistant.const import (
|
|
|
|
PERCENTAGE,
|
2023-02-09 19:15:37 +00:00
|
|
|
EntityCategory,
|
2022-12-09 09:51:26 +00:00
|
|
|
UnitOfElectricCurrent,
|
2022-12-15 12:59:21 +00:00
|
|
|
UnitOfElectricPotential,
|
2022-12-19 10:06:00 +00:00
|
|
|
UnitOfEnergy,
|
2022-12-12 10:48:09 +00:00
|
|
|
UnitOfPower,
|
2022-12-20 17:29:16 +00:00
|
|
|
UnitOfTemperature,
|
2021-08-28 21:07:06 +00:00
|
|
|
)
|
2021-04-25 00:40:12 +00:00
|
|
|
from homeassistant.core import HomeAssistant
|
2021-04-30 18:38:59 +00:00
|
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
2021-11-25 11:34:04 +00:00
|
|
|
from homeassistant.helpers.typing import StateType
|
|
|
|
from homeassistant.util.dt import utc_from_timestamp
|
2019-03-21 05:56:46 +00:00
|
|
|
|
2022-11-18 16:37:56 +00:00
|
|
|
from . import FritzBoxDeviceEntity
|
2021-08-28 21:07:06 +00:00
|
|
|
from .const import CONF_COORDINATOR, DOMAIN as FRITZBOX_DOMAIN
|
|
|
|
from .model import FritzEntityDescriptionMixinBase
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class FritzEntityDescriptionMixinSensor(FritzEntityDescriptionMixinBase):
|
|
|
|
"""Sensor description mixin for Fritz!Smarthome entities."""
|
|
|
|
|
2021-11-25 11:34:04 +00:00
|
|
|
native_value: Callable[[FritzhomeDevice], StateType | datetime]
|
2021-08-28 21:07:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class FritzSensorEntityDescription(
|
|
|
|
SensorEntityDescription, FritzEntityDescriptionMixinSensor
|
|
|
|
):
|
|
|
|
"""Description for Fritz!Smarthome sensor entities."""
|
|
|
|
|
|
|
|
|
2022-09-28 06:43:31 +00:00
|
|
|
def suitable_eco_temperature(device: FritzhomeDevice) -> bool:
|
|
|
|
"""Check suitablity for eco temperature sensor."""
|
|
|
|
return device.has_thermostat and device.eco_temperature is not None
|
|
|
|
|
|
|
|
|
|
|
|
def suitable_comfort_temperature(device: FritzhomeDevice) -> bool:
|
|
|
|
"""Check suitablity for comfort temperature sensor."""
|
|
|
|
return device.has_thermostat and device.comfort_temperature is not None
|
|
|
|
|
|
|
|
|
|
|
|
def suitable_nextchange_temperature(device: FritzhomeDevice) -> bool:
|
|
|
|
"""Check suitablity for next scheduled temperature sensor."""
|
|
|
|
return device.has_thermostat and device.nextchange_temperature is not None
|
|
|
|
|
|
|
|
|
|
|
|
def suitable_nextchange_time(device: FritzhomeDevice) -> bool:
|
|
|
|
"""Check suitablity for next scheduled changed time sensor."""
|
|
|
|
return device.has_thermostat and device.nextchange_endperiod is not None
|
|
|
|
|
|
|
|
|
|
|
|
def suitable_temperature(device: FritzhomeDevice) -> bool:
|
|
|
|
"""Check suitablity for temperature sensor."""
|
|
|
|
return device.has_temperature_sensor and not device.has_thermostat
|
|
|
|
|
|
|
|
|
|
|
|
def value_electric_current(device: FritzhomeDevice) -> float:
|
|
|
|
"""Return native value for electric current sensor."""
|
2022-10-21 08:07:45 +00:00
|
|
|
if (
|
|
|
|
isinstance(device.power, int)
|
|
|
|
and isinstance(device.voltage, int)
|
|
|
|
and device.voltage > 0
|
|
|
|
):
|
2022-09-28 06:43:31 +00:00
|
|
|
return round(device.power / device.voltage, 3)
|
|
|
|
return 0.0
|
|
|
|
|
|
|
|
|
|
|
|
def value_nextchange_preset(device: FritzhomeDevice) -> str:
|
|
|
|
"""Return native value for next scheduled preset sensor."""
|
|
|
|
if device.nextchange_temperature == device.eco_temperature:
|
|
|
|
return PRESET_ECO
|
|
|
|
return PRESET_COMFORT
|
|
|
|
|
|
|
|
|
|
|
|
def value_scheduled_preset(device: FritzhomeDevice) -> str:
|
|
|
|
"""Return native value for current scheduled preset sensor."""
|
|
|
|
if device.nextchange_temperature == device.eco_temperature:
|
|
|
|
return PRESET_COMFORT
|
|
|
|
return PRESET_ECO
|
|
|
|
|
|
|
|
|
2021-08-28 21:07:06 +00:00
|
|
|
SENSOR_TYPES: Final[tuple[FritzSensorEntityDescription, ...]] = (
|
|
|
|
FritzSensorEntityDescription(
|
|
|
|
key="temperature",
|
|
|
|
name="Temperature",
|
2022-12-20 17:29:16 +00:00
|
|
|
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
2021-12-10 13:58:23 +00:00
|
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
2022-09-28 06:43:31 +00:00
|
|
|
suitable=suitable_temperature,
|
2021-08-28 21:07:06 +00:00
|
|
|
native_value=lambda device: device.temperature, # type: ignore[no-any-return]
|
2021-09-30 09:56:38 +00:00
|
|
|
),
|
|
|
|
FritzSensorEntityDescription(
|
|
|
|
key="humidity",
|
|
|
|
name="Humidity",
|
|
|
|
native_unit_of_measurement=PERCENTAGE,
|
2021-12-10 13:58:23 +00:00
|
|
|
device_class=SensorDeviceClass.HUMIDITY,
|
|
|
|
state_class=SensorStateClass.MEASUREMENT,
|
2021-09-30 09:56:38 +00:00
|
|
|
suitable=lambda device: device.rel_humidity is not None,
|
|
|
|
native_value=lambda device: device.rel_humidity, # type: ignore[no-any-return]
|
2021-08-28 21:07:06 +00:00
|
|
|
),
|
|
|
|
FritzSensorEntityDescription(
|
|
|
|
key="battery",
|
|
|
|
name="Battery",
|
|
|
|
native_unit_of_measurement=PERCENTAGE,
|
2021-12-10 13:58:23 +00:00
|
|
|
device_class=SensorDeviceClass.BATTERY,
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
2021-08-28 21:07:06 +00:00
|
|
|
suitable=lambda device: device.battery_level is not None,
|
|
|
|
native_value=lambda device: device.battery_level, # type: ignore[no-any-return]
|
|
|
|
),
|
|
|
|
FritzSensorEntityDescription(
|
|
|
|
key="power_consumption",
|
|
|
|
name="Power Consumption",
|
2022-12-12 10:48:09 +00:00
|
|
|
native_unit_of_measurement=UnitOfPower.WATT,
|
2021-12-10 13:58:23 +00:00
|
|
|
device_class=SensorDeviceClass.POWER,
|
|
|
|
state_class=SensorStateClass.MEASUREMENT,
|
2021-08-28 21:07:06 +00:00
|
|
|
suitable=lambda device: device.has_powermeter, # type: ignore[no-any-return]
|
2022-09-15 14:01:55 +00:00
|
|
|
native_value=lambda device: round((device.power or 0.0) / 1000, 3),
|
2021-08-28 21:07:06 +00:00
|
|
|
),
|
2022-04-24 20:02:19 +00:00
|
|
|
FritzSensorEntityDescription(
|
|
|
|
key="voltage",
|
|
|
|
name="Voltage",
|
2022-12-15 12:59:21 +00:00
|
|
|
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
|
2022-04-24 20:02:19 +00:00
|
|
|
device_class=SensorDeviceClass.VOLTAGE,
|
|
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
|
|
suitable=lambda device: device.has_powermeter, # type: ignore[no-any-return]
|
2022-09-15 14:01:55 +00:00
|
|
|
native_value=lambda device: round((device.voltage or 0.0) / 1000, 2),
|
2022-04-24 20:02:19 +00:00
|
|
|
),
|
|
|
|
FritzSensorEntityDescription(
|
|
|
|
key="electric_current",
|
|
|
|
name="Electric Current",
|
2022-12-09 09:51:26 +00:00
|
|
|
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
|
2022-04-24 20:02:19 +00:00
|
|
|
device_class=SensorDeviceClass.CURRENT,
|
|
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
|
|
suitable=lambda device: device.has_powermeter, # type: ignore[no-any-return]
|
2022-09-28 06:43:31 +00:00
|
|
|
native_value=value_electric_current,
|
2022-04-24 20:02:19 +00:00
|
|
|
),
|
2021-08-28 21:07:06 +00:00
|
|
|
FritzSensorEntityDescription(
|
|
|
|
key="total_energy",
|
|
|
|
name="Total Energy",
|
2022-12-19 10:06:00 +00:00
|
|
|
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
|
2021-12-10 13:58:23 +00:00
|
|
|
device_class=SensorDeviceClass.ENERGY,
|
|
|
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
2021-08-28 21:07:06 +00:00
|
|
|
suitable=lambda device: device.has_powermeter, # type: ignore[no-any-return]
|
2022-09-15 14:01:55 +00:00
|
|
|
native_value=lambda device: (device.energy or 0.0) / 1000,
|
2021-08-28 21:07:06 +00:00
|
|
|
),
|
2021-11-25 11:34:04 +00:00
|
|
|
# Thermostat Sensors
|
|
|
|
FritzSensorEntityDescription(
|
|
|
|
key="comfort_temperature",
|
|
|
|
name="Comfort Temperature",
|
2022-12-20 17:29:16 +00:00
|
|
|
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
2021-12-10 13:58:23 +00:00
|
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
2022-09-28 06:43:31 +00:00
|
|
|
suitable=suitable_comfort_temperature,
|
2021-11-25 11:34:04 +00:00
|
|
|
native_value=lambda device: device.comfort_temperature, # type: ignore[no-any-return]
|
|
|
|
),
|
|
|
|
FritzSensorEntityDescription(
|
|
|
|
key="eco_temperature",
|
|
|
|
name="Eco Temperature",
|
2022-12-20 17:29:16 +00:00
|
|
|
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
2021-12-10 13:58:23 +00:00
|
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
2022-09-28 06:43:31 +00:00
|
|
|
suitable=suitable_eco_temperature,
|
2021-11-25 11:34:04 +00:00
|
|
|
native_value=lambda device: device.eco_temperature, # type: ignore[no-any-return]
|
|
|
|
),
|
|
|
|
FritzSensorEntityDescription(
|
|
|
|
key="nextchange_temperature",
|
|
|
|
name="Next Scheduled Temperature",
|
2022-12-20 17:29:16 +00:00
|
|
|
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
2021-12-10 13:58:23 +00:00
|
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
2022-09-28 06:43:31 +00:00
|
|
|
suitable=suitable_nextchange_temperature,
|
2021-11-25 11:34:04 +00:00
|
|
|
native_value=lambda device: device.nextchange_temperature, # type: ignore[no-any-return]
|
|
|
|
),
|
|
|
|
FritzSensorEntityDescription(
|
|
|
|
key="nextchange_time",
|
|
|
|
name="Next Scheduled Change Time",
|
2021-12-10 13:58:23 +00:00
|
|
|
device_class=SensorDeviceClass.TIMESTAMP,
|
2022-09-28 06:43:31 +00:00
|
|
|
suitable=suitable_nextchange_time,
|
2021-11-25 11:34:04 +00:00
|
|
|
native_value=lambda device: utc_from_timestamp(device.nextchange_endperiod),
|
|
|
|
),
|
|
|
|
FritzSensorEntityDescription(
|
|
|
|
key="nextchange_preset",
|
|
|
|
name="Next Scheduled Preset",
|
2022-09-28 06:43:31 +00:00
|
|
|
suitable=suitable_nextchange_temperature,
|
|
|
|
native_value=value_nextchange_preset,
|
2021-11-25 11:34:04 +00:00
|
|
|
),
|
|
|
|
FritzSensorEntityDescription(
|
|
|
|
key="scheduled_preset",
|
|
|
|
name="Current Scheduled Preset",
|
2022-09-28 06:43:31 +00:00
|
|
|
suitable=suitable_nextchange_temperature,
|
|
|
|
native_value=value_scheduled_preset,
|
2021-11-25 11:34:04 +00:00
|
|
|
),
|
2021-08-28 21:07:06 +00:00
|
|
|
)
|
2019-01-30 17:44:36 +00:00
|
|
|
|
|
|
|
|
2021-04-25 00:40:12 +00:00
|
|
|
async def async_setup_entry(
|
2021-04-30 18:38:59 +00:00
|
|
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
2021-04-25 00:40:12 +00:00
|
|
|
) -> None:
|
2021-05-03 10:52:22 +00:00
|
|
|
"""Set up the FRITZ!SmartHome sensor from ConfigEntry."""
|
2021-04-25 00:40:12 +00:00
|
|
|
coordinator = hass.data[FRITZBOX_DOMAIN][entry.entry_id][CONF_COORDINATOR]
|
2019-01-30 17:44:36 +00:00
|
|
|
|
2021-08-27 15:09:34 +00:00
|
|
|
async_add_entities(
|
|
|
|
[
|
|
|
|
FritzBoxSensor(coordinator, ain, description)
|
2022-11-18 16:37:56 +00:00
|
|
|
for ain, device in coordinator.data.devices.items()
|
2021-08-27 15:09:34 +00:00
|
|
|
for description in SENSOR_TYPES
|
|
|
|
if description.suitable(device)
|
|
|
|
]
|
|
|
|
)
|
2019-01-30 17:44:36 +00:00
|
|
|
|
|
|
|
|
2022-11-18 16:37:56 +00:00
|
|
|
class FritzBoxSensor(FritzBoxDeviceEntity, SensorEntity):
|
2021-08-12 12:23:56 +00:00
|
|
|
"""The entity class for FRITZ!SmartHome sensors."""
|
|
|
|
|
2021-08-27 15:09:34 +00:00
|
|
|
entity_description: FritzSensorEntityDescription
|
2021-04-18 22:30:58 +00:00
|
|
|
|
|
|
|
@property
|
2021-11-25 11:34:04 +00:00
|
|
|
def native_value(self) -> StateType | datetime:
|
2021-04-18 22:30:58 +00:00
|
|
|
"""Return the state of the sensor."""
|
2022-11-19 14:12:24 +00:00
|
|
|
return self.entity_description.native_value(self.data)
|