mirror of
https://github.com/home-assistant/core.git
synced 2025-12-24 12:59:34 +00:00
Migrate Tuya climate (hvac_mode/presets) to use wrapper class (#156933)
This commit is contained in:
@@ -27,6 +27,7 @@ from . import TuyaConfigEntry
|
||||
from .const import TUYA_DISCOVERY_NEW, DeviceCategory, DPCode, DPType
|
||||
from .entity import TuyaEntity
|
||||
from .models import (
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
IntegerTypeData,
|
||||
@@ -120,6 +121,12 @@ async def async_setup_entry(
|
||||
(DPCode.FAN_SPEED_ENUM, DPCode.LEVEL, DPCode.WINDSPEED),
|
||||
prefer_function=True,
|
||||
),
|
||||
hvac_mode_wrapper=DPCodeEnumWrapper.find_dpcode(
|
||||
device, DPCode.MODE, prefer_function=True
|
||||
),
|
||||
switch_wrapper=DPCodeBooleanWrapper.find_dpcode(
|
||||
device, DPCode.SWITCH, prefer_function=True
|
||||
),
|
||||
target_humidity_wrapper=_RoundedIntegerWrapper.find_dpcode(
|
||||
device, DPCode.HUMIDITY_SET, prefer_function=True
|
||||
),
|
||||
@@ -150,9 +157,11 @@ class TuyaClimateEntity(TuyaEntity, ClimateEntity):
|
||||
description: TuyaClimateEntityDescription,
|
||||
system_temperature_unit: UnitOfTemperature,
|
||||
*,
|
||||
current_humidity_wrapper: _RoundedIntegerWrapper | None = None,
|
||||
fan_mode_wrapper: DPCodeEnumWrapper | None = None,
|
||||
target_humidity_wrapper: _RoundedIntegerWrapper | None = None,
|
||||
current_humidity_wrapper: _RoundedIntegerWrapper | None,
|
||||
fan_mode_wrapper: DPCodeEnumWrapper | None,
|
||||
hvac_mode_wrapper: DPCodeEnumWrapper | None,
|
||||
switch_wrapper: DPCodeBooleanWrapper | None,
|
||||
target_humidity_wrapper: _RoundedIntegerWrapper | None,
|
||||
) -> None:
|
||||
"""Determine which values to use."""
|
||||
self._attr_target_temperature_step = 1.0
|
||||
@@ -161,6 +170,8 @@ class TuyaClimateEntity(TuyaEntity, ClimateEntity):
|
||||
super().__init__(device, device_manager)
|
||||
self._current_humidity_wrapper = current_humidity_wrapper
|
||||
self._fan_mode_wrapper = fan_mode_wrapper
|
||||
self._hvac_mode_wrapper = hvac_mode_wrapper
|
||||
self._switch_wrapper = switch_wrapper
|
||||
self._target_humidity_wrapper = target_humidity_wrapper
|
||||
|
||||
# If both temperature values for celsius and fahrenheit are present,
|
||||
@@ -234,12 +245,10 @@ class TuyaClimateEntity(TuyaEntity, ClimateEntity):
|
||||
# Determine HVAC modes
|
||||
self._attr_hvac_modes: list[HVACMode] = []
|
||||
self._hvac_to_tuya = {}
|
||||
if enum_type := find_dpcode(
|
||||
self.device, DPCode.MODE, dptype=DPType.ENUM, prefer_function=True
|
||||
):
|
||||
if hvac_mode_wrapper:
|
||||
self._attr_hvac_modes = [HVACMode.OFF]
|
||||
unknown_hvac_modes: list[str] = []
|
||||
for tuya_mode in enum_type.range:
|
||||
for tuya_mode in hvac_mode_wrapper.type_information.range:
|
||||
if tuya_mode in TUYA_HVAC_TO_HA:
|
||||
ha_mode = TUYA_HVAC_TO_HA[tuya_mode]
|
||||
self._hvac_to_tuya[ha_mode] = tuya_mode
|
||||
@@ -251,7 +260,7 @@ class TuyaClimateEntity(TuyaEntity, ClimateEntity):
|
||||
self._attr_hvac_modes.append(description.switch_only_hvac_mode)
|
||||
self._attr_preset_modes = unknown_hvac_modes
|
||||
self._attr_supported_features |= ClimateEntityFeature.PRESET_MODE
|
||||
elif get_dpcode(self.device, DPCode.SWITCH):
|
||||
elif switch_wrapper:
|
||||
self._attr_hvac_modes = [
|
||||
HVACMode.OFF,
|
||||
description.switch_only_hvac_mode,
|
||||
@@ -293,24 +302,31 @@ class TuyaClimateEntity(TuyaEntity, ClimateEntity):
|
||||
if get_dpcode(self.device, DPCode.SWITCH_VERTICAL):
|
||||
self._attr_swing_modes.append(SWING_VERTICAL)
|
||||
|
||||
if DPCode.SWITCH in self.device.function:
|
||||
if switch_wrapper:
|
||||
self._attr_supported_features |= (
|
||||
ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
def set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set new target hvac mode."""
|
||||
commands = [{"code": DPCode.SWITCH, "value": hvac_mode != HVACMode.OFF}]
|
||||
if hvac_mode in self._hvac_to_tuya:
|
||||
commands = []
|
||||
if self._switch_wrapper:
|
||||
commands.append(
|
||||
{"code": DPCode.MODE, "value": self._hvac_to_tuya[hvac_mode]}
|
||||
self._switch_wrapper.get_update_command(
|
||||
self.device, hvac_mode != HVACMode.OFF
|
||||
)
|
||||
)
|
||||
self._send_command(commands)
|
||||
if self._hvac_mode_wrapper and hvac_mode in self._hvac_to_tuya:
|
||||
commands.append(
|
||||
self._hvac_mode_wrapper.get_update_command(
|
||||
self.device, self._hvac_to_tuya[hvac_mode]
|
||||
)
|
||||
)
|
||||
await self._async_send_commands(commands)
|
||||
|
||||
def set_preset_mode(self, preset_mode: str) -> None:
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set new target preset mode."""
|
||||
commands = [{"code": DPCode.MODE, "value": preset_mode}]
|
||||
self._send_command(commands)
|
||||
await self._async_send_dpcode_update(self._hvac_mode_wrapper, preset_mode)
|
||||
|
||||
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
||||
"""Set new target fan mode."""
|
||||
@@ -406,34 +422,29 @@ class TuyaClimateEntity(TuyaEntity, ClimateEntity):
|
||||
@property
|
||||
def hvac_mode(self) -> HVACMode:
|
||||
"""Return hvac mode."""
|
||||
# If the switch off, hvac mode is off as well. Unless the switch
|
||||
# the switch is on or doesn't exists of course...
|
||||
if not self.device.status.get(DPCode.SWITCH, True):
|
||||
# If the switch is off, hvac mode is off as well.
|
||||
# Unless the switch doesn't exists of course...
|
||||
if (switch_status := self._read_wrapper(self._switch_wrapper)) is False:
|
||||
return HVACMode.OFF
|
||||
|
||||
if DPCode.MODE not in self.device.function:
|
||||
if self.device.status.get(DPCode.SWITCH, False):
|
||||
return self.entity_description.switch_only_hvac_mode
|
||||
return HVACMode.OFF
|
||||
# If the mode is known and maps to an HVAC mode, return it.
|
||||
if (mode := self._read_wrapper(self._hvac_mode_wrapper)) and (
|
||||
hvac_mode := TUYA_HVAC_TO_HA.get(mode)
|
||||
):
|
||||
return hvac_mode
|
||||
|
||||
if (
|
||||
mode := self.device.status.get(DPCode.MODE)
|
||||
) is not None and mode in TUYA_HVAC_TO_HA:
|
||||
return TUYA_HVAC_TO_HA[mode]
|
||||
|
||||
# If the switch is on, and the mode does not match any hvac mode.
|
||||
if self.device.status.get(DPCode.SWITCH, False):
|
||||
# If hvac_mode is unknown, return the switch only mode.
|
||||
if switch_status:
|
||||
return self.entity_description.switch_only_hvac_mode
|
||||
|
||||
return HVACMode.OFF
|
||||
|
||||
@property
|
||||
def preset_mode(self) -> str | None:
|
||||
"""Return preset mode."""
|
||||
if DPCode.MODE not in self.device.function:
|
||||
if self._hvac_mode_wrapper is None:
|
||||
return None
|
||||
|
||||
mode = self.device.status.get(DPCode.MODE)
|
||||
mode = self._read_wrapper(self._hvac_mode_wrapper)
|
||||
if mode in TUYA_HVAC_TO_HA:
|
||||
return None
|
||||
|
||||
@@ -463,10 +474,10 @@ class TuyaClimateEntity(TuyaEntity, ClimateEntity):
|
||||
|
||||
return SWING_OFF
|
||||
|
||||
def turn_on(self) -> None:
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn the device on, retaining current HVAC (if supported)."""
|
||||
self._send_command([{"code": DPCode.SWITCH, "value": True}])
|
||||
await self._async_send_dpcode_update(self._switch_wrapper, True)
|
||||
|
||||
def turn_off(self) -> None:
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn the device on, retaining current HVAC (if supported)."""
|
||||
self._send_command([{"code": DPCode.SWITCH, "value": False}])
|
||||
await self._async_send_dpcode_update(self._switch_wrapper, False)
|
||||
|
||||
@@ -66,6 +66,10 @@ class TuyaEntity(Entity):
|
||||
LOGGER.debug("Sending commands for device %s: %s", self.device.id, commands)
|
||||
self.device_manager.send_commands(self.device.id, commands)
|
||||
|
||||
async def _async_send_commands(self, commands: list[dict[str, Any]]) -> None:
|
||||
"""Send a list of commands to the device."""
|
||||
await self.hass.async_add_executor_job(self._send_command, commands)
|
||||
|
||||
def _read_wrapper(self, dpcode_wrapper: DPCodeWrapper | None) -> Any | None:
|
||||
"""Read the wrapper device status."""
|
||||
if dpcode_wrapper is None:
|
||||
|
||||
@@ -922,7 +922,7 @@
|
||||
]),
|
||||
'max_temp': 40.0,
|
||||
'min_temp': 5.0,
|
||||
'preset_mode': 'hold',
|
||||
'preset_mode': None,
|
||||
'preset_modes': list([
|
||||
'holiday',
|
||||
]),
|
||||
|
||||
Reference in New Issue
Block a user