2727from .const import TUYA_DISCOVERY_NEW , DeviceCategory , DPCode , DPType
2828from .entity import TuyaEntity
2929from .models import (
30+ DPCodeBooleanWrapper ,
3031 DPCodeEnumWrapper ,
3132 DPCodeIntegerWrapper ,
3233 IntegerTypeData ,
@@ -120,6 +121,12 @@ def async_discover_device(device_ids: list[str]) -> None:
120121 (DPCode .FAN_SPEED_ENUM , DPCode .LEVEL , DPCode .WINDSPEED ),
121122 prefer_function = True ,
122123 ),
124+ hvac_mode_wrapper = DPCodeEnumWrapper .find_dpcode (
125+ device , DPCode .MODE , prefer_function = True
126+ ),
127+ switch_wrapper = DPCodeBooleanWrapper .find_dpcode (
128+ device , DPCode .SWITCH , prefer_function = True
129+ ),
123130 target_humidity_wrapper = _RoundedIntegerWrapper .find_dpcode (
124131 device , DPCode .HUMIDITY_SET , prefer_function = True
125132 ),
@@ -150,9 +157,11 @@ def __init__(
150157 description : TuyaClimateEntityDescription ,
151158 system_temperature_unit : UnitOfTemperature ,
152159 * ,
153- current_humidity_wrapper : _RoundedIntegerWrapper | None = None ,
154- fan_mode_wrapper : DPCodeEnumWrapper | None = None ,
155- target_humidity_wrapper : _RoundedIntegerWrapper | None = None ,
160+ current_humidity_wrapper : _RoundedIntegerWrapper | None ,
161+ fan_mode_wrapper : DPCodeEnumWrapper | None ,
162+ hvac_mode_wrapper : DPCodeEnumWrapper | None ,
163+ switch_wrapper : DPCodeBooleanWrapper | None ,
164+ target_humidity_wrapper : _RoundedIntegerWrapper | None ,
156165 ) -> None :
157166 """Determine which values to use."""
158167 self ._attr_target_temperature_step = 1.0
@@ -161,6 +170,8 @@ def __init__(
161170 super ().__init__ (device , device_manager )
162171 self ._current_humidity_wrapper = current_humidity_wrapper
163172 self ._fan_mode_wrapper = fan_mode_wrapper
173+ self ._hvac_mode_wrapper = hvac_mode_wrapper
174+ self ._switch_wrapper = switch_wrapper
164175 self ._target_humidity_wrapper = target_humidity_wrapper
165176
166177 # If both temperature values for celsius and fahrenheit are present,
@@ -234,12 +245,10 @@ def __init__(
234245 # Determine HVAC modes
235246 self ._attr_hvac_modes : list [HVACMode ] = []
236247 self ._hvac_to_tuya = {}
237- if enum_type := find_dpcode (
238- self .device , DPCode .MODE , dptype = DPType .ENUM , prefer_function = True
239- ):
248+ if hvac_mode_wrapper :
240249 self ._attr_hvac_modes = [HVACMode .OFF ]
241250 unknown_hvac_modes : list [str ] = []
242- for tuya_mode in enum_type .range :
251+ for tuya_mode in hvac_mode_wrapper . type_information .range :
243252 if tuya_mode in TUYA_HVAC_TO_HA :
244253 ha_mode = TUYA_HVAC_TO_HA [tuya_mode ]
245254 self ._hvac_to_tuya [ha_mode ] = tuya_mode
@@ -251,7 +260,7 @@ def __init__(
251260 self ._attr_hvac_modes .append (description .switch_only_hvac_mode )
252261 self ._attr_preset_modes = unknown_hvac_modes
253262 self ._attr_supported_features |= ClimateEntityFeature .PRESET_MODE
254- elif get_dpcode ( self . device , DPCode . SWITCH ) :
263+ elif switch_wrapper :
255264 self ._attr_hvac_modes = [
256265 HVACMode .OFF ,
257266 description .switch_only_hvac_mode ,
@@ -293,24 +302,31 @@ def __init__(
293302 if get_dpcode (self .device , DPCode .SWITCH_VERTICAL ):
294303 self ._attr_swing_modes .append (SWING_VERTICAL )
295304
296- if DPCode . SWITCH in self . device . function :
305+ if switch_wrapper :
297306 self ._attr_supported_features |= (
298307 ClimateEntityFeature .TURN_OFF | ClimateEntityFeature .TURN_ON
299308 )
300309
301- def set_hvac_mode (self , hvac_mode : HVACMode ) -> None :
310+ async def async_set_hvac_mode (self , hvac_mode : HVACMode ) -> None :
302311 """Set new target hvac mode."""
303- commands = [{ "code" : DPCode . SWITCH , "value" : hvac_mode != HVACMode . OFF } ]
304- if hvac_mode in self ._hvac_to_tuya :
312+ commands = []
313+ if self ._switch_wrapper :
305314 commands .append (
306- {"code" : DPCode .MODE , "value" : self ._hvac_to_tuya [hvac_mode ]}
315+ self ._switch_wrapper .get_update_command (
316+ self .device , hvac_mode != HVACMode .OFF
317+ )
307318 )
308- self ._send_command (commands )
319+ if self ._hvac_mode_wrapper and hvac_mode in self ._hvac_to_tuya :
320+ commands .append (
321+ self ._hvac_mode_wrapper .get_update_command (
322+ self .device , self ._hvac_to_tuya [hvac_mode ]
323+ )
324+ )
325+ await self ._async_send_commands (commands )
309326
310- def set_preset_mode (self , preset_mode : str ) -> None :
327+ async def async_set_preset_mode (self , preset_mode : str ) -> None :
311328 """Set new target preset mode."""
312- commands = [{"code" : DPCode .MODE , "value" : preset_mode }]
313- self ._send_command (commands )
329+ await self ._async_send_dpcode_update (self ._hvac_mode_wrapper , preset_mode )
314330
315331 async def async_set_fan_mode (self , fan_mode : str ) -> None :
316332 """Set new target fan mode."""
@@ -406,34 +422,29 @@ def target_humidity(self) -> int | None:
406422 @property
407423 def hvac_mode (self ) -> HVACMode :
408424 """Return hvac mode."""
409- # If the switch off, hvac mode is off as well. Unless the switch
410- # the switch is on or doesn't exists of course...
411- if not self .device .status .get (DPCode .SWITCH , True ):
412- return HVACMode .OFF
413-
414- if DPCode .MODE not in self .device .function :
415- if self .device .status .get (DPCode .SWITCH , False ):
416- return self .entity_description .switch_only_hvac_mode
425+ # If the switch is off, hvac mode is off as well.
426+ # Unless the switch doesn't exists of course...
427+ if (switch_status := self ._read_wrapper (self ._switch_wrapper )) is False :
417428 return HVACMode .OFF
418429
419- if (
420- mode := self .device .status .get (DPCode .MODE )
421- ) is not None and mode in TUYA_HVAC_TO_HA :
422- return TUYA_HVAC_TO_HA [mode ]
430+ # If the mode is known and maps to an HVAC mode, return it.
431+ if (mode := self ._read_wrapper (self ._hvac_mode_wrapper )) and (
432+ hvac_mode := TUYA_HVAC_TO_HA .get (mode )
433+ ):
434+ return hvac_mode
423435
424- # If the switch is on, and the mode does not match any hvac mode.
425- if self . device . status . get ( DPCode . SWITCH , False ) :
436+ # If hvac_mode is unknown, return the switch only mode.
437+ if switch_status :
426438 return self .entity_description .switch_only_hvac_mode
427-
428439 return HVACMode .OFF
429440
430441 @property
431442 def preset_mode (self ) -> str | None :
432443 """Return preset mode."""
433- if DPCode . MODE not in self . device . function :
444+ if self . _hvac_mode_wrapper is None :
434445 return None
435446
436- mode = self .device . status . get ( DPCode . MODE )
447+ mode = self ._read_wrapper ( self . _hvac_mode_wrapper )
437448 if mode in TUYA_HVAC_TO_HA :
438449 return None
439450
@@ -463,10 +474,10 @@ def swing_mode(self) -> str:
463474
464475 return SWING_OFF
465476
466- def turn_on (self ) -> None :
477+ async def async_turn_on (self ) -> None :
467478 """Turn the device on, retaining current HVAC (if supported)."""
468- self ._send_command ([{ "code" : DPCode . SWITCH , "value" : True }] )
479+ await self ._async_send_dpcode_update ( self . _switch_wrapper , True )
469480
470- def turn_off (self ) -> None :
481+ async def async_turn_off (self ) -> None :
471482 """Turn the device on, retaining current HVAC (if supported)."""
472- self ._send_command ([{ "code" : DPCode . SWITCH , "value" : False }] )
483+ await self ._async_send_dpcode_update ( self . _switch_wrapper , False )
0 commit comments