Home Assistant Unofficial Reference 2024.12.1
entity.py
Go to the documentation of this file.
1 """Support for Soma Smartshades."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable, Coroutine
6 import logging
7 from typing import Any
8 
9 from requests import RequestException
10 
11 from homeassistant.helpers.device_registry import DeviceInfo
12 from homeassistant.helpers.entity import Entity
13 
14 from .const import DOMAIN
15 from .utils import is_api_response_success
16 
17 _LOGGER = logging.getLogger(__name__)
18 
19 
20 def soma_api_call[_SomaEntityT: SomaEntity](
21  api_call: Callable[[_SomaEntityT], Coroutine[Any, Any, dict]],
22 ) -> Callable[[_SomaEntityT], Coroutine[Any, Any, dict]]:
23  """Soma api call decorator."""
24 
25  async def inner(self: _SomaEntityT) -> dict:
26  response = {}
27  try:
28  response_from_api = await api_call(self)
29  except RequestException:
30  if self.api_is_available:
31  _LOGGER.warning("Connection to SOMA Connect failed")
32  self.api_is_available = False
33  else:
34  if not self.api_is_available:
35  self.api_is_available = True
36  _LOGGER.info("Connection to SOMA Connect succeeded")
37 
38  if not is_api_response_success(response_from_api):
39  if self.is_available:
40  self.is_available = False
41  _LOGGER.warning(
42  (
43  "Device is unreachable (%s). Error while fetching the"
44  " state: %s"
45  ),
46  self.name,
47  response_from_api["msg"],
48  )
49  else:
50  if not self.is_available:
51  self.is_available = True
52  _LOGGER.info("Device %s is now reachable", self.name)
53  response = response_from_api
54  return response
55 
56  return inner
57 
58 
60  """Representation of a generic Soma device."""
61 
62  _attr_has_entity_name = True
63 
64  def __init__(self, device, api):
65  """Initialize the Soma device."""
66  self.devicedevice = device
67  self.apiapi = api
68  self.current_positioncurrent_position = 50
69  self.battery_statebattery_state = 0
70  self.is_availableis_available = True
71  self.api_is_availableapi_is_available = True
72 
73  @property
74  def available(self):
75  """Return true if the last API commands returned successfully."""
76  return self.is_availableis_available
77 
78  @property
79  def unique_id(self):
80  """Return the unique id base on the id returned by pysoma API."""
81  return self.devicedevice["mac"]
82 
83  @property
84  def device_info(self) -> DeviceInfo:
85  """Return device specific attributes.
86 
87  Implemented by platform classes.
88  """
89  return DeviceInfo(
90  identifiers={(DOMAIN, self.unique_idunique_idunique_id)},
91  manufacturer="Wazombi Labs",
92  name=self.devicedevice["name"],
93  )
94 
95  def set_position(self, position: int) -> None:
96  """Set the current device position."""
97  self.current_positioncurrent_position = position
98  self.schedule_update_ha_stateschedule_update_ha_state()
99 
100  @soma_api_call
101  async def get_shade_state_from_api(self) -> dict:
102  """Return the shade state from the api."""
103  return await self.hasshass.async_add_executor_job(
104  self.apiapi.get_shade_state, self.devicedevice["mac"]
105  )
106 
107  @soma_api_call
108  async def get_battery_level_from_api(self) -> dict:
109  """Return the battery level from the api."""
110  return await self.hasshass.async_add_executor_job(
111  self.apiapi.get_battery_level, self.devicedevice["mac"]
112  )
None set_position(self, int position)
Definition: entity.py:95
None schedule_update_ha_state(self, bool force_refresh=False)
Definition: entity.py:1244
bool is_api_response_success(dict api_response)
Definition: utils.py:4