Home Assistant Unofficial Reference 2024.12.1
cover.py
Go to the documentation of this file.
1 """Support for KNX/IP covers."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 from typing import Any
7 
8 from xknx.devices import Cover as XknxCover
9 
10 from homeassistant import config_entries
12  ATTR_POSITION,
13  ATTR_TILT_POSITION,
14  CoverDeviceClass,
15  CoverEntity,
16  CoverEntityFeature,
17 )
18 from homeassistant.const import (
19  CONF_DEVICE_CLASS,
20  CONF_ENTITY_CATEGORY,
21  CONF_NAME,
22  Platform,
23 )
24 from homeassistant.core import HomeAssistant
25 from homeassistant.helpers.entity_platform import AddEntitiesCallback
26 from homeassistant.helpers.typing import ConfigType
27 
28 from . import KNXModule
29 from .const import KNX_MODULE_KEY
30 from .entity import KnxYamlEntity
31 from .schema import CoverSchema
32 
33 
35  hass: HomeAssistant,
36  config_entry: config_entries.ConfigEntry,
37  async_add_entities: AddEntitiesCallback,
38 ) -> None:
39  """Set up cover(s) for KNX platform."""
40  knx_module = hass.data[KNX_MODULE_KEY]
41  config: list[ConfigType] = knx_module.config_yaml[Platform.COVER]
42 
43  async_add_entities(KNXCover(knx_module, entity_config) for entity_config in config)
44 
45 
47  """Representation of a KNX cover."""
48 
49  _device: XknxCover
50 
51  def __init__(self, knx_module: KNXModule, config: ConfigType) -> None:
52  """Initialize the cover."""
53  super().__init__(
54  knx_module=knx_module,
55  device=XknxCover(
56  xknx=knx_module.xknx,
57  name=config[CONF_NAME],
58  group_address_long=config.get(CoverSchema.CONF_MOVE_LONG_ADDRESS),
59  group_address_short=config.get(CoverSchema.CONF_MOVE_SHORT_ADDRESS),
60  group_address_stop=config.get(CoverSchema.CONF_STOP_ADDRESS),
61  group_address_position_state=config.get(
62  CoverSchema.CONF_POSITION_STATE_ADDRESS
63  ),
64  group_address_angle=config.get(CoverSchema.CONF_ANGLE_ADDRESS),
65  group_address_angle_state=config.get(
66  CoverSchema.CONF_ANGLE_STATE_ADDRESS
67  ),
68  group_address_position=config.get(CoverSchema.CONF_POSITION_ADDRESS),
69  travel_time_down=config[CoverSchema.CONF_TRAVELLING_TIME_DOWN],
70  travel_time_up=config[CoverSchema.CONF_TRAVELLING_TIME_UP],
71  invert_updown=config[CoverSchema.CONF_INVERT_UPDOWN],
72  invert_position=config[CoverSchema.CONF_INVERT_POSITION],
73  invert_angle=config[CoverSchema.CONF_INVERT_ANGLE],
74  ),
75  )
76  self._unsubscribe_auto_updater: Callable[[], None] | None = None
77 
78  self._attr_entity_category_attr_entity_category = config.get(CONF_ENTITY_CATEGORY)
79  _supports_tilt = False
80  self._attr_supported_features_attr_supported_features = (
81  CoverEntityFeature.CLOSE
82  | CoverEntityFeature.OPEN
83  | CoverEntityFeature.SET_POSITION
84  )
85  if self._device_device.step.writable:
86  _supports_tilt = True
87  self._attr_supported_features_attr_supported_features |= (
88  CoverEntityFeature.CLOSE_TILT
89  | CoverEntityFeature.OPEN_TILT
90  | CoverEntityFeature.STOP_TILT
91  )
92  if self._device_device.supports_angle:
93  _supports_tilt = True
94  self._attr_supported_features_attr_supported_features |= CoverEntityFeature.SET_TILT_POSITION
95  if self._device_device.supports_stop:
96  self._attr_supported_features_attr_supported_features |= CoverEntityFeature.STOP
97  if _supports_tilt:
98  self._attr_supported_features_attr_supported_features |= CoverEntityFeature.STOP_TILT
99 
100  self._attr_device_class_attr_device_class = config.get(CONF_DEVICE_CLASS) or (
101  CoverDeviceClass.BLIND if _supports_tilt else None
102  )
103  self._attr_unique_id_attr_unique_id = (
104  f"{self._device.updown.group_address}_"
105  f"{self._device.position_target.group_address}"
106  )
107 
108  @property
109  def current_cover_position(self) -> int | None:
110  """Return the current position of the cover.
111 
112  None is unknown, 0 is closed, 100 is fully open.
113  """
114  # In KNX 0 is open, 100 is closed.
115  if (pos := self._device_device.current_position()) is not None:
116  return 100 - pos
117  return None
118 
119  @property
120  def is_closed(self) -> bool | None:
121  """Return if the cover is closed."""
122  # state shall be "unknown" when xknx travelcalculator is not initialized
123  if self._device_device.current_position() is None:
124  return None
125  return self._device_device.is_closed()
126 
127  @property
128  def is_opening(self) -> bool:
129  """Return if the cover is opening or not."""
130  return self._device_device.is_opening()
131 
132  @property
133  def is_closing(self) -> bool:
134  """Return if the cover is closing or not."""
135  return self._device_device.is_closing()
136 
137  async def async_close_cover(self, **kwargs: Any) -> None:
138  """Close the cover."""
139  await self._device_device.set_down()
140 
141  async def async_open_cover(self, **kwargs: Any) -> None:
142  """Open the cover."""
143  await self._device_device.set_up()
144 
145  async def async_set_cover_position(self, **kwargs: Any) -> None:
146  """Move the cover to a specific position."""
147  knx_position = 100 - kwargs[ATTR_POSITION]
148  await self._device_device.set_position(knx_position)
149 
150  async def async_stop_cover(self, **kwargs: Any) -> None:
151  """Stop the cover."""
152  await self._device_device.stop()
153 
154  @property
155  def current_cover_tilt_position(self) -> int | None:
156  """Return current tilt position of cover."""
157  if (angle := self._device_device.current_angle()) is not None:
158  return 100 - angle
159  return None
160 
161  async def async_set_cover_tilt_position(self, **kwargs: Any) -> None:
162  """Move the cover tilt to a specific position."""
163  knx_tilt_position = 100 - kwargs[ATTR_TILT_POSITION]
164  await self._device_device.set_angle(knx_tilt_position)
165 
166  async def async_open_cover_tilt(self, **kwargs: Any) -> None:
167  """Open the cover tilt."""
168  if self._device_device.angle.writable:
169  await self._device_device.set_angle(0)
170  else:
171  await self._device_device.set_short_up()
172 
173  async def async_close_cover_tilt(self, **kwargs: Any) -> None:
174  """Close the cover tilt."""
175  if self._device_device.angle.writable:
176  await self._device_device.set_angle(100)
177  else:
178  await self._device_device.set_short_down()
179 
180  async def async_stop_cover_tilt(self, **kwargs: Any) -> None:
181  """Stop the cover tilt."""
182  await self._device_device.stop()
None async_set_cover_tilt_position(self, **Any kwargs)
Definition: cover.py:161
None async_open_cover(self, **Any kwargs)
Definition: cover.py:141
None __init__(self, KNXModule knx_module, ConfigType config)
Definition: cover.py:51
None async_close_cover_tilt(self, **Any kwargs)
Definition: cover.py:173
None async_stop_cover_tilt(self, **Any kwargs)
Definition: cover.py:180
None async_stop_cover(self, **Any kwargs)
Definition: cover.py:150
None async_open_cover_tilt(self, **Any kwargs)
Definition: cover.py:166
None async_close_cover(self, **Any kwargs)
Definition: cover.py:137
None async_set_cover_position(self, **Any kwargs)
Definition: cover.py:145
None async_setup_entry(HomeAssistant hass, config_entries.ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: cover.py:38