Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """Support for Supla devices."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from datetime import timedelta
7 import logging
8 
9 from asyncpysupla import SuplaAPI
10 import voluptuous as vol
11 
12 from homeassistant.const import CONF_ACCESS_TOKEN, Platform
13 from homeassistant.core import HomeAssistant
14 from homeassistant.helpers.aiohttp_client import async_get_clientsession
16 from homeassistant.helpers.discovery import async_load_platform
17 from homeassistant.helpers.typing import ConfigType
18 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
19 
20 _LOGGER = logging.getLogger(__name__)
21 
22 DOMAIN = "supla"
23 CONF_SERVER = "server"
24 CONF_SERVERS = "servers"
25 
26 SCAN_INTERVAL = timedelta(seconds=10)
27 
28 SUPLA_FUNCTION_HA_CMP_MAP = {
29  "CONTROLLINGTHEROLLERSHUTTER": Platform.COVER,
30  "CONTROLLINGTHEGATE": Platform.COVER,
31  "CONTROLLINGTHEGARAGEDOOR": Platform.COVER,
32  "LIGHTSWITCH": Platform.SWITCH,
33 }
34 SUPLA_FUNCTION_NONE = "NONE"
35 SUPLA_SERVERS = "supla_servers"
36 SUPLA_COORDINATORS = "supla_coordinators"
37 
38 SERVER_CONFIG = vol.Schema(
39  {
40  vol.Required(CONF_SERVER): cv.string,
41  vol.Required(CONF_ACCESS_TOKEN): cv.string,
42  }
43 )
44 
45 CONFIG_SCHEMA = vol.Schema(
46  {
47  DOMAIN: vol.Schema(
48  {vol.Required(CONF_SERVERS): vol.All(cv.ensure_list, [SERVER_CONFIG])}
49  )
50  },
51  extra=vol.ALLOW_EXTRA,
52 )
53 
54 
55 async def async_setup(hass: HomeAssistant, base_config: ConfigType) -> bool:
56  """Set up the Supla component."""
57 
58  server_confs = base_config[DOMAIN][CONF_SERVERS]
59 
60  hass.data[DOMAIN] = {SUPLA_SERVERS: {}, SUPLA_COORDINATORS: {}}
61 
62  session = async_get_clientsession(hass)
63 
64  for server_conf in server_confs:
65  server_address = server_conf[CONF_SERVER]
66 
67  server = SuplaAPI(server_address, server_conf[CONF_ACCESS_TOKEN], session)
68 
69  # Test connection
70  try:
71  srv_info = await server.get_server_info()
72  if srv_info.get("authenticated"):
73  hass.data[DOMAIN][SUPLA_SERVERS][server_conf[CONF_SERVER]] = server
74 
75  else:
76  _LOGGER.error(
77  "Server: %s not configured. API call returned: %s",
78  server_address,
79  srv_info,
80  )
81  return False
82  except OSError:
83  _LOGGER.exception(
84  "Server: %s not configured. Error on Supla API access: ", server_address
85  )
86  return False
87 
88  await discover_devices(hass, base_config)
89 
90  return True
91 
92 
93 async def discover_devices(hass, hass_config):
94  """Run periodically to discover new devices.
95 
96  Currently it is only run at startup.
97  """
98  component_configs: dict[Platform, dict[str, dict]] = {}
99 
100  for server_name, server in hass.data[DOMAIN][SUPLA_SERVERS].items():
101 
102  async def _fetch_channels():
103  async with asyncio.timeout(SCAN_INTERVAL.total_seconds()):
104  return {
105  channel["id"]: channel
106  for channel in await server.get_channels( # noqa: B023
107  include=["iodevice", "state", "connected"]
108  )
109  }
110 
111  coordinator = DataUpdateCoordinator(
112  hass,
113  _LOGGER,
114  name=f"{DOMAIN}-{server_name}",
115  update_method=_fetch_channels,
116  update_interval=SCAN_INTERVAL,
117  )
118 
119  await coordinator.async_refresh()
120 
121  hass.data[DOMAIN][SUPLA_COORDINATORS][server_name] = coordinator
122 
123  for channel_id, channel in coordinator.data.items():
124  channel_function = channel["function"]["name"]
125 
126  if channel_function == SUPLA_FUNCTION_NONE:
127  _LOGGER.debug(
128  "Ignored function: %s, channel ID: %s",
129  channel_function,
130  channel["id"],
131  )
132  continue
133 
134  component_name = SUPLA_FUNCTION_HA_CMP_MAP.get(channel_function)
135 
136  if component_name is None:
137  _LOGGER.warning(
138  "Unsupported function: %s, channel ID: %s",
139  channel_function,
140  channel["id"],
141  )
142  continue
143 
144  channel["server_name"] = server_name
145  component_config = component_configs.setdefault(component_name, {})
146  component_config[f"{server_name}_{channel_id}"] = {
147  "channel_id": channel_id,
148  "server_name": server_name,
149  "function_name": channel["function"]["name"],
150  }
151 
152  # Load discovered devices
153  for component_name, config in component_configs.items():
154  await async_load_platform(hass, component_name, DOMAIN, config, hass_config)
bool async_setup(HomeAssistant hass, ConfigType base_config)
Definition: __init__.py:55
def discover_devices(hass, hass_config)
Definition: __init__.py:93
aiohttp.ClientSession async_get_clientsession(HomeAssistant hass, bool verify_ssl=True, socket.AddressFamily family=socket.AF_UNSPEC, ssl_util.SSLCipherList ssl_cipher=ssl_util.SSLCipherList.PYTHON_DEFAULT)
None async_load_platform(core.HomeAssistant hass, Platform|str component, str platform, DiscoveryInfoType|None discovered, ConfigType hass_config)
Definition: discovery.py:152