1 """Support for Xiaomi Mi routers."""
3 from __future__
import annotations
5 from http
import HTTPStatus
9 import voluptuous
as vol
12 DOMAIN
as DEVICE_TRACKER_DOMAIN,
13 PLATFORM_SCHEMA
as DEVICE_TRACKER_PLATFORM_SCHEMA,
21 _LOGGER = logging.getLogger(__name__)
23 PLATFORM_SCHEMA = DEVICE_TRACKER_PLATFORM_SCHEMA.extend(
25 vol.Required(CONF_HOST): cv.string,
26 vol.Required(CONF_USERNAME, default=
"admin"): cv.string,
27 vol.Required(CONF_PASSWORD): cv.string,
32 def get_scanner(hass: HomeAssistant, config: ConfigType) -> XiaomiDeviceScanner |
None:
33 """Validate the configuration and return a Xiaomi Device Scanner."""
36 return scanner
if scanner.success_init
else None
40 """Class which queries a Xiaomi Mi router.
42 Adapted from Luci scanner.
46 """Initialize the scanner."""
47 self.
hosthost = config[CONF_HOST]
58 """Scan for new devices and return a list with found device IDs."""
63 """Return the name of the given device or None if we don't know."""
67 hosts = [x
for x
in result
if "mac" in x
and "name" in x]
68 mac2name_list = [(x[
"mac"].upper(), x[
"name"])
for x
in hosts]
73 return self.
mac2namemac2name.
get(device.upper(),
None)
76 """Ensure the information from the router are up to date.
78 Returns true if scanning successful.
90 """Retrieve the device list with a retry if token is invalid.
92 Return the list if successful.
94 _LOGGER.debug(
"Refreshing device list")
99 _LOGGER.debug(
"Refreshing token and retrying device list refresh")
104 """Extract and store the device list in self.last_results."""
106 for device_entry
in result:
108 if int(device_entry[
"online"]) == 1:
109 self.
last_resultslast_results.append(device_entry[
"mac"])
113 """Get device list for the given host."""
114 url =
"http://{}/cgi-bin/luci/;stok={}/api/misystem/devicelist"
115 url = url.format(host, token)
117 res = requests.get(url, timeout=10, **kwargs)
118 except requests.exceptions.Timeout:
119 _LOGGER.exception(
"Connection to the router timed out at URL %s", url)
121 if res.status_code != HTTPStatus.OK:
122 _LOGGER.exception(
"Connection failed with http code %s", res.status_code)
128 _LOGGER.exception(
"Failed to parse response from mi router")
131 xiaomi_code = result[
"code"]
133 _LOGGER.exception(
"No field code in response from mi router. %s", result)
137 return result[
"list"]
139 _LOGGER.exception(
"No list in response from mi router. %s", result)
143 "Receive wrong Xiaomi code %s, expected 0 in response %s",
151 """Get authentication token for the given host+username+password."""
152 url = f
"http://{host}/cgi-bin/luci/api/xqsystem/login"
153 data = {
"username": username,
"password": password}
155 res = requests.post(url, data=data, timeout=5)
156 except requests.exceptions.Timeout:
157 _LOGGER.exception(
"Connection to the router timed out")
159 if res.status_code == HTTPStatus.OK:
164 _LOGGER.exception(
"Failed to parse response from mi router")
167 return result[
"token"]
170 "Xiaomi token cannot be refreshed, response from "
171 "url: [%s] \nwith parameter: [%s] \nwas: [%s]"
173 _LOGGER.exception(error_message, url, data, result)
176 _LOGGER.error(
"Invalid response: [%s] at url: [%s] with data [%s]", res, url, data)
def _retrieve_list_with_retry(self)
def _store_result(self, result)
def __init__(self, config)
def get_device_name(self, device)
web.Response get(self, web.Request request, str config_key)
def _retrieve_list(host, token, **kwargs)
def _get_token(host, username, password)
XiaomiDeviceScanner|None get_scanner(HomeAssistant hass, ConfigType config)