Add climate platform to switchbee integration (#78385)
* Added Climate platform to switchbee integration * uploaded missing file * Applied code review feedback from other PR * Addressed comments from previous PRs * fixed misspell error * fixed mistake in the code * added type hints * fixes * fixes * Update homeassistant/components/switchbee/climate.py Co-authored-by: Shay Levy <levyshay1@gmail.com> * Update homeassistant/components/switchbee/entity.py Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> * Update homeassistant/components/switchbee/climate.py Co-authored-by: Shay Levy <levyshay1@gmail.com> * Update homeassistant/components/switchbee/climate.py Co-authored-by: Shay Levy <levyshay1@gmail.com> * Update homeassistant/components/switchbee/climate.py Co-authored-by: Shay Levy <levyshay1@gmail.com> * Update homeassistant/components/switchbee/climate.py Co-authored-by: Shay Levy <levyshay1@gmail.com> * Update homeassistant/components/switchbee/climate.py Co-authored-by: Shay Levy <levyshay1@gmail.com> * Update homeassistant/components/switchbee/climate.py Co-authored-by: Shay Levy <levyshay1@gmail.com> * fixes * Update homeassistant/components/switchbee/climate.py Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> * fixes * Update homeassistant/components/switchbee/climate.py * Update homeassistant/components/switchbee/climate.py Co-authored-by: Shay Levy <levyshay1@gmail.com> * more fixes Co-authored-by: Shay Levy <levyshay1@gmail.com> Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>pull/79556/head
parent
9b7eb6b5a1
commit
e8650dd4b7
|
@ -1232,6 +1232,7 @@ omit =
|
|||
homeassistant/components/swisscom/device_tracker.py
|
||||
homeassistant/components/switchbee/__init__.py
|
||||
homeassistant/components/switchbee/button.py
|
||||
homeassistant/components/switchbee/climate.py
|
||||
homeassistant/components/switchbee/coordinator.py
|
||||
homeassistant/components/switchbee/cover.py
|
||||
homeassistant/components/switchbee/entity.py
|
||||
|
|
|
@ -15,6 +15,7 @@ from .coordinator import SwitchBeeCoordinator
|
|||
|
||||
PLATFORMS: list[Platform] = [
|
||||
Platform.BUTTON,
|
||||
Platform.CLIMATE,
|
||||
Platform.COVER,
|
||||
Platform.LIGHT,
|
||||
Platform.SWITCH,
|
||||
|
@ -27,7 +28,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
central_unit = entry.data[CONF_HOST]
|
||||
user = entry.data[CONF_USERNAME]
|
||||
password = entry.data[CONF_PASSWORD]
|
||||
|
||||
websession = async_get_clientsession(hass, verify_ssl=False)
|
||||
api = CentralUnitAPI(central_unit, user, password, websession)
|
||||
try:
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
"""Support for SwitchBee climate."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from switchbee.api 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, TEMP_CELSIUS, TEMP_FAHRENHEIT
|
||||
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: TEMP_CELSIUS,
|
||||
ThermostatTemperatureUnit.FAHRENHEIT: TEMP_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_supported_features = (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE
|
||||
)
|
||||
_attr_fan_modes = SUPPORTED_FAN_MODES
|
||||
_attr_target_temperature_step = 1
|
||||
|
||||
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.unit]
|
||||
self._attr_hvac_modes = [HVAC_MODE_SB_TO_HASS[mode] for mode in device.modes]
|
||||
self._attr_hvac_modes.append(HVACMode.OFF)
|
||||
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: {str(exp)}"
|
||||
) from exp
|
||||
else:
|
||||
await self.coordinator.async_refresh()
|
|
@ -4,7 +4,7 @@ from typing import Generic, TypeVar, cast
|
|||
|
||||
from switchbee import SWITCHBEE_BRAND
|
||||
from switchbee.api import SwitchBeeDeviceOfflineError, SwitchBeeError
|
||||
from switchbee.device import SwitchBeeBaseDevice
|
||||
from switchbee.device import DeviceType, SwitchBeeBaseDevice
|
||||
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
@ -46,12 +46,15 @@ class SwitchBeeDeviceEntity(SwitchBeeEntity[_DeviceTypeT]):
|
|||
"""Initialize the Switchbee device."""
|
||||
super().__init__(device, coordinator)
|
||||
self._is_online: bool = True
|
||||
identifier = (
|
||||
device.id if device.type == DeviceType.Thermostat else device.unit_id
|
||||
)
|
||||
self._attr_device_info = DeviceInfo(
|
||||
name=f"SwitchBee {device.unit_id}",
|
||||
name=f"SwitchBee {identifier}",
|
||||
identifiers={
|
||||
(
|
||||
DOMAIN,
|
||||
f"{device.unit_id}-{coordinator.mac_formatted}",
|
||||
f"{identifier}-{coordinator.mac_formatted}",
|
||||
)
|
||||
},
|
||||
manufacturer=SWITCHBEE_BRAND,
|
||||
|
|
Loading…
Reference in New Issue