Migrate Tuya cover (state) to use wrapper class (#156941)

This commit is contained in:
epenet
2025-11-21 11:38:05 +01:00
committed by GitHub
parent 30cce68e0b
commit dea2f37e8f
+49 -21
View File
@@ -23,7 +23,6 @@ from . import TuyaConfigEntry
from .const import TUYA_DISCOVERY_NEW, DeviceCategory, DPCode
from .entity import TuyaEntity
from .models import DPCodeBooleanWrapper, DPCodeEnumWrapper, DPCodeIntegerWrapper
from .util import get_dpcode
class _DPCodePercentageMappingWrapper(DPCodeIntegerWrapper):
@@ -127,12 +126,46 @@ class _SpecialInstructionEnumWrapper(_InstructionEnumWrapper):
stop_instruction = "STOP"
class _IsClosedWrapper:
"""Wrapper for checking if cover is closed."""
def is_closed(self, device: CustomerDevice) -> bool | None:
return None
class _IsClosedInvertedWrapper(DPCodeBooleanWrapper, _IsClosedWrapper):
"""Boolean wrapper for checking if cover is closed (inverted)."""
def is_closed(self, device: CustomerDevice) -> bool | None:
if (value := self.read_device_status(device)) is None:
return None
return not value
class _IsClosedEnumWrapper(DPCodeEnumWrapper, _IsClosedWrapper):
"""Enum wrapper for checking if state is closed."""
_MAPPINGS = {
"close": True,
"fully_close": True,
"open": False,
"fully_open": False,
}
def is_closed(self, device: CustomerDevice) -> bool | None:
if (value := self.read_device_status(device)) is None:
return None
return self._MAPPINGS.get(value)
@dataclass(frozen=True)
class TuyaCoverEntityDescription(CoverEntityDescription):
"""Describe an Tuya cover entity."""
current_state: DPCode | tuple[DPCode, ...] | None = None
current_state_inverse: bool = False
current_state_wrapper: type[_IsClosedInvertedWrapper | _IsClosedEnumWrapper] = (
_IsClosedEnumWrapper
)
current_position: DPCode | tuple[DPCode, ...] | None = None
instruction_wrapper: type[_InstructionEnumWrapper] = _InstructionEnumWrapper
position_wrapper: type[_DPCodePercentageMappingWrapper] = (
@@ -148,7 +181,7 @@ COVERS: dict[DeviceCategory, tuple[TuyaCoverEntityDescription, ...]] = {
translation_key="indexed_door",
translation_placeholders={"index": "1"},
current_state=DPCode.DOORCONTACT_STATE,
current_state_inverse=True,
current_state_wrapper=_IsClosedInvertedWrapper,
device_class=CoverDeviceClass.GARAGE,
),
TuyaCoverEntityDescription(
@@ -156,7 +189,7 @@ COVERS: dict[DeviceCategory, tuple[TuyaCoverEntityDescription, ...]] = {
translation_key="indexed_door",
translation_placeholders={"index": "2"},
current_state=DPCode.DOORCONTACT_STATE_2,
current_state_inverse=True,
current_state_wrapper=_IsClosedInvertedWrapper,
device_class=CoverDeviceClass.GARAGE,
),
TuyaCoverEntityDescription(
@@ -164,7 +197,7 @@ COVERS: dict[DeviceCategory, tuple[TuyaCoverEntityDescription, ...]] = {
translation_key="indexed_door",
translation_placeholders={"index": "3"},
current_state=DPCode.DOORCONTACT_STATE_3,
current_state_inverse=True,
current_state_wrapper=_IsClosedInvertedWrapper,
device_class=CoverDeviceClass.GARAGE,
),
),
@@ -283,6 +316,9 @@ async def async_setup_entry(
instruction_wrapper=_get_instruction_wrapper(
device, description
),
current_state_wrapper=description.current_state_wrapper.find_dpcode(
device, description.current_state
),
set_position=description.position_wrapper.find_dpcode(
device, description.set_position, prefer_function=True
),
@@ -311,7 +347,6 @@ async def async_setup_entry(
class TuyaCoverEntity(TuyaEntity, CoverEntity):
"""Tuya Cover Device."""
_current_state: DPCode | None = None
entity_description: TuyaCoverEntityDescription
def __init__(
@@ -320,10 +355,11 @@ class TuyaCoverEntity(TuyaEntity, CoverEntity):
device_manager: Manager,
description: TuyaCoverEntityDescription,
*,
current_position: _DPCodePercentageMappingWrapper | None = None,
instruction_wrapper: _InstructionWrapper | None = None,
set_position: _DPCodePercentageMappingWrapper | None = None,
tilt_position: _DPCodePercentageMappingWrapper | None = None,
current_position: _DPCodePercentageMappingWrapper | None,
current_state_wrapper: _IsClosedWrapper | None,
instruction_wrapper: _InstructionWrapper | None,
set_position: _DPCodePercentageMappingWrapper | None,
tilt_position: _DPCodePercentageMappingWrapper | None,
) -> None:
"""Init Tuya Cover."""
super().__init__(device, device_manager)
@@ -332,6 +368,7 @@ class TuyaCoverEntity(TuyaEntity, CoverEntity):
self._attr_supported_features = CoverEntityFeature(0)
self._current_position = current_position or set_position
self._current_state_wrapper = current_state_wrapper
self._instruction_wrapper = instruction_wrapper
self._set_position = set_position
self._tilt_position = tilt_position
@@ -344,8 +381,6 @@ class TuyaCoverEntity(TuyaEntity, CoverEntity):
if instruction_wrapper.get_stop_command(device) is not None:
self._attr_supported_features |= CoverEntityFeature.STOP
self._current_state = get_dpcode(self.device, description.current_state)
if set_position:
self._attr_supported_features |= CoverEntityFeature.SET_POSITION
if tilt_position:
@@ -371,15 +406,8 @@ class TuyaCoverEntity(TuyaEntity, CoverEntity):
if (position := self.current_cover_position) is not None:
return position == 0
if (
self._current_state is not None
and (current_state := self.device.status.get(self._current_state))
is not None
and current_state != "stop"
):
return self.entity_description.current_state_inverse is not (
current_state in (True, "close", "fully_close")
)
if self._current_state_wrapper:
return self._current_state_wrapper.is_closed(self.device)
return None