core/homeassistant/components/huum/climate.py

135 lines
4.6 KiB
Python

"""Support for Huum wifi-enabled sauna."""
from __future__ import annotations
import logging
from typing import Any
from huum.const import SaunaStatus
from huum.exceptions import SafetyException
from huum.huum import Huum
from huum.schemas import HuumStatusResponse
from homeassistant.components.climate import (
ClimateEntity,
ClimateEntityFeature,
HVACMode,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, PRECISION_WHOLE, UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Huum sauna with config flow."""
huum_handler = hass.data.setdefault(DOMAIN, {})[entry.entry_id]
async_add_entities([HuumDevice(huum_handler, entry.entry_id)], True)
class HuumDevice(ClimateEntity):
"""Representation of a heater."""
_attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF]
_attr_supported_features = (
ClimateEntityFeature.TARGET_TEMPERATURE
| ClimateEntityFeature.TURN_OFF
| ClimateEntityFeature.TURN_ON
)
_attr_target_temperature_step = PRECISION_WHOLE
_attr_temperature_unit = UnitOfTemperature.CELSIUS
_attr_max_temp = 110
_attr_min_temp = 40
_attr_has_entity_name = True
_attr_name = None
_target_temperature: int | None = None
_status: HuumStatusResponse | None = None
_enable_turn_on_off_backwards_compatibility = False
def __init__(self, huum_handler: Huum, unique_id: str) -> None:
"""Initialize the heater."""
self._attr_unique_id = unique_id
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, unique_id)},
name="Huum sauna",
manufacturer="Huum",
)
self._huum_handler = huum_handler
@property
def hvac_mode(self) -> HVACMode:
"""Return hvac operation ie. heat, cool mode."""
if self._status and self._status.status == SaunaStatus.ONLINE_HEATING:
return HVACMode.HEAT
return HVACMode.OFF
@property
def icon(self) -> str:
"""Return nice icon for heater."""
if self.hvac_mode == HVACMode.HEAT:
return "mdi:radiator"
return "mdi:radiator-off"
@property
def current_temperature(self) -> int | None:
"""Return the current temperature."""
if (status := self._status) is not None:
return status.temperature
return None
@property
def target_temperature(self) -> int:
"""Return the temperature we try to reach."""
return self._target_temperature or int(self.min_temp)
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set hvac mode."""
if hvac_mode == HVACMode.HEAT:
await self._turn_on(self.target_temperature)
elif hvac_mode == HVACMode.OFF:
await self._huum_handler.turn_off()
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
temperature = kwargs.get(ATTR_TEMPERATURE)
if temperature is None:
return
self._target_temperature = temperature
if self.hvac_mode == HVACMode.HEAT:
await self._turn_on(temperature)
async def async_update(self) -> None:
"""Get the latest status data.
We get the latest status first from the status endpoints of the sauna.
If that data does not include the temperature, that means that the sauna
is off, we then call the off command which will in turn return the temperature.
This is a workaround for getting the temperature as the Huum API does not
return the target temperature of a sauna that is off, even if it can have
a target temperature at that time.
"""
self._status = await self._huum_handler.status_from_status_or_stop()
if self._target_temperature is None or self.hvac_mode == HVACMode.HEAT:
self._target_temperature = self._status.target_temperature
async def _turn_on(self, temperature: int) -> None:
try:
await self._huum_handler.turn_on(temperature)
except (ValueError, SafetyException) as err:
_LOGGER.error(str(err))
raise HomeAssistantError(f"Unable to turn on sauna: {err}") from err