mirror of
https://github.com/home-assistant/core.git
synced 2025-11-27 03:28:04 +00:00
147 lines
5.0 KiB
Python
147 lines
5.0 KiB
Python
"""Climate platform for Saunum Leil Sauna Control Unit."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from typing import Any
|
|
|
|
from pysaunum import MAX_TEMPERATURE, MIN_TEMPERATURE, SaunumException
|
|
|
|
from homeassistant.components.climate import (
|
|
FAN_HIGH,
|
|
FAN_LOW,
|
|
FAN_MEDIUM,
|
|
FAN_OFF,
|
|
ClimateEntity,
|
|
ClimateEntityFeature,
|
|
HVACAction,
|
|
HVACMode,
|
|
)
|
|
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|
|
|
from . import LeilSaunaConfigEntry
|
|
from .const import DELAYED_REFRESH_SECONDS, DOMAIN
|
|
from .entity import LeilSaunaEntity
|
|
|
|
PARALLEL_UPDATES = 1
|
|
|
|
# Map Saunum fan speed (0-3) to Home Assistant fan modes
|
|
FAN_SPEED_TO_MODE = {
|
|
0: FAN_OFF,
|
|
1: FAN_LOW,
|
|
2: FAN_MEDIUM,
|
|
3: FAN_HIGH,
|
|
}
|
|
FAN_MODE_TO_SPEED = {v: k for k, v in FAN_SPEED_TO_MODE.items()}
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
entry: LeilSaunaConfigEntry,
|
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
) -> None:
|
|
"""Set up Saunum Leil Sauna climate entity."""
|
|
coordinator = entry.runtime_data
|
|
async_add_entities([LeilSaunaClimate(coordinator)])
|
|
|
|
|
|
class LeilSaunaClimate(LeilSaunaEntity, ClimateEntity):
|
|
"""Representation of a Saunum Leil Sauna climate entity."""
|
|
|
|
_attr_name = None
|
|
_attr_hvac_modes = [HVACMode.OFF, HVACMode.HEAT]
|
|
_attr_supported_features = (
|
|
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE
|
|
)
|
|
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
|
_attr_min_temp = MIN_TEMPERATURE
|
|
_attr_max_temp = MAX_TEMPERATURE
|
|
_attr_fan_modes = [FAN_OFF, FAN_LOW, FAN_MEDIUM, FAN_HIGH]
|
|
|
|
@property
|
|
def current_temperature(self) -> float | None:
|
|
"""Return the current temperature in Celsius."""
|
|
return self.coordinator.data.current_temperature
|
|
|
|
@property
|
|
def target_temperature(self) -> float | None:
|
|
"""Return the target temperature in Celsius."""
|
|
return self.coordinator.data.target_temperature
|
|
|
|
@property
|
|
def fan_mode(self) -> str | None:
|
|
"""Return the current fan mode."""
|
|
fan_speed = self.coordinator.data.fan_speed
|
|
if fan_speed is not None and fan_speed in FAN_SPEED_TO_MODE:
|
|
return FAN_SPEED_TO_MODE[fan_speed]
|
|
return None
|
|
|
|
@property
|
|
def hvac_mode(self) -> HVACMode:
|
|
"""Return current HVAC mode."""
|
|
session_active = self.coordinator.data.session_active
|
|
return HVACMode.HEAT if session_active else HVACMode.OFF
|
|
|
|
@property
|
|
def hvac_action(self) -> HVACAction | None:
|
|
"""Return current HVAC action."""
|
|
if not self.coordinator.data.session_active:
|
|
return HVACAction.OFF
|
|
|
|
heater_elements_active = self.coordinator.data.heater_elements_active
|
|
return (
|
|
HVACAction.HEATING
|
|
if heater_elements_active and heater_elements_active > 0
|
|
else HVACAction.IDLE
|
|
)
|
|
|
|
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
|
"""Set new HVAC mode."""
|
|
try:
|
|
if hvac_mode == HVACMode.HEAT:
|
|
await self.coordinator.client.async_start_session()
|
|
else:
|
|
await self.coordinator.client.async_stop_session()
|
|
except SaunumException as err:
|
|
raise HomeAssistantError(
|
|
translation_domain=DOMAIN,
|
|
translation_key="set_hvac_mode_failed",
|
|
translation_placeholders={"hvac_mode": hvac_mode},
|
|
) from err
|
|
|
|
# The device takes 1-2 seconds to turn heater elements on/off and
|
|
# update heater_elements_active. Wait and refresh again to ensure
|
|
# the HVAC action state reflects the actual heater status.
|
|
await asyncio.sleep(DELAYED_REFRESH_SECONDS.total_seconds())
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
async def async_set_temperature(self, **kwargs: Any) -> None:
|
|
"""Set new target temperature."""
|
|
try:
|
|
await self.coordinator.client.async_set_target_temperature(
|
|
int(kwargs[ATTR_TEMPERATURE])
|
|
)
|
|
except SaunumException as err:
|
|
raise HomeAssistantError(
|
|
translation_domain=DOMAIN,
|
|
translation_key="set_temperature_failed",
|
|
translation_placeholders={"temperature": str(kwargs[ATTR_TEMPERATURE])},
|
|
) from err
|
|
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
|
"""Set new fan mode."""
|
|
if not self.coordinator.data.session_active:
|
|
raise ServiceValidationError(
|
|
"Cannot change fan mode when sauna session is not active",
|
|
translation_domain=DOMAIN,
|
|
translation_key="session_not_active",
|
|
)
|
|
|
|
await self.coordinator.client.async_set_fan_speed(FAN_MODE_TO_SPEED[fan_mode])
|
|
await self.coordinator.async_request_refresh()
|