Skip to content

Commit dea2f37

Browse files
authored
Migrate Tuya cover (state) to use wrapper class (home-assistant#156941)
1 parent 30cce68 commit dea2f37

File tree

1 file changed

+49
-21
lines changed

1 file changed

+49
-21
lines changed

homeassistant/components/tuya/cover.py

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
from .const import TUYA_DISCOVERY_NEW, DeviceCategory, DPCode
2424
from .entity import TuyaEntity
2525
from .models import DPCodeBooleanWrapper, DPCodeEnumWrapper, DPCodeIntegerWrapper
26-
from .util import get_dpcode
2726

2827

2928
class _DPCodePercentageMappingWrapper(DPCodeIntegerWrapper):
@@ -127,12 +126,46 @@ class _SpecialInstructionEnumWrapper(_InstructionEnumWrapper):
127126
stop_instruction = "STOP"
128127

129128

129+
class _IsClosedWrapper:
130+
"""Wrapper for checking if cover is closed."""
131+
132+
def is_closed(self, device: CustomerDevice) -> bool | None:
133+
return None
134+
135+
136+
class _IsClosedInvertedWrapper(DPCodeBooleanWrapper, _IsClosedWrapper):
137+
"""Boolean wrapper for checking if cover is closed (inverted)."""
138+
139+
def is_closed(self, device: CustomerDevice) -> bool | None:
140+
if (value := self.read_device_status(device)) is None:
141+
return None
142+
return not value
143+
144+
145+
class _IsClosedEnumWrapper(DPCodeEnumWrapper, _IsClosedWrapper):
146+
"""Enum wrapper for checking if state is closed."""
147+
148+
_MAPPINGS = {
149+
"close": True,
150+
"fully_close": True,
151+
"open": False,
152+
"fully_open": False,
153+
}
154+
155+
def is_closed(self, device: CustomerDevice) -> bool | None:
156+
if (value := self.read_device_status(device)) is None:
157+
return None
158+
return self._MAPPINGS.get(value)
159+
160+
130161
@dataclass(frozen=True)
131162
class TuyaCoverEntityDescription(CoverEntityDescription):
132163
"""Describe an Tuya cover entity."""
133164

134165
current_state: DPCode | tuple[DPCode, ...] | None = None
135-
current_state_inverse: bool = False
166+
current_state_wrapper: type[_IsClosedInvertedWrapper | _IsClosedEnumWrapper] = (
167+
_IsClosedEnumWrapper
168+
)
136169
current_position: DPCode | tuple[DPCode, ...] | None = None
137170
instruction_wrapper: type[_InstructionEnumWrapper] = _InstructionEnumWrapper
138171
position_wrapper: type[_DPCodePercentageMappingWrapper] = (
@@ -148,23 +181,23 @@ class TuyaCoverEntityDescription(CoverEntityDescription):
148181
translation_key="indexed_door",
149182
translation_placeholders={"index": "1"},
150183
current_state=DPCode.DOORCONTACT_STATE,
151-
current_state_inverse=True,
184+
current_state_wrapper=_IsClosedInvertedWrapper,
152185
device_class=CoverDeviceClass.GARAGE,
153186
),
154187
TuyaCoverEntityDescription(
155188
key=DPCode.SWITCH_2,
156189
translation_key="indexed_door",
157190
translation_placeholders={"index": "2"},
158191
current_state=DPCode.DOORCONTACT_STATE_2,
159-
current_state_inverse=True,
192+
current_state_wrapper=_IsClosedInvertedWrapper,
160193
device_class=CoverDeviceClass.GARAGE,
161194
),
162195
TuyaCoverEntityDescription(
163196
key=DPCode.SWITCH_3,
164197
translation_key="indexed_door",
165198
translation_placeholders={"index": "3"},
166199
current_state=DPCode.DOORCONTACT_STATE_3,
167-
current_state_inverse=True,
200+
current_state_wrapper=_IsClosedInvertedWrapper,
168201
device_class=CoverDeviceClass.GARAGE,
169202
),
170203
),
@@ -283,6 +316,9 @@ def async_discover_device(device_ids: list[str]) -> None:
283316
instruction_wrapper=_get_instruction_wrapper(
284317
device, description
285318
),
319+
current_state_wrapper=description.current_state_wrapper.find_dpcode(
320+
device, description.current_state
321+
),
286322
set_position=description.position_wrapper.find_dpcode(
287323
device, description.set_position, prefer_function=True
288324
),
@@ -311,7 +347,6 @@ def async_discover_device(device_ids: list[str]) -> None:
311347
class TuyaCoverEntity(TuyaEntity, CoverEntity):
312348
"""Tuya Cover Device."""
313349

314-
_current_state: DPCode | None = None
315350
entity_description: TuyaCoverEntityDescription
316351

317352
def __init__(
@@ -320,10 +355,11 @@ def __init__(
320355
device_manager: Manager,
321356
description: TuyaCoverEntityDescription,
322357
*,
323-
current_position: _DPCodePercentageMappingWrapper | None = None,
324-
instruction_wrapper: _InstructionWrapper | None = None,
325-
set_position: _DPCodePercentageMappingWrapper | None = None,
326-
tilt_position: _DPCodePercentageMappingWrapper | None = None,
358+
current_position: _DPCodePercentageMappingWrapper | None,
359+
current_state_wrapper: _IsClosedWrapper | None,
360+
instruction_wrapper: _InstructionWrapper | None,
361+
set_position: _DPCodePercentageMappingWrapper | None,
362+
tilt_position: _DPCodePercentageMappingWrapper | None,
327363
) -> None:
328364
"""Init Tuya Cover."""
329365
super().__init__(device, device_manager)
@@ -332,6 +368,7 @@ def __init__(
332368
self._attr_supported_features = CoverEntityFeature(0)
333369

334370
self._current_position = current_position or set_position
371+
self._current_state_wrapper = current_state_wrapper
335372
self._instruction_wrapper = instruction_wrapper
336373
self._set_position = set_position
337374
self._tilt_position = tilt_position
@@ -344,8 +381,6 @@ def __init__(
344381
if instruction_wrapper.get_stop_command(device) is not None:
345382
self._attr_supported_features |= CoverEntityFeature.STOP
346383

347-
self._current_state = get_dpcode(self.device, description.current_state)
348-
349384
if set_position:
350385
self._attr_supported_features |= CoverEntityFeature.SET_POSITION
351386
if tilt_position:
@@ -371,15 +406,8 @@ def is_closed(self) -> bool | None:
371406
if (position := self.current_cover_position) is not None:
372407
return position == 0
373408

374-
if (
375-
self._current_state is not None
376-
and (current_state := self.device.status.get(self._current_state))
377-
is not None
378-
and current_state != "stop"
379-
):
380-
return self.entity_description.current_state_inverse is not (
381-
current_state in (True, "close", "fully_close")
382-
)
409+
if self._current_state_wrapper:
410+
return self._current_state_wrapper.is_closed(self.device)
383411

384412
return None
385413

0 commit comments

Comments
 (0)