2626from . import TuyaConfigEntry
2727from .const import TUYA_DISCOVERY_NEW , DeviceCategory , DPCode , DPType
2828from .entity import TuyaEntity
29- from .models import IntegerTypeData , find_dpcode
29+ from .models import DPCodeIntegerWrapper , IntegerTypeData , find_dpcode
3030from .util import get_dpcode
3131
3232TUYA_HVAC_TO_HA = {
4141}
4242
4343
44+ class _RoundedIntegerWrapper (DPCodeIntegerWrapper ):
45+ """An integer that always rounds its value."""
46+
47+ def read_device_status (self , device : CustomerDevice ) -> int | None :
48+ """Read and round the device status."""
49+ if (value := super ().read_device_status (device )) is None :
50+ return None
51+ return round (value )
52+
53+
4454@dataclass (frozen = True , kw_only = True )
4555class TuyaClimateEntityDescription (ClimateEntityDescription ):
4656 """Describe an Tuya climate entity."""
@@ -97,6 +107,12 @@ def async_discover_device(device_ids: list[str]) -> None:
97107 manager ,
98108 CLIMATE_DESCRIPTIONS [device .category ],
99109 hass .config .units .temperature_unit ,
110+ current_humidity_wrapper = _RoundedIntegerWrapper .find_dpcode (
111+ device , DPCode .HUMIDITY_CURRENT
112+ ),
113+ target_humidity_wrapper = _RoundedIntegerWrapper .find_dpcode (
114+ device , DPCode .HUMIDITY_SET , prefer_function = True
115+ ),
100116 )
101117 )
102118 async_add_entities (entities )
@@ -111,10 +127,8 @@ def async_discover_device(device_ids: list[str]) -> None:
111127class TuyaClimateEntity (TuyaEntity , ClimateEntity ):
112128 """Tuya Climate Device."""
113129
114- _current_humidity : IntegerTypeData | None = None
115130 _current_temperature : IntegerTypeData | None = None
116131 _hvac_to_tuya : dict [str , str ]
117- _set_humidity : IntegerTypeData | None = None
118132 _set_temperature : IntegerTypeData | None = None
119133 entity_description : TuyaClimateEntityDescription
120134 _attr_name = None
@@ -125,12 +139,17 @@ def __init__(
125139 device_manager : Manager ,
126140 description : TuyaClimateEntityDescription ,
127141 system_temperature_unit : UnitOfTemperature ,
142+ * ,
143+ current_humidity_wrapper : _RoundedIntegerWrapper | None = None ,
144+ target_humidity_wrapper : _RoundedIntegerWrapper | None = None ,
128145 ) -> None :
129146 """Determine which values to use."""
130147 self ._attr_target_temperature_step = 1.0
131148 self .entity_description = description
132149
133150 super ().__init__ (device , device_manager )
151+ self ._current_humidity_wrapper = current_humidity_wrapper
152+ self ._target_humidity_wrapper = target_humidity_wrapper
134153
135154 # If both temperature values for celsius and fahrenheit are present,
136155 # use whatever the device is set to, with a fallback to celsius.
@@ -227,21 +246,14 @@ def __init__(
227246 ]
228247
229248 # Determine dpcode to use for setting the humidity
230- if int_type := find_dpcode (
231- self .device ,
232- DPCode .HUMIDITY_SET ,
233- dptype = DPType .INTEGER ,
234- prefer_function = True ,
235- ):
249+ if target_humidity_wrapper :
236250 self ._attr_supported_features |= ClimateEntityFeature .TARGET_HUMIDITY
237- self ._set_humidity = int_type
238- self ._attr_min_humidity = int (int_type .min_scaled )
239- self ._attr_max_humidity = int (int_type .max_scaled )
240-
241- # Determine dpcode to use for getting the current humidity
242- self ._current_humidity = find_dpcode (
243- self .device , DPCode .HUMIDITY_CURRENT , dptype = DPType .INTEGER
244- )
251+ self ._attr_min_humidity = round (
252+ target_humidity_wrapper .type_information .min_scaled
253+ )
254+ self ._attr_max_humidity = round (
255+ target_humidity_wrapper .type_information .max_scaled
256+ )
245257
246258 # Determine fan modes
247259 self ._fan_mode_dp_code : str | None = None
@@ -303,20 +315,9 @@ def set_fan_mode(self, fan_mode: str) -> None:
303315
304316 self ._send_command ([{"code" : self ._fan_mode_dp_code , "value" : fan_mode }])
305317
306- def set_humidity (self , humidity : int ) -> None :
318+ async def async_set_humidity (self , humidity : int ) -> None :
307319 """Set new target humidity."""
308- if TYPE_CHECKING :
309- # guarded by ClimateEntityFeature.TARGET_HUMIDITY
310- assert self ._set_humidity is not None
311-
312- self ._send_command (
313- [
314- {
315- "code" : self ._set_humidity .dpcode ,
316- "value" : self ._set_humidity .scale_value_back (humidity ),
317- }
318- ]
319- )
320+ await self ._async_send_dpcode_update (self ._target_humidity_wrapper , humidity )
320321
321322 def set_swing_mode (self , swing_mode : str ) -> None :
322323 """Set new target swing operation."""
@@ -382,14 +383,7 @@ def current_temperature(self) -> float | None:
382383 @property
383384 def current_humidity (self ) -> int | None :
384385 """Return the current humidity."""
385- if self ._current_humidity is None :
386- return None
387-
388- humidity = self .device .status .get (self ._current_humidity .dpcode )
389- if humidity is None :
390- return None
391-
392- return round (self ._current_humidity .scale_value (humidity ))
386+ return self ._read_wrapper (self ._current_humidity_wrapper )
393387
394388 @property
395389 def target_temperature (self ) -> float | None :
@@ -406,14 +400,7 @@ def target_temperature(self) -> float | None:
406400 @property
407401 def target_humidity (self ) -> int | None :
408402 """Return the humidity currently set to be reached."""
409- if self ._set_humidity is None :
410- return None
411-
412- humidity = self .device .status .get (self ._set_humidity .dpcode )
413- if humidity is None :
414- return None
415-
416- return round (self ._set_humidity .scale_value (humidity ))
403+ return self ._read_wrapper (self ._target_humidity_wrapper )
417404
418405 @property
419406 def hvac_mode (self ) -> HVACMode :
0 commit comments