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
Jafar Atili 2022-10-03 21:34:02 +03:00 committed by GitHub
parent 9b7eb6b5a1
commit e8650dd4b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 190 additions and 4 deletions

View File

@ -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

View File

@ -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:

View File

@ -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()

View File

@ -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,