core/homeassistant/components/balboa/climate.py

152 lines
5.0 KiB
Python

"""Support for Balboa Spa Wifi adaptor."""
from __future__ import annotations
from enum import IntEnum
from typing import Any
from pybalboa import SpaClient, SpaControl
from pybalboa.enums import HeatMode, HeatState, TemperatureUnit
from homeassistant.components.climate import (
ClimateEntity,
ClimateEntityFeature,
HVACAction,
HVACMode,
)
from homeassistant.const import (
ATTR_TEMPERATURE,
PRECISION_HALVES,
PRECISION_WHOLE,
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import BalboaConfigEntry
from .const import DOMAIN
from .entity import BalboaEntity
HEAT_HVAC_MODE_MAP: dict[IntEnum, HVACMode] = {
HeatMode.READY: HVACMode.HEAT,
HeatMode.REST: HVACMode.OFF,
HeatMode.READY_IN_REST: HVACMode.AUTO,
}
HVAC_HEAT_MODE_MAP = {value: key for key, value in HEAT_HVAC_MODE_MAP.items()}
HEAT_STATE_HVAC_ACTION_MAP = {
HeatState.OFF: HVACAction.OFF,
HeatState.HEATING: HVACAction.HEATING,
HeatState.HEAT_WAITING: HVACAction.IDLE,
}
TEMPERATURE_UNIT_MAP = {
TemperatureUnit.CELSIUS: UnitOfTemperature.CELSIUS,
TemperatureUnit.FAHRENHEIT: UnitOfTemperature.FAHRENHEIT,
}
async def async_setup_entry(
hass: HomeAssistant,
entry: BalboaConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the spa climate entity."""
async_add_entities([BalboaClimateEntity(entry.runtime_data)])
class BalboaClimateEntity(BalboaEntity, ClimateEntity):
"""Representation of a Balboa spa climate entity."""
_attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF]
_attr_supported_features = (
ClimateEntityFeature.TARGET_TEMPERATURE
| ClimateEntityFeature.PRESET_MODE
| ClimateEntityFeature.TURN_OFF
| ClimateEntityFeature.TURN_ON
)
_attr_translation_key = DOMAIN
_attr_name = None
_enable_turn_on_off_backwards_compatibility = False
def __init__(self, client: SpaClient) -> None:
"""Initialize the climate entity."""
super().__init__(client, "Climate")
self._attr_preset_modes = [opt.name.lower() for opt in client.heat_mode.options]
self._blower: SpaControl | None = None
if client.blowers and (blower := client.blowers[0]) is not None:
self._blower = blower
self._attr_supported_features |= ClimateEntityFeature.FAN_MODE
self._fan_mode_map = {opt.name.lower(): opt for opt in blower.options}
self._attr_fan_modes = list(self._fan_mode_map)
@property
def hvac_mode(self) -> HVACMode | None:
"""Return the current HVAC mode."""
return HEAT_HVAC_MODE_MAP.get(self._client.heat_mode.state)
@property
def hvac_action(self) -> HVACAction:
"""Return the current operation mode."""
return HEAT_STATE_HVAC_ACTION_MAP[self._client.heat_state]
@property
def fan_mode(self) -> str | None:
"""Return the fan setting."""
if (blower := self._blower) is not None:
return blower.state.name.lower()
return None
@property
def precision(self) -> float:
"""Return the precision of the system."""
if self.hass.config.units.temperature_unit == UnitOfTemperature.CELSIUS:
return PRECISION_HALVES
return PRECISION_WHOLE
@property
def temperature_unit(self) -> str:
"""Return the unit of measurement used by the platform."""
return TEMPERATURE_UNIT_MAP[self._client.temperature_unit]
@property
def current_temperature(self) -> float | None:
"""Return the current temperature."""
return self._client.temperature
@property
def target_temperature(self) -> float:
"""Return the target temperature we try to reach."""
return self._client.target_temperature
@property
def min_temp(self) -> float:
"""Return the minimum temperature supported by the spa."""
return self._client.temperature_minimum
@property
def max_temp(self) -> float:
"""Return the minimum temperature supported by the spa."""
return self._client.temperature_maximum
@property
def preset_mode(self) -> str:
"""Return current preset mode."""
return self._client.heat_mode.state.name.lower()
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set a new target temperature."""
await self._client.set_temperature(kwargs[ATTR_TEMPERATURE])
async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set new preset mode."""
await self._client.heat_mode.set_state(HeatMode[preset_mode.upper()])
async def async_set_fan_mode(self, fan_mode: str) -> None:
"""Set new fan mode."""
if (blower := self._blower) is not None:
await blower.set_state(self._fan_mode_map[fan_mode])
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target hvac mode."""
await self._client.heat_mode.set_state(HVAC_HEAT_MODE_MAP[hvac_mode])