1 """Support for Tuya Cover."""
3 from __future__
import annotations
5 from dataclasses
import dataclass
8 from tuya_sharing
import CustomerDevice, Manager
15 CoverEntityDescription,
22 from .
import TuyaConfigEntry
23 from .const
import TUYA_DISCOVERY_NEW, DPCode, DPType
24 from .entity
import IntegerTypeData, TuyaEntity
27 @dataclass(frozen=True)
29 """Describe an Tuya cover entity."""
31 current_state: DPCode |
None =
None
32 current_state_inverse: bool =
False
33 current_position: DPCode | tuple[DPCode, ...] |
None =
None
34 set_position: DPCode |
None =
None
35 open_instruction_value: str =
"open"
36 close_instruction_value: str =
"close"
37 stop_instruction_value: str =
"stop"
40 COVERS: dict[str, tuple[TuyaCoverEntityDescription, ...]] = {
47 translation_key=
"curtain",
48 current_state=DPCode.SITUATION_SET,
49 current_position=(DPCode.PERCENT_STATE, DPCode.PERCENT_CONTROL),
50 set_position=DPCode.PERCENT_CONTROL,
51 device_class=CoverDeviceClass.CURTAIN,
55 translation_key=
"curtain_2",
56 current_position=DPCode.PERCENT_STATE_2,
57 set_position=DPCode.PERCENT_CONTROL_2,
58 device_class=CoverDeviceClass.CURTAIN,
62 translation_key=
"curtain_3",
63 current_position=DPCode.PERCENT_STATE_3,
64 set_position=DPCode.PERCENT_CONTROL_3,
65 device_class=CoverDeviceClass.CURTAIN,
68 key=DPCode.MACH_OPERATE,
69 translation_key=
"curtain",
70 current_position=DPCode.POSITION,
71 set_position=DPCode.POSITION,
72 device_class=CoverDeviceClass.CURTAIN,
73 open_instruction_value=
"FZ",
74 close_instruction_value=
"ZZ",
75 stop_instruction_value=
"STOP",
81 translation_key=
"blind",
82 current_position=DPCode.PERCENT_CONTROL,
83 set_position=DPCode.PERCENT_CONTROL,
84 device_class=CoverDeviceClass.BLIND,
92 translation_key=
"door",
93 current_state=DPCode.DOORCONTACT_STATE,
94 current_state_inverse=
True,
95 device_class=CoverDeviceClass.GARAGE,
99 translation_key=
"door_2",
100 current_state=DPCode.DOORCONTACT_STATE_2,
101 current_state_inverse=
True,
102 device_class=CoverDeviceClass.GARAGE,
106 translation_key=
"door_3",
107 current_state=DPCode.DOORCONTACT_STATE_3,
108 current_state_inverse=
True,
109 device_class=CoverDeviceClass.GARAGE,
117 translation_key=
"curtain",
118 current_position=DPCode.PERCENT_CONTROL,
119 set_position=DPCode.PERCENT_CONTROL,
120 device_class=CoverDeviceClass.CURTAIN,
123 key=DPCode.CONTROL_2,
124 translation_key=
"curtain_2",
125 current_position=DPCode.PERCENT_CONTROL_2,
126 set_position=DPCode.PERCENT_CONTROL_2,
127 device_class=CoverDeviceClass.CURTAIN,
135 translation_key=
"curtain",
136 current_position=DPCode.PERCENT_STATE,
137 set_position=DPCode.PERCENT_CONTROL,
138 device_class=CoverDeviceClass.CURTAIN,
145 hass: HomeAssistant, entry: TuyaConfigEntry, async_add_entities: AddEntitiesCallback
147 """Set up Tuya cover dynamically through Tuya discovery."""
148 hass_data = entry.runtime_data
152 """Discover and add a discovered tuya cover."""
153 entities: list[TuyaCoverEntity] = []
154 for device_id
in device_ids:
155 device = hass_data.manager.device_map[device_id]
156 if descriptions := COVERS.get(device.category):
159 for description
in descriptions
161 description.key
in device.function
162 or description.key
in device.status_range
170 entry.async_on_unload(
176 """Tuya Cover Device."""
178 _current_position: IntegerTypeData |
None =
None
179 _set_position: IntegerTypeData |
None =
None
180 _tilt: IntegerTypeData |
None =
None
181 entity_description: TuyaCoverEntityDescription
185 device: CustomerDevice,
186 device_manager: Manager,
187 description: TuyaCoverEntityDescription,
189 """Init Tuya Cover."""
190 super().
__init__(device, device_manager)
197 if device.function[description.key].type ==
"Boolean":
199 CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE
202 description.key, dptype=DPType.ENUM, prefer_function=
True
204 if description.open_instruction_value
in enum_type.range:
206 if description.close_instruction_value
in enum_type.range:
208 if description.stop_instruction_value
in enum_type.range:
213 description.set_position, dptype=DPType.INTEGER, prefer_function=
True
222 description.current_position, dptype=DPType.INTEGER, prefer_function=
True
228 (DPCode.ANGLE_HORIZONTAL, DPCode.ANGLE_VERTICAL),
229 dptype=DPType.INTEGER,
230 prefer_function=
True,
237 """Return cover current position."""
245 self.
_current_position_current_position.remap_value_to(position, 0, 100, reverse=
True)
250 """Return current position of cover tilt.
252 None is unknown, 0 is closed, 100 is fully open.
254 if self.
_tilt_tilt
is None:
257 if (angle := self.
devicedevice.status.get(self.
_tilt_tilt.dpcode))
is None:
260 return round(self.
_tilt_tilt.remap_value_to(angle, 0, 100))
264 """Return true if cover is closed."""
268 current_state := self.
devicedevice.status.get(
275 current_state
in (
True,
"fully_close")
284 """Open the cover."""
285 value: bool | str =
True
287 self.
entity_descriptionentity_description.key, dptype=DPType.ENUM, prefer_function=
True
291 commands: list[dict[str, str | int]] = [
300 self.
_set_position_set_position.remap_value_from(100, 0, 100, reverse=
True),
309 value: bool | str =
False
311 self.
entity_descriptionentity_description.key, dptype=DPType.ENUM, prefer_function=
True
315 commands: list[dict[str, str | int]] = [
324 self.
_set_position_set_position.remap_value_from(0, 0, 100, reverse=
True),
332 """Move the cover to a specific position."""
335 "Cannot set position, device doesn't provide methods to set it"
344 kwargs[ATTR_POSITION], 0, 100, reverse=
True
352 """Stop the cover."""
363 """Move the cover tilt to a specific position."""
364 if self.
_tilt_tilt
is None:
366 "Cannot set tilt, device doesn't provide methods to set it"
372 "code": self.
_tilt_tilt.dpcode,
374 self.
_tilt_tilt.remap_value_from(
375 kwargs[ATTR_TILT_POSITION], 0, 100, reverse=
True
current_cover_tilt_position
int|None current_cover_position(self)
None set_cover_position(self, **Any kwargs)
None close_cover(self, **Any kwargs)
None set_cover_tilt_position(self, **Any kwargs)
bool|None is_closed(self)
int|None current_cover_position(self)
None open_cover(self, **Any kwargs)
None __init__(self, CustomerDevice device, Manager device_manager, TuyaCoverEntityDescription description)
None stop_cover(self, **Any kwargs)
None _send_command(self, list[dict[str, Any]] commands)
DPCode|EnumTypeData|IntegerTypeData|None find_dpcode(self, str|DPCode|tuple[DPCode,...]|None dpcodes, *bool prefer_function=False, DPType|None dptype=None)
IntegerTypeData|None find_dpcode(self, str|DPCode|tuple[DPCode,...]|None dpcodes, *bool prefer_function=False, Literal[DPType.INTEGER] dptype)
DPCode|None find_dpcode(self, str|DPCode|tuple[DPCode,...]|None dpcodes, *bool prefer_function=False)
EnumTypeData|None find_dpcode(self, str|DPCode|tuple[DPCode,...]|None dpcodes, *bool prefer_function=False, Literal[DPType.ENUM] dptype)
ElkSystem|None async_discover_device(HomeAssistant hass, str host)
None async_setup_entry(HomeAssistant hass, TuyaConfigEntry entry, AddEntitiesCallback async_add_entities)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)