Home Assistant Unofficial Reference 2024.12.1
gateway.py
Go to the documentation of this file.
1 """Code to handle a Xiaomi Gateway."""
2 
3 import logging
4 
5 from construct.core import ChecksumError
6 from micloud import MiCloud
7 from micloud.micloudexception import MiCloudAccessDenied
8 from miio import DeviceException, gateway
9 from miio.gateway.gateway import GATEWAY_MODEL_EU
10 
11 from .const import (
12  CONF_CLOUD_COUNTRY,
13  CONF_CLOUD_PASSWORD,
14  CONF_CLOUD_SUBDEVICES,
15  CONF_CLOUD_USERNAME,
16  AuthException,
17  SetupException,
18 )
19 
20 _LOGGER = logging.getLogger(__name__)
21 
22 
24  """Class to async connect to a Xiaomi Gateway."""
25 
26  def __init__(self, hass, config_entry):
27  """Initialize the entity."""
28  self._hass_hass = hass
29  self._config_entry_config_entry = config_entry
30  self._gateway_device_gateway_device = None
31  self._gateway_info_gateway_info = None
32  self._use_cloud_use_cloud = None
33  self._cloud_username_cloud_username = None
34  self._cloud_password_cloud_password = None
35  self._cloud_country_cloud_country = None
36  self._host_host = None
37  self._token_token = None
38 
39  @property
40  def gateway_device(self):
41  """Return the class containing all connections to the gateway."""
42  return self._gateway_device_gateway_device
43 
44  @property
45  def gateway_info(self):
46  """Return the class containing gateway info."""
47  return self._gateway_info_gateway_info
48 
49  async def async_connect_gateway(self, host, token):
50  """Connect to the Xiaomi Gateway."""
51  _LOGGER.debug("Initializing with host %s (token %s...)", host, token[:5])
52 
53  self._host_host = host
54  self._token_token = token
55  self._use_cloud_use_cloud = self._config_entry_config_entry.options.get(CONF_CLOUD_SUBDEVICES, False)
56  self._cloud_username_cloud_username = self._config_entry_config_entry.data.get(CONF_CLOUD_USERNAME)
57  self._cloud_password_cloud_password = self._config_entry_config_entry.data.get(CONF_CLOUD_PASSWORD)
58  self._cloud_country_cloud_country = self._config_entry_config_entry.data.get(CONF_CLOUD_COUNTRY)
59 
60  await self._hass_hass.async_add_executor_job(self.connect_gatewayconnect_gateway)
61 
62  _LOGGER.debug(
63  "%s %s %s detected",
64  self._gateway_info_gateway_info.model,
65  self._gateway_info_gateway_info.firmware_version,
66  self._gateway_info_gateway_info.hardware_version,
67  )
68 
69  def connect_gateway(self):
70  """Connect the gateway in a way that can called by async_add_executor_job."""
71  try:
72  self._gateway_device_gateway_device = gateway.Gateway(self._host_host, self._token_token)
73  # get the gateway info
74  self._gateway_info_gateway_info = self._gateway_device_gateway_device.info()
75  except DeviceException as error:
76  if isinstance(error.__cause__, ChecksumError):
77  raise AuthException(error) from error
78 
79  raise SetupException(
80  f"DeviceException during setup of xiaomi gateway with host {self._host}"
81  ) from error
82 
83  # get the connected sub devices
84  use_cloud = self._use_cloud_use_cloud or self._gateway_info_gateway_info.model == GATEWAY_MODEL_EU
85  if not use_cloud:
86  # use local query (not supported by all gateway types)
87  try:
88  self._gateway_device_gateway_device.discover_devices()
89  except DeviceException as error:
90  _LOGGER.error(
91  (
92  "DeviceException during getting subdevices of xiaomi gateway"
93  " with host %s, trying cloud to obtain subdevices: %s"
94  ),
95  self._host_host,
96  error,
97  )
98  use_cloud = True
99 
100  if use_cloud:
101  # use miio-cloud
102  if (
103  self._cloud_username_cloud_username is None
104  or self._cloud_password_cloud_password is None
105  or self._cloud_country_cloud_country is None
106  ):
107  raise AuthException(
108  "Missing cloud credentials in Xiaomi Miio configuration"
109  )
110 
111  try:
112  miio_cloud = MiCloud(self._cloud_username_cloud_username, self._cloud_password_cloud_password)
113  if not miio_cloud.login():
114  raise SetupException(
115  (
116  "Failed to login to Xiaomi Miio Cloud during setup of"
117  f" Xiaomi gateway with host {self._host}"
118  ),
119  )
120  devices_raw = miio_cloud.get_devices(self._cloud_country_cloud_country)
121  self._gateway_device_gateway_device.get_devices_from_dict(devices_raw)
122  except MiCloudAccessDenied as error:
123  raise AuthException(
124  "Could not login to Xiaomi Miio Cloud, check the credentials"
125  ) from error
126  except DeviceException as error:
127  raise SetupException(
128  "DeviceException during setup of xiaomi gateway with host"
129  f" {self._host}"
130  ) from error
list[tuple[str, str]] discover_devices(int device_id)