Home Assistant Unofficial Reference 2024.12.1
vertical_cover.py
Go to the documentation of this file.
1 """Support for Overkiz Vertical Covers."""
2 
3 from __future__ import annotations
4 
5 from typing import Any, cast
6 
7 from pyoverkiz.enums import (
8  OverkizCommand,
9  OverkizCommandParam,
10  OverkizState,
11  UIClass,
12  UIWidget,
13 )
14 
16  ATTR_POSITION,
17  CoverDeviceClass,
18  CoverEntityFeature,
19 )
20 
21 from ..coordinator import OverkizDataUpdateCoordinator
22 from .generic_cover import (
23  COMMANDS_CLOSE_TILT,
24  COMMANDS_OPEN_TILT,
25  COMMANDS_STOP,
26  OverkizGenericCover,
27 )
28 
29 COMMANDS_OPEN = [OverkizCommand.OPEN, OverkizCommand.UP, OverkizCommand.CYCLE]
30 COMMANDS_CLOSE = [OverkizCommand.CLOSE, OverkizCommand.DOWN, OverkizCommand.CYCLE]
31 
32 OVERKIZ_DEVICE_TO_DEVICE_CLASS = {
33  UIClass.CURTAIN: CoverDeviceClass.CURTAIN,
34  UIClass.EXTERIOR_SCREEN: CoverDeviceClass.BLIND,
35  UIClass.EXTERIOR_VENETIAN_BLIND: CoverDeviceClass.BLIND,
36  UIClass.GARAGE_DOOR: CoverDeviceClass.GARAGE,
37  UIClass.GATE: CoverDeviceClass.GATE,
38  UIWidget.MY_FOX_SECURITY_CAMERA: CoverDeviceClass.SHUTTER,
39  UIClass.PERGOLA: CoverDeviceClass.AWNING,
40  UIClass.ROLLER_SHUTTER: CoverDeviceClass.SHUTTER,
41  UIClass.SWINGING_SHUTTER: CoverDeviceClass.SHUTTER,
42  UIClass.WINDOW: CoverDeviceClass.WINDOW,
43 }
44 
45 
47  """Representation of an Overkiz vertical cover."""
48 
49  def __init__(
50  self, device_url: str, coordinator: OverkizDataUpdateCoordinator
51  ) -> None:
52  """Initialize vertical cover."""
53  super().__init__(device_url, coordinator)
54  self._attr_device_class_attr_device_class = (
55  OVERKIZ_DEVICE_TO_DEVICE_CLASS.get(self.devicedevice.widget)
56  or OVERKIZ_DEVICE_TO_DEVICE_CLASS.get(self.devicedevice.ui_class)
57  or CoverDeviceClass.BLIND
58  )
59 
60  @property
61  def supported_features(self) -> CoverEntityFeature:
62  """Flag supported features."""
63  supported_features = super().supported_features
64 
65  if self.executorexecutor.has_command(OverkizCommand.SET_CLOSURE):
66  supported_features |= CoverEntityFeature.SET_POSITION
67 
68  if self.executorexecutor.has_command(*COMMANDS_OPEN):
69  supported_features |= CoverEntityFeature.OPEN
70 
71  if self.executorexecutor.has_command(*COMMANDS_STOP):
72  supported_features |= CoverEntityFeature.STOP
73 
74  if self.executorexecutor.has_command(*COMMANDS_CLOSE):
75  supported_features |= CoverEntityFeature.CLOSE
76 
77  return supported_features
78 
79  @property
80  def current_cover_position(self) -> int | None:
81  """Return current position of cover.
82 
83  None is unknown, 0 is closed, 100 is fully open.
84  """
85  position = self.executorexecutor.select_state(
86  OverkizState.CORE_CLOSURE,
87  OverkizState.CORE_CLOSURE_OR_ROCKER_POSITION,
88  OverkizState.CORE_PEDESTRIAN_POSITION,
89  )
90 
91  if position is None:
92  return None
93 
94  return 100 - cast(int, position)
95 
96  async def async_set_cover_position(self, **kwargs: Any) -> None:
97  """Move the cover to a specific position."""
98  position = 100 - kwargs[ATTR_POSITION]
99  await self.executorexecutor.async_execute_command(OverkizCommand.SET_CLOSURE, position)
100 
101  async def async_open_cover(self, **kwargs: Any) -> None:
102  """Open the cover."""
103  if command := self.executorexecutor.select_command(*COMMANDS_OPEN):
104  await self.executorexecutor.async_execute_command(command)
105 
106  async def async_close_cover(self, **kwargs: Any) -> None:
107  """Close the cover."""
108  if command := self.executorexecutor.select_command(*COMMANDS_CLOSE):
109  await self.executorexecutor.async_execute_command(command)
110 
111  @property
112  def is_opening(self) -> bool | None:
113  """Return if the cover is opening or not."""
114  if self.is_runningis_running(COMMANDS_OPEN + COMMANDS_OPEN_TILT):
115  return True
116 
117  # Check if cover is moving based on current state
118  is_moving = self.devicedevice.states.get(OverkizState.CORE_MOVING)
119  current_closure = self.devicedevice.states.get(OverkizState.CORE_CLOSURE)
120  target_closure = self.devicedevice.states.get(OverkizState.CORE_TARGET_CLOSURE)
121 
122  if not is_moving or not current_closure or not target_closure:
123  return None
124 
125  return cast(int, current_closure.value) > cast(int, target_closure.value)
126 
127  @property
128  def is_closing(self) -> bool | None:
129  """Return if the cover is closing or not."""
130  if self.is_runningis_running(COMMANDS_CLOSE + COMMANDS_CLOSE_TILT):
131  return True
132 
133  # Check if cover is moving based on current state
134  is_moving = self.devicedevice.states.get(OverkizState.CORE_MOVING)
135  current_closure = self.devicedevice.states.get(OverkizState.CORE_CLOSURE)
136  target_closure = self.devicedevice.states.get(OverkizState.CORE_TARGET_CLOSURE)
137 
138  if not is_moving or not current_closure or not target_closure:
139  return None
140 
141  return cast(int, current_closure.value) < cast(int, target_closure.value)
142 
143 
145  """Representation of an Overkiz Low Speed cover."""
146 
147  def __init__(
148  self,
149  device_url: str,
150  coordinator: OverkizDataUpdateCoordinator,
151  ) -> None:
152  """Initialize the device."""
153  super().__init__(device_url, coordinator)
154  self._attr_name_attr_name_attr_name = "Low speed"
155  self._attr_unique_id_attr_unique_id_attr_unique_id = f"{self._attr_unique_id}_low_speed"
156 
157  async def async_set_cover_position(self, **kwargs: Any) -> None:
158  """Move the cover to a specific position."""
159  await self.async_set_cover_position_low_speedasync_set_cover_position_low_speed(**kwargs)
160 
161  async def async_open_cover(self, **kwargs: Any) -> None:
162  """Open the cover."""
163  await self.async_set_cover_position_low_speedasync_set_cover_position_low_speed(**{ATTR_POSITION: 100})
164 
165  async def async_close_cover(self, **kwargs: Any) -> None:
166  """Close the cover."""
167  await self.async_set_cover_position_low_speedasync_set_cover_position_low_speed(**{ATTR_POSITION: 0})
168 
169  async def async_set_cover_position_low_speed(self, **kwargs: Any) -> None:
170  """Move the cover to a specific position with a low speed."""
171  position = 100 - kwargs.get(ATTR_POSITION, 0)
172 
173  await self.executorexecutor.async_execute_command(
174  OverkizCommand.SET_CLOSURE_AND_LINEAR_SPEED,
175  position,
176  OverkizCommandParam.LOWSPEED,
177  )
None __init__(self, str device_url, OverkizDataUpdateCoordinator coordinator)
None __init__(self, str device_url, OverkizDataUpdateCoordinator coordinator)