Home Assistant Unofficial Reference 2024.12.1
cover.py
Go to the documentation of this file.
1 """Support for Rflink Cover devices."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any
7 
8 import voluptuous as vol
9 
11  PLATFORM_SCHEMA as COVER_PLATFORM_SCHEMA,
12  CoverEntity,
13  CoverState,
14 )
15 from homeassistant.const import CONF_DEVICES, CONF_NAME, CONF_TYPE
16 from homeassistant.core import HomeAssistant
18 from homeassistant.helpers.entity_platform import AddEntitiesCallback
19 from homeassistant.helpers.restore_state import RestoreEntity
20 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
21 
22 from .const import (
23  CONF_ALIASES,
24  CONF_DEVICE_DEFAULTS,
25  CONF_FIRE_EVENT,
26  CONF_GROUP,
27  CONF_GROUP_ALIASES,
28  CONF_NOGROUP_ALIASES,
29  CONF_SIGNAL_REPETITIONS,
30  DEVICE_DEFAULTS_SCHEMA,
31 )
32 from .entity import RflinkCommand
33 
34 _LOGGER = logging.getLogger(__name__)
35 
36 PARALLEL_UPDATES = 0
37 
38 TYPE_STANDARD = "standard"
39 TYPE_INVERTED = "inverted"
40 
41 PLATFORM_SCHEMA = COVER_PLATFORM_SCHEMA.extend(
42  {
43  vol.Optional(
44  CONF_DEVICE_DEFAULTS, default=DEVICE_DEFAULTS_SCHEMA({})
45  ): DEVICE_DEFAULTS_SCHEMA,
46  vol.Optional(CONF_DEVICES, default={}): vol.Schema(
47  {
48  cv.string: {
49  vol.Optional(CONF_NAME): cv.string,
50  vol.Optional(CONF_TYPE): vol.Any(TYPE_STANDARD, TYPE_INVERTED),
51  vol.Optional(CONF_ALIASES, default=[]): vol.All(
52  cv.ensure_list, [cv.string]
53  ),
54  vol.Optional(CONF_GROUP_ALIASES, default=[]): vol.All(
55  cv.ensure_list, [cv.string]
56  ),
57  vol.Optional(CONF_NOGROUP_ALIASES, default=[]): vol.All(
58  cv.ensure_list, [cv.string]
59  ),
60  vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean,
61  vol.Optional(CONF_SIGNAL_REPETITIONS): vol.Coerce(int),
62  vol.Optional(CONF_GROUP, default=True): cv.boolean,
63  }
64  }
65  ),
66  }
67 )
68 
69 
71  """Return entity class for protocol of a given device_id.
72 
73  Async friendly.
74  """
75  entity_type_mapping = {
76  # KlikAanKlikUit cover have the controls inverted
77  "newkaku": TYPE_INVERTED
78  }
79  protocol = device_id.split("_")[0]
80  return entity_type_mapping.get(protocol, TYPE_STANDARD)
81 
82 
83 def entity_class_for_type(entity_type):
84  """Translate entity type to entity class.
85 
86  Async friendly.
87  """
88  entity_device_mapping = {
89  # default cover implementation
90  TYPE_STANDARD: RflinkCover,
91  # cover with open/close commands inverted
92  # like KAKU/COCO ASUN-650
93  TYPE_INVERTED: InvertedRflinkCover,
94  }
95 
96  return entity_device_mapping.get(entity_type, RflinkCover)
97 
98 
99 def devices_from_config(domain_config):
100  """Parse configuration and add Rflink cover devices."""
101  devices = []
102  for device_id, config in domain_config[CONF_DEVICES].items():
103  # Determine what kind of entity to create, RflinkCover
104  # or InvertedRflinkCover
105  if CONF_TYPE in config:
106  # Remove type from config to not pass it as and argument
107  # to entity instantiation
108  entity_type = config.pop(CONF_TYPE)
109  else:
110  entity_type = entity_type_for_device_id(device_id)
111 
112  entity_class = entity_class_for_type(entity_type)
113  device_config = dict(domain_config[CONF_DEVICE_DEFAULTS], **config)
114  device = entity_class(device_id, **device_config)
115  devices.append(device)
116 
117  return devices
118 
119 
121  hass: HomeAssistant,
122  config: ConfigType,
123  async_add_entities: AddEntitiesCallback,
124  discovery_info: DiscoveryInfoType | None = None,
125 ) -> None:
126  """Set up the Rflink cover platform."""
128 
129 
131  """Rflink entity which can switch on/stop/off (eg: cover)."""
132 
133  async def async_added_to_hass(self) -> None:
134  """Restore RFLink cover state (OPEN/CLOSE)."""
135  await super().async_added_to_hass()
136  if (old_state := await self.async_get_last_stateasync_get_last_state()) is not None:
137  self._state_state_state = old_state.state == CoverState.OPEN
138 
139  def _handle_event(self, event):
140  """Adjust state if Rflink picks up a remote command for this device."""
141  self.cancel_queued_send_commandscancel_queued_send_commands()
142 
143  command = event["command"]
144  if command in ["on", "allon", "up"]:
145  self._state_state_state = True
146  elif command in ["off", "alloff", "down"]:
147  self._state_state_state = False
148 
149  @property
150  def is_closed(self) -> bool | None:
151  """Return if the cover is closed."""
152  return not self._state_state_state
153 
154  @property
155  def assumed_state(self) -> bool:
156  """Return True because covers can be stopped midway."""
157  return True
158 
159  async def async_close_cover(self, **kwargs: Any) -> None:
160  """Turn the device close."""
161  await self._async_handle_command_async_handle_command("close_cover")
162 
163  async def async_open_cover(self, **kwargs: Any) -> None:
164  """Turn the device open."""
165  await self._async_handle_command_async_handle_command("open_cover")
166 
167  async def async_stop_cover(self, **kwargs: Any) -> None:
168  """Turn the device stop."""
169  await self._async_handle_command_async_handle_command("stop_cover")
170 
171 
173  """Rflink cover that has inverted open/close commands."""
174 
175  async def _async_send_command(self, cmd, repetitions):
176  """Will invert only the UP/DOWN commands."""
177  _LOGGER.debug("Getting command: %s for Rflink device: %s", cmd, self._device_id_device_id)
178  cmd_inv = {"UP": "DOWN", "DOWN": "UP"}
179  await super()._async_send_command(cmd_inv.get(cmd, cmd), repetitions)
None async_open_cover(self, **Any kwargs)
Definition: __init__.py:394
None async_close_cover(self, **Any kwargs)
Definition: __init__.py:402
None async_stop_cover(self, **Any kwargs)
Definition: __init__.py:438