Skip to content

Commit 5a5a106

Browse files
epenetCopilot
andauthored
Migrate Tuya humidifier to use wrapper class (home-assistant#156572)
Co-authored-by: Copilot <[email protected]>
1 parent 796b421 commit 5a5a106

File tree

2 files changed

+122
-203
lines changed

2 files changed

+122
-203
lines changed

homeassistant/components/tuya/humidifier.py

Lines changed: 67 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,22 @@
1818
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
1919

2020
from . import TuyaConfigEntry
21-
from .const import TUYA_DISCOVERY_NEW, DeviceCategory, DPCode, DPType
21+
from .const import TUYA_DISCOVERY_NEW, DeviceCategory, DPCode
2222
from .entity import TuyaEntity
23-
from .models import IntegerTypeData, find_dpcode
23+
from .models import DPCodeBooleanWrapper, DPCodeEnumWrapper, DPCodeIntegerWrapper
2424
from .util import ActionDPCodeNotFoundError, get_dpcode
2525

2626

27+
class _RoundedIntegerWrapper(DPCodeIntegerWrapper):
28+
"""An integer that always rounds its value."""
29+
30+
def read_device_status(self, device: CustomerDevice) -> int | None:
31+
"""Read and round the device status."""
32+
if (value := super().read_device_status(device)) is None:
33+
return None
34+
return round(value)
35+
36+
2737
@dataclass(frozen=True)
2838
class TuyaHumidifierEntityDescription(HumidifierEntityDescription):
2939
"""Describe an Tuya (de)humidifier entity."""
@@ -84,7 +94,27 @@ def async_discover_device(device_ids: list[str]) -> None:
8494
if (
8595
description := HUMIDIFIERS.get(device.category)
8696
) and _has_a_valid_dpcode(device, description):
87-
entities.append(TuyaHumidifierEntity(device, manager, description))
97+
entities.append(
98+
TuyaHumidifierEntity(
99+
device,
100+
manager,
101+
description,
102+
current_humidity_wrapper=_RoundedIntegerWrapper.find_dpcode(
103+
device, description.current_humidity
104+
),
105+
mode_wrapper=DPCodeEnumWrapper.find_dpcode(
106+
device, DPCode.MODE, prefer_function=True
107+
),
108+
switch_wrapper=DPCodeBooleanWrapper.find_dpcode(
109+
device,
110+
description.dpcode or DPCode(description.key),
111+
prefer_function=True,
112+
),
113+
target_humidity_wrapper=_RoundedIntegerWrapper.find_dpcode(
114+
device, description.humidity, prefer_function=True
115+
),
116+
)
117+
)
88118
async_add_entities(entities)
89119

90120
async_discover_device([*manager.device_map])
@@ -97,9 +127,6 @@ def async_discover_device(device_ids: list[str]) -> None:
97127
class TuyaHumidifierEntity(TuyaEntity, HumidifierEntity):
98128
"""Tuya (de)humidifier Device."""
99129

100-
_current_humidity: IntegerTypeData | None = None
101-
_set_humidity: IntegerTypeData | None = None
102-
_switch_dpcode: DPCode | None = None
103130
entity_description: TuyaHumidifierEntityDescription
104131
_attr_name = None
105132

@@ -108,115 +135,83 @@ def __init__(
108135
device: CustomerDevice,
109136
device_manager: Manager,
110137
description: TuyaHumidifierEntityDescription,
138+
*,
139+
current_humidity_wrapper: _RoundedIntegerWrapper | None = None,
140+
mode_wrapper: DPCodeEnumWrapper | None = None,
141+
switch_wrapper: DPCodeBooleanWrapper | None = None,
142+
target_humidity_wrapper: _RoundedIntegerWrapper | None = None,
111143
) -> None:
112144
"""Init Tuya (de)humidifier."""
113145
super().__init__(device, device_manager)
114146
self.entity_description = description
115147
self._attr_unique_id = f"{super().unique_id}{description.key}"
116148

117-
# Determine main switch DPCode
118-
self._switch_dpcode = get_dpcode(
119-
self.device, description.dpcode or DPCode(description.key)
120-
)
149+
self._current_humidity_wrapper = current_humidity_wrapper
150+
self._mode_wrapper = mode_wrapper
151+
self._switch_wrapper = switch_wrapper
152+
self._target_humidity_wrapper = target_humidity_wrapper
121153

122154
# Determine humidity parameters
123-
if int_type := find_dpcode(
124-
self.device,
125-
description.humidity,
126-
dptype=DPType.INTEGER,
127-
prefer_function=True,
128-
):
129-
self._set_humidity = int_type
130-
self._attr_min_humidity = int(int_type.min_scaled)
131-
self._attr_max_humidity = int(int_type.max_scaled)
132-
133-
# Determine current humidity DPCode
134-
if int_type := find_dpcode(
135-
self.device,
136-
description.current_humidity,
137-
dptype=DPType.INTEGER,
138-
):
139-
self._current_humidity = int_type
155+
if target_humidity_wrapper:
156+
self._attr_min_humidity = round(
157+
target_humidity_wrapper.type_information.min_scaled
158+
)
159+
self._attr_max_humidity = round(
160+
target_humidity_wrapper.type_information.max_scaled
161+
)
140162

141163
# Determine mode support and provided modes
142-
if enum_type := find_dpcode(
143-
self.device, DPCode.MODE, dptype=DPType.ENUM, prefer_function=True
144-
):
164+
if mode_wrapper:
145165
self._attr_supported_features |= HumidifierEntityFeature.MODES
146-
self._attr_available_modes = enum_type.range
166+
self._attr_available_modes = mode_wrapper.type_information.range
147167

148168
@property
149-
def is_on(self) -> bool:
169+
def is_on(self) -> bool | None:
150170
"""Return the device is on or off."""
151-
if self._switch_dpcode is None:
152-
return False
153-
return self.device.status.get(self._switch_dpcode, False)
171+
return self._read_wrapper(self._switch_wrapper)
154172

155173
@property
156174
def mode(self) -> str | None:
157175
"""Return the current mode."""
158-
return self.device.status.get(DPCode.MODE)
176+
return self._read_wrapper(self._mode_wrapper)
159177

160178
@property
161179
def target_humidity(self) -> int | None:
162180
"""Return the humidity we try to reach."""
163-
if self._set_humidity is None:
164-
return None
165-
166-
humidity = self.device.status.get(self._set_humidity.dpcode)
167-
if humidity is None:
168-
return None
169-
170-
return round(self._set_humidity.scale_value(humidity))
181+
return self._read_wrapper(self._target_humidity_wrapper)
171182

172183
@property
173184
def current_humidity(self) -> int | None:
174185
"""Return the current humidity."""
175-
if self._current_humidity is None:
176-
return None
186+
return self._read_wrapper(self._current_humidity_wrapper)
177187

178-
if (
179-
current_humidity := self.device.status.get(self._current_humidity.dpcode)
180-
) is None:
181-
return None
182-
183-
return round(self._current_humidity.scale_value(current_humidity))
184-
185-
def turn_on(self, **kwargs: Any) -> None:
188+
async def async_turn_on(self, **kwargs: Any) -> None:
186189
"""Turn the device on."""
187-
if self._switch_dpcode is None:
190+
if self._switch_wrapper is None:
188191
raise ActionDPCodeNotFoundError(
189192
self.device,
190193
self.entity_description.dpcode or self.entity_description.key,
191194
)
192-
self._send_command([{"code": self._switch_dpcode, "value": True}])
195+
await self._async_send_dpcode_update(self._switch_wrapper, True)
193196

194-
def turn_off(self, **kwargs: Any) -> None:
197+
async def async_turn_off(self, **kwargs: Any) -> None:
195198
"""Turn the device off."""
196-
if self._switch_dpcode is None:
199+
if self._switch_wrapper is None:
197200
raise ActionDPCodeNotFoundError(
198201
self.device,
199202
self.entity_description.dpcode or self.entity_description.key,
200203
)
201-
self._send_command([{"code": self._switch_dpcode, "value": False}])
204+
await self._async_send_dpcode_update(self._switch_wrapper, False)
202205

203-
def set_humidity(self, humidity: int) -> None:
206+
async def async_set_humidity(self, humidity: int) -> None:
204207
"""Set new target humidity."""
205-
if self._set_humidity is None:
208+
if self._target_humidity_wrapper is None:
206209
raise ActionDPCodeNotFoundError(
207210
self.device,
208211
self.entity_description.humidity,
209212
)
213+
await self._async_send_dpcode_update(self._target_humidity_wrapper, humidity)
210214

211-
self._send_command(
212-
[
213-
{
214-
"code": self._set_humidity.dpcode,
215-
"value": self._set_humidity.scale_value_back(humidity),
216-
}
217-
]
218-
)
219-
220-
def set_mode(self, mode: str) -> None:
215+
async def async_set_mode(self, mode: str) -> None:
221216
"""Set new target preset mode."""
222-
self._send_command([{"code": DPCode.MODE, "value": mode}])
217+
await self._async_send_dpcode_update(self._mode_wrapper, mode)

0 commit comments

Comments
 (0)