Home Assistant Unofficial Reference 2024.12.1
cover.py
Go to the documentation of this file.
1 """Support for SwitchBee cover."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 from switchbee.api.central_unit import SwitchBeeError, SwitchBeeTokenError
8 from switchbee.const import SomfyCommand
9 from switchbee.device import SwitchBeeShutter, SwitchBeeSomfy
10 
12  ATTR_POSITION,
13  CoverDeviceClass,
14  CoverEntity,
15  CoverEntityFeature,
16 )
17 from homeassistant.config_entries import ConfigEntry
18 from homeassistant.core import HomeAssistant, callback
19 from homeassistant.exceptions import HomeAssistantError
20 from homeassistant.helpers.entity_platform import AddEntitiesCallback
21 
22 from .const import DOMAIN
23 from .coordinator import SwitchBeeCoordinator
24 from .entity import SwitchBeeDeviceEntity
25 
26 
28  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
29 ) -> None:
30  """Set up SwitchBee switch."""
31  coordinator: SwitchBeeCoordinator = hass.data[DOMAIN][entry.entry_id]
32  entities: list[CoverEntity] = []
33 
34  for device in coordinator.data.values():
35  if isinstance(device, SwitchBeeShutter):
36  entities.append(SwitchBeeCoverEntity(device, coordinator))
37  elif isinstance(device, SwitchBeeSomfy):
38  entities.append(SwitchBeeSomfyEntity(device, coordinator))
39 
40  async_add_entities(entities)
41 
42 
43 class SwitchBeeSomfyEntity(SwitchBeeDeviceEntity[SwitchBeeSomfy], CoverEntity):
44  """Representation of a SwitchBee Somfy cover."""
45 
46  _attr_device_class = CoverDeviceClass.SHUTTER
47  _attr_supported_features = (
48  CoverEntityFeature.CLOSE | CoverEntityFeature.OPEN | CoverEntityFeature.STOP
49  )
50  _attr_is_closed = None
51 
52  async def _fire_somfy_command(self, command: str) -> None:
53  """Async function to fire Somfy device command."""
54  try:
55  await self.coordinator.api.set_state(self._device.id, command)
56  except (SwitchBeeError, SwitchBeeTokenError) as exp:
57  raise HomeAssistantError(
58  f"Failed to fire {command} for {self.name}, {exp!s}"
59  ) from exp
60 
61  async def async_open_cover(self, **kwargs: Any) -> None:
62  """Open the cover."""
63  return await self._fire_somfy_command_fire_somfy_command(SomfyCommand.UP)
64 
65  async def async_close_cover(self, **kwargs: Any) -> None:
66  """Close the cover."""
67  return await self._fire_somfy_command_fire_somfy_command(SomfyCommand.DOWN)
68 
69  async def async_stop_cover(self, **kwargs: Any) -> None:
70  """Stop a moving cover."""
71  return await self._fire_somfy_command_fire_somfy_command(SomfyCommand.MY)
72 
73 
74 class SwitchBeeCoverEntity(SwitchBeeDeviceEntity[SwitchBeeShutter], CoverEntity):
75  """Representation of a SwitchBee cover."""
76 
77  _attr_device_class = CoverDeviceClass.SHUTTER
78  _attr_supported_features = (
79  CoverEntityFeature.CLOSE
80  | CoverEntityFeature.OPEN
81  | CoverEntityFeature.SET_POSITION
82  | CoverEntityFeature.STOP
83  )
84  _attr_is_closed: bool | None = None
85 
86  @callback
87  def _handle_coordinator_update(self) -> None:
88  """Handle updated data from the coordinator."""
89  self._update_from_coordinator_update_from_coordinator()
91 
92  def _update_from_coordinator(self) -> None:
93  """Update the entity attributes from the coordinator data."""
94 
95  coordinator_device = self._get_coordinator_device()
96 
97  if coordinator_device.position == -1:
98  self._check_if_became_offline()
99  return
100 
101  # check if the device was offline (now online) and bring it back
102  self._check_if_became_online()
103 
104  self._attr_current_cover_position_attr_current_cover_position = coordinator_device.position
105 
107  self._attr_is_closed_attr_is_closed = True
108  else:
109  self._attr_is_closed_attr_is_closed = False
111 
112  async def async_open_cover(self, **kwargs: Any) -> None:
113  """Open the cover."""
114  if self.current_cover_positioncurrent_cover_positioncurrent_cover_positioncurrent_cover_position == 100:
115  return
116 
117  await self.async_set_cover_positionasync_set_cover_positionasync_set_cover_position(position=100)
118 
119  async def async_close_cover(self, **kwargs: Any) -> None:
120  """Close the cover."""
122  return
123 
124  await self.async_set_cover_positionasync_set_cover_positionasync_set_cover_position(position=0)
125 
126  async def async_stop_cover(self, **kwargs: Any) -> None:
127  """Stop a moving cover."""
128  # to stop the shutter, we just interrupt it with any state during operation
129  await self.async_set_cover_positionasync_set_cover_positionasync_set_cover_position(
130  position=self.current_cover_positioncurrent_cover_positioncurrent_cover_positioncurrent_cover_position, force=True
131  )
132 
133  # fetch data from the Central Unit to get the new position
134  await self.coordinator.async_request_refresh()
135 
136  async def async_set_cover_position(self, **kwargs: Any) -> None:
137  """Async function to set position to cover."""
138  if (
139  self.current_cover_positioncurrent_cover_positioncurrent_cover_positioncurrent_cover_position == kwargs[ATTR_POSITION]
140  and "force" not in kwargs
141  ):
142  return
143  try:
144  await self.coordinator.api.set_state(self._device.id, kwargs[ATTR_POSITION])
145  except (SwitchBeeError, SwitchBeeTokenError) as exp:
146  raise HomeAssistantError(
147  f"Failed to set {self.name} position to {kwargs[ATTR_POSITION]}, error:"
148  f" {exp!s}"
149  ) from exp
150 
151  self._get_coordinator_device().position = kwargs[ATTR_POSITION]
152  self.coordinator.async_set_updated_data(self.coordinator.data)
153  self.async_write_ha_stateasync_write_ha_state()
None async_set_cover_position(self, **Any kwargs)
Definition: __init__.py:429
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: cover.py:29