mirror of https://github.com/home-assistant/core
188 lines
6.2 KiB
Python
188 lines
6.2 KiB
Python
"""Support for SwitchBee climate."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from switchbee.api.central_unit import SwitchBeeDeviceOfflineError, SwitchBeeError
|
|
from switchbee.const import (
|
|
ApiAttribute,
|
|
ThermostatFanSpeed,
|
|
ThermostatMode,
|
|
ThermostatTemperatureUnit,
|
|
)
|
|
from switchbee.device import ApiStateCommand, SwitchBeeThermostat
|
|
|
|
from homeassistant.components.climate import (
|
|
FAN_AUTO,
|
|
FAN_HIGH,
|
|
FAN_LOW,
|
|
FAN_MEDIUM,
|
|
ClimateEntity,
|
|
ClimateEntityFeature,
|
|
HVACAction,
|
|
HVACMode,
|
|
)
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
|
from homeassistant.core import HomeAssistant, callback
|
|
from homeassistant.exceptions import HomeAssistantError
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
|
|
from .const import DOMAIN
|
|
from .coordinator import SwitchBeeCoordinator
|
|
from .entity import SwitchBeeDeviceEntity
|
|
|
|
FAN_SB_TO_HASS = {
|
|
ThermostatFanSpeed.AUTO: FAN_AUTO,
|
|
ThermostatFanSpeed.LOW: FAN_LOW,
|
|
ThermostatFanSpeed.MEDIUM: FAN_MEDIUM,
|
|
ThermostatFanSpeed.HIGH: FAN_HIGH,
|
|
}
|
|
|
|
FAN_HASS_TO_SB: dict[str | None, str] = {
|
|
FAN_AUTO: ThermostatFanSpeed.AUTO,
|
|
FAN_LOW: ThermostatFanSpeed.LOW,
|
|
FAN_MEDIUM: ThermostatFanSpeed.MEDIUM,
|
|
FAN_HIGH: ThermostatFanSpeed.HIGH,
|
|
}
|
|
|
|
HVAC_MODE_SB_TO_HASS = {
|
|
ThermostatMode.COOL: HVACMode.COOL,
|
|
ThermostatMode.HEAT: HVACMode.HEAT,
|
|
ThermostatMode.FAN: HVACMode.FAN_ONLY,
|
|
}
|
|
|
|
HVAC_MODE_HASS_TO_SB: dict[HVACMode | str | None, str] = {
|
|
HVACMode.COOL: ThermostatMode.COOL,
|
|
HVACMode.HEAT: ThermostatMode.HEAT,
|
|
HVACMode.FAN_ONLY: ThermostatMode.FAN,
|
|
}
|
|
|
|
HVAC_ACTION_SB_TO_HASS = {
|
|
ThermostatMode.COOL: HVACAction.COOLING,
|
|
ThermostatMode.HEAT: HVACAction.HEATING,
|
|
ThermostatMode.FAN: HVACAction.FAN,
|
|
}
|
|
|
|
HVAC_UNIT_SB_TO_HASS = {
|
|
ThermostatTemperatureUnit.CELSIUS: UnitOfTemperature.CELSIUS,
|
|
ThermostatTemperatureUnit.FAHRENHEIT: UnitOfTemperature.FAHRENHEIT,
|
|
}
|
|
|
|
SUPPORTED_FAN_MODES = [FAN_AUTO, FAN_HIGH, FAN_MEDIUM, FAN_LOW]
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
|
) -> None:
|
|
"""Set up SwitchBee climate."""
|
|
coordinator: SwitchBeeCoordinator = hass.data[DOMAIN][entry.entry_id]
|
|
async_add_entities(
|
|
SwitchBeeClimateEntity(switchbee_device, coordinator)
|
|
for switchbee_device in coordinator.data.values()
|
|
if isinstance(switchbee_device, SwitchBeeThermostat)
|
|
)
|
|
|
|
|
|
class SwitchBeeClimateEntity(SwitchBeeDeviceEntity[SwitchBeeThermostat], ClimateEntity):
|
|
"""Representation of a SwitchBee climate."""
|
|
|
|
_attr_fan_modes = SUPPORTED_FAN_MODES
|
|
_attr_target_temperature_step = 1
|
|
_enable_turn_on_off_backwards_compatibility = False
|
|
|
|
def __init__(
|
|
self,
|
|
device: SwitchBeeThermostat,
|
|
coordinator: SwitchBeeCoordinator,
|
|
) -> None:
|
|
"""Initialize the Switchbee switch."""
|
|
super().__init__(device, coordinator)
|
|
# set HVAC capabilities
|
|
self._attr_max_temp = device.max_temperature
|
|
self._attr_min_temp = device.min_temperature
|
|
self._attr_temperature_unit = HVAC_UNIT_SB_TO_HASS[device.temperature_unit]
|
|
self._attr_hvac_modes = [HVAC_MODE_SB_TO_HASS[mode] for mode in device.modes]
|
|
self._attr_hvac_modes.append(HVACMode.OFF)
|
|
self._attr_supported_features = (
|
|
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE
|
|
)
|
|
if len(self.hvac_modes) > 1:
|
|
self._attr_supported_features |= (
|
|
ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON
|
|
)
|
|
self._update_attrs_from_coordinator()
|
|
|
|
@callback
|
|
def _handle_coordinator_update(self) -> None:
|
|
"""Handle updated data from the coordinator."""
|
|
self._update_attrs_from_coordinator()
|
|
super()._handle_coordinator_update()
|
|
|
|
def _update_attrs_from_coordinator(self) -> None:
|
|
coordinator_device = self._get_coordinator_device()
|
|
|
|
self._attr_hvac_mode: HVACMode = (
|
|
HVACMode.OFF
|
|
if coordinator_device.state == ApiStateCommand.OFF
|
|
else HVAC_MODE_SB_TO_HASS[coordinator_device.mode]
|
|
)
|
|
self._attr_fan_mode = FAN_SB_TO_HASS[coordinator_device.fan]
|
|
self._attr_current_temperature = coordinator_device.temperature
|
|
self._attr_target_temperature = coordinator_device.target_temperature
|
|
|
|
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
|
"""Set hvac mode."""
|
|
|
|
if hvac_mode == HVACMode.OFF:
|
|
await self._operate(power=ApiStateCommand.OFF)
|
|
else:
|
|
await self._operate(
|
|
power=ApiStateCommand.ON, mode=HVAC_MODE_HASS_TO_SB[hvac_mode]
|
|
)
|
|
|
|
async def async_set_temperature(self, **kwargs: Any) -> None:
|
|
"""Set new target temperature."""
|
|
await self._operate(target_temperature=kwargs[ATTR_TEMPERATURE])
|
|
|
|
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
|
"""Set AC fan mode."""
|
|
await self._operate(fan=FAN_HASS_TO_SB[fan_mode])
|
|
|
|
async def _operate(
|
|
self,
|
|
power: str | None = None,
|
|
mode: str | None = None,
|
|
fan: str | None = None,
|
|
target_temperature: int | None = None,
|
|
) -> None:
|
|
"""Send request to central unit."""
|
|
|
|
if power is None:
|
|
power = ApiStateCommand.ON
|
|
if self.hvac_mode == HVACMode.OFF:
|
|
power = ApiStateCommand.OFF
|
|
if mode is None:
|
|
mode = HVAC_MODE_HASS_TO_SB[self.hvac_mode]
|
|
if fan is None:
|
|
fan = FAN_HASS_TO_SB[self.fan_mode]
|
|
if target_temperature is None:
|
|
target_temperature = int(self.target_temperature or 0)
|
|
|
|
state: dict[str, int | str] = {
|
|
ApiAttribute.POWER: power,
|
|
ApiAttribute.MODE: mode,
|
|
ApiAttribute.FAN: fan,
|
|
ApiAttribute.CONFIGURED_TEMPERATURE: target_temperature,
|
|
}
|
|
|
|
try:
|
|
await self.coordinator.api.set_state(self._device.id, state)
|
|
except (SwitchBeeError, SwitchBeeDeviceOfflineError) as exp:
|
|
raise HomeAssistantError(
|
|
f"Failed to set {self.name} state {state}, error: {exp!s}"
|
|
) from exp
|
|
|
|
await self.coordinator.async_refresh()
|