2323from .const import TUYA_DISCOVERY_NEW , DeviceCategory , DPCode
2424from .entity import TuyaEntity
2525from .models import DPCodeBooleanWrapper , DPCodeEnumWrapper , DPCodeIntegerWrapper
26- from .util import get_dpcode
2726
2827
2928class _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 )
131162class 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:
311347class 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