Home Assistant Unofficial Reference 2024.12.1
cover.py
Go to the documentation of this file.
1 """Support for SwitchBot curtains."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any
7 
8 import switchbot
9 
11  ATTR_CURRENT_POSITION,
12  ATTR_CURRENT_TILT_POSITION,
13  ATTR_POSITION,
14  ATTR_TILT_POSITION,
15  CoverDeviceClass,
16  CoverEntity,
17  CoverEntityFeature,
18 )
19 from homeassistant.core import HomeAssistant, callback
20 from homeassistant.helpers.entity_platform import AddEntitiesCallback
21 from homeassistant.helpers.restore_state import RestoreEntity
22 
23 from .coordinator import SwitchbotConfigEntry, SwitchbotDataUpdateCoordinator
24 from .entity import SwitchbotEntity
25 
26 # Initialize the logger
27 _LOGGER = logging.getLogger(__name__)
28 PARALLEL_UPDATES = 0
29 
30 
32  hass: HomeAssistant,
33  entry: SwitchbotConfigEntry,
34  async_add_entities: AddEntitiesCallback,
35 ) -> None:
36  """Set up Switchbot curtain based on a config entry."""
37  coordinator = entry.runtime_data
38  if isinstance(coordinator.device, switchbot.SwitchbotBlindTilt):
40  else:
42 
43 
45  """Representation of a Switchbot."""
46 
47  _device: switchbot.SwitchbotCurtain
48  _attr_device_class = CoverDeviceClass.CURTAIN
49  _attr_supported_features = (
50  CoverEntityFeature.OPEN
51  | CoverEntityFeature.CLOSE
52  | CoverEntityFeature.STOP
53  | CoverEntityFeature.SET_POSITION
54  )
55  _attr_translation_key = "cover"
56  _attr_name = None
57 
58  def __init__(self, coordinator: SwitchbotDataUpdateCoordinator) -> None:
59  """Initialize the Switchbot."""
60  super().__init__(coordinator)
61  self._attr_is_closed_attr_is_closed = None
62 
63  async def async_added_to_hass(self) -> None:
64  """Run when entity about to be added."""
65  await super().async_added_to_hass()
66  last_state = await self.async_get_last_stateasync_get_last_state()
67  if not last_state or ATTR_CURRENT_POSITION not in last_state.attributes:
68  return
69 
70  self._attr_current_cover_position_attr_current_cover_position = last_state.attributes.get(
71  ATTR_CURRENT_POSITION
72  )
73  self._last_run_success_last_run_success = last_state.attributes.get("last_run_success")
74  if self._attr_current_cover_position_attr_current_cover_position is not None:
75  self._attr_is_closed_attr_is_closed = self._attr_current_cover_position_attr_current_cover_position <= 20
76 
77  async def async_open_cover(self, **kwargs: Any) -> None:
78  """Open the curtain."""
79 
80  _LOGGER.debug("Switchbot to open curtain %s", self._address_address)
81  self._last_run_success_last_run_success = bool(await self._device_device.open())
82  self._attr_is_opening_attr_is_opening = self._device_device.is_opening()
83  self._attr_is_closing_attr_is_closing = self._device_device.is_closing()
84  self.async_write_ha_stateasync_write_ha_state()
85 
86  async def async_close_cover(self, **kwargs: Any) -> None:
87  """Close the curtain."""
88 
89  _LOGGER.debug("Switchbot to close the curtain %s", self._address_address)
90  self._last_run_success_last_run_success = bool(await self._device_device.close())
91  self._attr_is_opening_attr_is_opening = self._device_device.is_opening()
92  self._attr_is_closing_attr_is_closing = self._device_device.is_closing()
93  self.async_write_ha_stateasync_write_ha_state()
94 
95  async def async_stop_cover(self, **kwargs: Any) -> None:
96  """Stop the moving of this device."""
97 
98  _LOGGER.debug("Switchbot to stop %s", self._address_address)
99  self._last_run_success_last_run_success = bool(await self._device_device.stop())
100  self._attr_is_opening_attr_is_opening = self._device_device.is_opening()
101  self._attr_is_closing_attr_is_closing = self._device_device.is_closing()
102  self.async_write_ha_stateasync_write_ha_state()
103 
104  async def async_set_cover_position(self, **kwargs: Any) -> None:
105  """Move the cover shutter to a specific position."""
106  position = kwargs.get(ATTR_POSITION)
107 
108  _LOGGER.debug("Switchbot to move at %d %s", position, self._address_address)
109  self._last_run_success_last_run_success = bool(await self._device_device.set_position(position))
110  self._attr_is_opening_attr_is_opening = self._device_device.is_opening()
111  self._attr_is_closing_attr_is_closing = self._device_device.is_closing()
112  self.async_write_ha_stateasync_write_ha_state()
113 
114  @callback
115  def _handle_coordinator_update(self) -> None:
116  """Handle updated data from the coordinator."""
117  self._attr_is_closing_attr_is_closing = self._device_device.is_closing()
118  self._attr_is_opening_attr_is_opening = self._device_device.is_opening()
119  self._attr_current_cover_position_attr_current_cover_position = self.parsed_dataparsed_data["position"]
120  self._attr_is_closed_attr_is_closed = self.parsed_dataparsed_data["position"] <= 20
121 
122  self.async_write_ha_stateasync_write_ha_state()
123 
124 
126  """Representation of a Switchbot."""
127 
128  _device: switchbot.SwitchbotBlindTilt
129  _attr_device_class = CoverDeviceClass.BLIND
130  _attr_supported_features = (
131  CoverEntityFeature.OPEN_TILT
132  | CoverEntityFeature.CLOSE_TILT
133  | CoverEntityFeature.STOP_TILT
134  | CoverEntityFeature.SET_TILT_POSITION
135  )
136  _attr_name = None
137  _attr_translation_key = "cover"
138  CLOSED_UP_THRESHOLD = 80
139  CLOSED_DOWN_THRESHOLD = 20
140 
141  def __init__(self, coordinator: SwitchbotDataUpdateCoordinator) -> None:
142  """Initialize the Switchbot."""
143  super().__init__(coordinator)
144  self._attr_is_closed_attr_is_closed = None
145 
146  async def async_added_to_hass(self) -> None:
147  """Run when entity about to be added."""
148  await super().async_added_to_hass()
149  last_state = await self.async_get_last_stateasync_get_last_state()
150  if not last_state or ATTR_CURRENT_TILT_POSITION not in last_state.attributes:
151  return
152 
153  self._attr_current_cover_tilt_position_attr_current_cover_tilt_position = last_state.attributes.get(
154  ATTR_CURRENT_TILT_POSITION
155  )
156  self._last_run_success_last_run_success = last_state.attributes.get("last_run_success")
157  if (_tilt := self._attr_current_cover_position) is not None:
158  self._attr_is_closed_attr_is_closed = (_tilt < self.CLOSED_DOWN_THRESHOLDCLOSED_DOWN_THRESHOLD) or (
159  _tilt > self.CLOSED_UP_THRESHOLDCLOSED_UP_THRESHOLD
160  )
161 
162  async def async_open_cover_tilt(self, **kwargs: Any) -> None:
163  """Open the tilt."""
164 
165  _LOGGER.debug("Switchbot to open blind tilt %s", self._address_address)
166  self._last_run_success_last_run_success = bool(await self._device_device.open())
167  self.async_write_ha_stateasync_write_ha_state()
168 
169  async def async_close_cover_tilt(self, **kwargs: Any) -> None:
170  """Close the tilt."""
171 
172  _LOGGER.debug("Switchbot to close the blind tilt %s", self._address_address)
173  self._last_run_success_last_run_success = bool(await self._device_device.close())
174  self.async_write_ha_stateasync_write_ha_state()
175 
176  async def async_stop_cover_tilt(self, **kwargs: Any) -> None:
177  """Stop the moving of this device."""
178 
179  _LOGGER.debug("Switchbot to stop %s", self._address_address)
180  self._last_run_success_last_run_success = bool(await self._device_device.stop())
181  self.async_write_ha_stateasync_write_ha_state()
182 
183  async def async_set_cover_tilt_position(self, **kwargs: Any) -> None:
184  """Move the cover tilt to a specific position."""
185  position = kwargs.get(ATTR_TILT_POSITION)
186 
187  _LOGGER.debug("Switchbot to move at %d %s", position, self._address_address)
188  self._last_run_success_last_run_success = bool(await self._device_device.set_position(position))
189  self.async_write_ha_stateasync_write_ha_state()
190 
191  @callback
192  def _handle_coordinator_update(self) -> None:
193  """Handle updated data from the coordinator."""
194  _tilt = self.parsed_dataparsed_data["tilt"]
195  self._attr_current_cover_tilt_position_attr_current_cover_tilt_position = _tilt
196  self._attr_is_closed_attr_is_closed = (_tilt < self.CLOSED_DOWN_THRESHOLDCLOSED_DOWN_THRESHOLD) or (
197  _tilt > self.CLOSED_UP_THRESHOLDCLOSED_UP_THRESHOLD
198  )
199  self._attr_is_opening_attr_is_opening = self.parsed_dataparsed_data["motionDirection"]["opening"]
200  self._attr_is_closing_attr_is_closing = self.parsed_dataparsed_data["motionDirection"]["closing"]
201  self.async_write_ha_stateasync_write_ha_state()
None __init__(self, SwitchbotDataUpdateCoordinator coordinator)
Definition: cover.py:141
None __init__(self, SwitchbotDataUpdateCoordinator coordinator)
Definition: cover.py:58
None open(self, **Any kwargs)
Definition: lock.py:86
None async_setup_entry(HomeAssistant hass, SwitchbotConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: cover.py:35