Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """Component for the Slide API."""
2 
3 from datetime import timedelta
4 import logging
5 
6 from goslideapi import GoSlideCloud, goslideapi
7 import voluptuous as vol
8 
9 from homeassistant.const import (
10  CONF_PASSWORD,
11  CONF_SCAN_INTERVAL,
12  CONF_USERNAME,
13  STATE_CLOSED,
14  STATE_CLOSING,
15  STATE_OPEN,
16  STATE_OPENING,
17 )
18 from homeassistant.core import HomeAssistant
19 from homeassistant.helpers import config_validation as cv
20 from homeassistant.helpers.discovery import async_load_platform
21 from homeassistant.helpers.event import async_call_later, async_track_time_interval
22 from homeassistant.helpers.typing import ConfigType
23 
24 from .const import (
25  API,
26  COMPONENT_PLATFORM,
27  CONF_INVERT_POSITION,
28  DEFAULT_OFFSET,
29  DEFAULT_RETRY,
30  DOMAIN,
31  SLIDES,
32 )
33 
34 _LOGGER = logging.getLogger(__name__)
35 
36 DEFAULT_SCAN_INTERVAL = timedelta(seconds=30)
37 
38 CONFIG_SCHEMA = vol.Schema(
39  {
40  DOMAIN: vol.Schema(
41  {
42  vol.Required(CONF_USERNAME): cv.string,
43  vol.Required(CONF_PASSWORD): cv.string,
44  vol.Optional(
45  CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL
46  ): cv.time_period,
47  vol.Optional(CONF_INVERT_POSITION, default=False): cv.boolean,
48  }
49  )
50  },
51  extra=vol.ALLOW_EXTRA,
52 )
53 
54 
55 async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
56  """Set up the Slide platform."""
57 
58  async def update_slides(now=None):
59  """Update slide information."""
60  result = await hass.data[DOMAIN][API].slides_overview()
61 
62  if result is None:
63  _LOGGER.error("Slide API does not work or returned an error")
64  return
65 
66  if result:
67  _LOGGER.debug("Slide API returned %d slide(s)", len(result))
68  else:
69  _LOGGER.warning("Slide API returned 0 slides")
70 
71  for slide in result:
72  if "device_id" not in slide:
73  _LOGGER.error(
74  "Found invalid Slide entry, device_id is missing. Entry=%s", slide
75  )
76  continue
77 
78  uid = slide["device_id"].replace("slide_", "")
79  slidenew = hass.data[DOMAIN][SLIDES].setdefault(uid, {})
80  slidenew["mac"] = uid
81  slidenew["id"] = slide["id"]
82  slidenew["name"] = slide["device_name"]
83  slidenew["state"] = None
84  oldpos = slidenew.get("pos")
85  slidenew["pos"] = None
86  slidenew["online"] = False
87  slidenew["invert"] = config[DOMAIN][CONF_INVERT_POSITION]
88 
89  if "device_info" not in slide:
90  _LOGGER.error(
91  "Slide %s (%s) has no device_info Entry=%s",
92  slide["id"],
93  slidenew["mac"],
94  slide,
95  )
96  continue
97 
98  # Check if we have pos (OK) or code (NOK)
99  if "pos" in slide["device_info"]:
100  slidenew["online"] = True
101  slidenew["pos"] = slide["device_info"]["pos"]
102  slidenew["pos"] = max(0, min(1, slidenew["pos"]))
103 
104  if oldpos is None or oldpos == slidenew["pos"]:
105  slidenew["state"] = (
106  STATE_CLOSED
107  if slidenew["pos"] > (1 - DEFAULT_OFFSET)
108  else STATE_OPEN
109  )
110  elif oldpos < slidenew["pos"]:
111  slidenew["state"] = (
112  STATE_CLOSED
113  if slidenew["pos"] >= (1 - DEFAULT_OFFSET)
114  else STATE_CLOSING
115  )
116  else:
117  slidenew["state"] = (
118  STATE_OPEN
119  if slidenew["pos"] <= DEFAULT_OFFSET
120  else STATE_OPENING
121  )
122  elif "code" in slide["device_info"]:
123  _LOGGER.warning(
124  "Slide %s (%s) is offline with code=%s",
125  slide["id"],
126  slidenew["mac"],
127  slide["device_info"]["code"],
128  )
129  else:
130  _LOGGER.error(
131  "Slide %s (%s) has invalid device_info %s",
132  slide["id"],
133  slidenew["mac"],
134  slide["device_info"],
135  )
136 
137  _LOGGER.debug("Updated entry=%s", slidenew)
138 
139  async def retry_setup(now):
140  """Retry setup if a connection/timeout happens on Slide API."""
141  await async_setup(hass, config)
142 
143  hass.data[DOMAIN] = {}
144  hass.data[DOMAIN][SLIDES] = {}
145 
146  username = config[DOMAIN][CONF_USERNAME]
147  password = config[DOMAIN][CONF_PASSWORD]
148  scaninterval = config[DOMAIN][CONF_SCAN_INTERVAL]
149 
150  hass.data[DOMAIN][API] = GoSlideCloud(username, password)
151 
152  try:
153  result = await hass.data[DOMAIN][API].login()
154  except (goslideapi.ClientConnectionError, goslideapi.ClientTimeoutError) as err:
155  _LOGGER.error(
156  "Error connecting to Slide Cloud: %s, going to retry in %s second(s)",
157  err,
158  DEFAULT_RETRY,
159  )
160  async_call_later(hass, DEFAULT_RETRY, retry_setup)
161  return True
162 
163  if not result:
164  _LOGGER.error("Slide API returned unknown error during authentication")
165  return False
166 
167  _LOGGER.debug("Slide API successfully authenticated")
168 
169  await update_slides()
170 
171  hass.async_create_task(
172  async_load_platform(hass, COMPONENT_PLATFORM, DOMAIN, {}, config)
173  )
174 
175  async_track_time_interval(hass, update_slides, scaninterval)
176 
177  return True
bool async_setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:55
None async_load_platform(core.HomeAssistant hass, Platform|str component, str platform, DiscoveryInfoType|None discovered, ConfigType hass_config)
Definition: discovery.py:152
CALLBACK_TYPE async_call_later(HomeAssistant hass, float|timedelta delay, HassJob[[datetime], Coroutine[Any, Any, None]|None]|Callable[[datetime], Coroutine[Any, Any, None]|None] action)
Definition: event.py:1597
CALLBACK_TYPE async_track_time_interval(HomeAssistant hass, Callable[[datetime], Coroutine[Any, Any, None]|None] action, timedelta interval, *str|None name=None, bool|None cancel_on_shutdown=None)
Definition: event.py:1679