diff --git a/homeassistant/components/tolo/sensor.py b/homeassistant/components/tolo/sensor.py index bcdb7db0165..714667cc1f8 100644 --- a/homeassistant/components/tolo/sensor.py +++ b/homeassistant/components/tolo/sensor.py @@ -1,12 +1,19 @@ """TOLO Sauna (non-binary, general) sensors.""" +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass + +from tololib.message_info import SettingsInfo, StatusInfo from homeassistant.components.sensor import ( SensorDeviceClass, SensorEntity, + SensorEntityDescription, SensorStateClass, ) from homeassistant.config_entries import ConfigEntry -from homeassistant.const import PERCENTAGE, TEMP_CELSIUS +from homeassistant.const import PERCENTAGE, TEMP_CELSIUS, TIME_MINUTES from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -15,6 +22,75 @@ from . import ToloSaunaCoordinatorEntity, ToloSaunaUpdateCoordinator from .const import DOMAIN +@dataclass +class ToloSensorEntityDescriptionBase: + """Required values when describing TOLO Sensor entities.""" + + getter: Callable[[StatusInfo], int | None] + availability_checker: Callable[[SettingsInfo, StatusInfo], bool] | None + + +@dataclass +class ToloSensorEntityDescription( + SensorEntityDescription, ToloSensorEntityDescriptionBase +): + """Class describing TOLO Sensor entities.""" + + state_class = SensorStateClass.MEASUREMENT + + +SENSORS = ( + ToloSensorEntityDescription( + key="water_level", + entity_category=EntityCategory.DIAGNOSTIC, + icon="mdi:waves-arrow-up", + name="Water Level", + native_unit_of_measurement=PERCENTAGE, + getter=lambda status: status.water_level_percent, + availability_checker=None, + ), + ToloSensorEntityDescription( + key="tank_temperature", + device_class=SensorDeviceClass.TEMPERATURE, + entity_category=EntityCategory.DIAGNOSTIC, + name="Tank Temperature", + native_unit_of_measurement=TEMP_CELSIUS, + getter=lambda status: status.tank_temperature, + availability_checker=None, + ), + ToloSensorEntityDescription( + key="power_timer_remaining", + entity_category=EntityCategory.DIAGNOSTIC, + icon="mdi:power-settings", + name="Power Timer", + native_unit_of_measurement=TIME_MINUTES, + getter=lambda status: status.power_timer, + availability_checker=lambda settings, status: status.power_on + and settings.power_timer is not None, + ), + ToloSensorEntityDescription( + key="salt_bath_timer_remaining", + entity_category=EntityCategory.DIAGNOSTIC, + icon="mdi:shaker-outline", + name="Salt Bath Timer", + native_unit_of_measurement=TIME_MINUTES, + getter=lambda status: status.salt_bath_timer, + availability_checker=lambda settings, status: status.salt_bath_on + and settings.salt_bath_timer is not None, + ), + ToloSensorEntityDescription( + key="fan_timer_remaining", + entity_category=EntityCategory.DIAGNOSTIC, + icon="mdi:fan-auto", + name="Fan Timer", + native_unit_of_measurement=TIME_MINUTES, + getter=lambda status: status.fan_timer, + availability_checker=lambda settings, status: status.fan_on + and settings.fan_timer is not None, + ), +) + + async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, @@ -23,54 +99,36 @@ async def async_setup_entry( """Set up (non-binary, general) sensors for TOLO Sauna.""" coordinator = hass.data[DOMAIN][entry.entry_id] async_add_entities( - [ - ToloWaterLevelSensor(coordinator, entry), - ToloTankTemperatureSensor(coordinator, entry), - ] + ToloSensorEntity(coordinator, entry, description) for description in SENSORS ) -class ToloWaterLevelSensor(ToloSaunaCoordinatorEntity, SensorEntity): - """Sensor for tank water level.""" +class ToloSensorEntity(ToloSaunaCoordinatorEntity, SensorEntity): + """TOLO Number entity.""" - _attr_entity_category = EntityCategory.DIAGNOSTIC - _attr_name = "Water Level" - _attr_icon = "mdi:waves-arrow-up" - _attr_state_class = SensorStateClass.MEASUREMENT - _attr_native_unit_of_measurement = PERCENTAGE + entity_description: ToloSensorEntityDescription def __init__( - self, coordinator: ToloSaunaUpdateCoordinator, entry: ConfigEntry + self, + coordinator: ToloSaunaUpdateCoordinator, + entry: ConfigEntry, + entity_description: ToloSensorEntityDescription, ) -> None: - """Initialize TOLO Sauna tank water level sensor entity.""" + """Initialize TOLO Number entity.""" super().__init__(coordinator, entry) - - self._attr_unique_id = f"{entry.entry_id}_water_level" + self.entity_description = entity_description + self._attr_unique_id = f"{entry.entry_id}_{entity_description.key}" @property - def native_value(self) -> int: - """Return current tank water level.""" - return self.coordinator.data.status.water_level_percent - - -class ToloTankTemperatureSensor(ToloSaunaCoordinatorEntity, SensorEntity): - """Sensor for tank temperature.""" - - _attr_entity_category = EntityCategory.DIAGNOSTIC - _attr_name = "Tank Temperature" - _attr_device_class = SensorDeviceClass.TEMPERATURE - _attr_state_class = SensorStateClass.MEASUREMENT - _attr_native_unit_of_measurement = TEMP_CELSIUS - - def __init__( - self, coordinator: ToloSaunaUpdateCoordinator, entry: ConfigEntry - ) -> None: - """Initialize TOLO Sauna tank temperature sensor entity.""" - super().__init__(coordinator, entry) - - self._attr_unique_id = f"{entry.entry_id}_tank_temperature" + def available(self) -> bool: + """Return availability of the TOLO sensor.""" + if self.entity_description.availability_checker is None: + return super().available + return self.entity_description.availability_checker( + self.coordinator.data.settings, self.coordinator.data.status + ) @property - def native_value(self) -> int: - """Return current tank temperature.""" - return self.coordinator.data.status.tank_temperature + def native_value(self) -> int | None: + """Return native value of the TOLO sensor.""" + return self.entity_description.getter(self.coordinator.data.status)