mirror of
https://github.com/XiaoMi/ha_xiaomi_home.git
synced 2025-06-21 15:20:00 +08:00
feat: improve devices filter & optimize the network detection logic (#458)
* fix: fix miot http type error * style: change some miot cloud log level * feat: improve devices filter * feat: update save devices logic * refator: refactor miot network * feat: update miot_client.get_miot_instance_async * feat: option flow support network detect config * doc: update translations * feat: update config flow network detect logic * style: change miot client refresh prop log level * feat: config flow support network check * doc: update translations * refactor: rename func name * fix: ignore invalid type error * feat: option flow add check network deps * --amend * --amend * feat: check mqtt broker * feat: config flow support check network deps * feat: update manifest requirements, paho-mqtt<2.0.0 * fix: fix mqtt broker check logic * style: remove unuse params * feat: show integration instance id * feat: update data_schema from required to optional * fix: translation text error
This commit is contained in:
@ -1558,7 +1558,7 @@ class MIoTClient:
|
||||
None)
|
||||
self.__on_prop_msg(params=result, ctx=None)
|
||||
if request_list:
|
||||
_LOGGER.error(
|
||||
_LOGGER.info(
|
||||
'refresh props failed, cloud, %s',
|
||||
list(request_list.keys()))
|
||||
request_list = None
|
||||
@ -1614,7 +1614,7 @@ class MIoTClient:
|
||||
succeed_once = True
|
||||
if succeed_once:
|
||||
return True
|
||||
_LOGGER.error(
|
||||
_LOGGER.info(
|
||||
'refresh props failed, gw, %s', list(request_list.keys()))
|
||||
# Add failed request back to the list
|
||||
self._refresh_props_list.update(request_list)
|
||||
@ -1657,7 +1657,7 @@ class MIoTClient:
|
||||
succeed_once = True
|
||||
if succeed_once:
|
||||
return True
|
||||
_LOGGER.error(
|
||||
_LOGGER.info(
|
||||
'refresh props failed, lan, %s', list(request_list.keys()))
|
||||
# Add failed request back to the list
|
||||
self._refresh_props_list.update(request_list)
|
||||
@ -1689,10 +1689,10 @@ class MIoTClient:
|
||||
if self._refresh_props_timer:
|
||||
self._refresh_props_timer.cancel()
|
||||
self._refresh_props_timer = None
|
||||
_LOGGER.error('refresh props failed, retry count exceed')
|
||||
_LOGGER.info('refresh props failed, retry count exceed')
|
||||
return
|
||||
self._refresh_props_retry_count += 1
|
||||
_LOGGER.error(
|
||||
_LOGGER.info(
|
||||
'refresh props failed, retry, %s', self._refresh_props_retry_count)
|
||||
self._refresh_props_timer = self._main_loop.call_later(
|
||||
3, lambda: self._main_loop.create_task(
|
||||
@ -1851,15 +1851,6 @@ async def get_miot_instance_async(
|
||||
loop: asyncio.AbstractEventLoop = asyncio.get_running_loop()
|
||||
if loop is None:
|
||||
raise MIoTClientError('loop is None')
|
||||
# MIoT network
|
||||
network: Optional[MIoTNetwork] = hass.data[DOMAIN].get(
|
||||
'miot_network', None)
|
||||
if not network:
|
||||
network = MIoTNetwork(loop=loop)
|
||||
hass.data[DOMAIN]['miot_network'] = network
|
||||
await network.init_async(
|
||||
refresh_interval=NETWORK_REFRESH_INTERVAL)
|
||||
_LOGGER.info('create miot_network instance')
|
||||
# MIoT storage
|
||||
storage: Optional[MIoTStorage] = hass.data[DOMAIN].get(
|
||||
'miot_storage', None)
|
||||
@ -1868,12 +1859,29 @@ async def get_miot_instance_async(
|
||||
root_path=entry_data['storage_path'], loop=loop)
|
||||
hass.data[DOMAIN]['miot_storage'] = storage
|
||||
_LOGGER.info('create miot_storage instance')
|
||||
global_config: dict = await storage.load_user_config_async(
|
||||
uid='global_config', cloud_server='all',
|
||||
keys=['network_detect_addr', 'net_interfaces', 'enable_subscribe'])
|
||||
# MIoT network
|
||||
network_detect_addr: dict = global_config.get(
|
||||
'network_detect_addr', {})
|
||||
network: Optional[MIoTNetwork] = hass.data[DOMAIN].get(
|
||||
'miot_network', None)
|
||||
if not network:
|
||||
network = MIoTNetwork(
|
||||
ip_addr_list=network_detect_addr.get('ip', []),
|
||||
url_addr_list=network_detect_addr.get('url', []),
|
||||
refresh_interval=NETWORK_REFRESH_INTERVAL,
|
||||
loop=loop)
|
||||
hass.data[DOMAIN]['miot_network'] = network
|
||||
await network.init_async()
|
||||
_LOGGER.info('create miot_network instance')
|
||||
# MIoT service
|
||||
mips_service: Optional[MipsService] = hass.data[DOMAIN].get(
|
||||
'mips_service', None)
|
||||
if not mips_service:
|
||||
aiozc = await zeroconf.async_get_async_instance(hass)
|
||||
mips_service: MipsService = MipsService(aiozc=aiozc, loop=loop)
|
||||
mips_service = MipsService(aiozc=aiozc, loop=loop)
|
||||
hass.data[DOMAIN]['mips_service'] = mips_service
|
||||
await mips_service.init_async()
|
||||
_LOGGER.info('create mips_service instance')
|
||||
@ -1881,15 +1889,11 @@ async def get_miot_instance_async(
|
||||
miot_lan: Optional[MIoTLan] = hass.data[DOMAIN].get(
|
||||
'miot_lan', None)
|
||||
if not miot_lan:
|
||||
lan_config = (await storage.load_user_config_async(
|
||||
uid='global_config',
|
||||
cloud_server='all',
|
||||
keys=['net_interfaces', 'enable_subscribe'])) or {}
|
||||
miot_lan = MIoTLan(
|
||||
net_ifs=lan_config.get('net_interfaces', []),
|
||||
net_ifs=global_config.get('net_interfaces', []),
|
||||
network=network,
|
||||
mips_service=mips_service,
|
||||
enable_subscribe=lan_config.get('enable_subscribe', False),
|
||||
enable_subscribe=global_config.get('enable_subscribe', False),
|
||||
loop=loop)
|
||||
hass.data[DOMAIN]['miot_lan'] = miot_lan
|
||||
_LOGGER.info('create miot_lan instance')
|
||||
|
@ -224,20 +224,20 @@ class MIoTHttpClient:
|
||||
_client_id: str
|
||||
_access_token: str
|
||||
|
||||
_get_prop_timer: asyncio.TimerHandle
|
||||
_get_prop_list: dict[str, dict[str, asyncio.Future | str | bool]]
|
||||
_get_prop_timer: Optional[asyncio.TimerHandle]
|
||||
_get_prop_list: dict[str, dict]
|
||||
|
||||
def __init__(
|
||||
self, cloud_server: str, client_id: str, access_token: str,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
) -> None:
|
||||
self._main_loop = loop or asyncio.get_running_loop()
|
||||
self._host = None
|
||||
self._base_url = None
|
||||
self._client_id = None
|
||||
self._access_token = None
|
||||
self._host = DEFAULT_OAUTH2_API_HOST
|
||||
self._base_url = ''
|
||||
self._client_id = ''
|
||||
self._access_token = ''
|
||||
|
||||
self._get_prop_timer: asyncio.TimerHandle = None
|
||||
self._get_prop_timer = None
|
||||
self._get_prop_list = {}
|
||||
|
||||
if (
|
||||
@ -258,8 +258,9 @@ class MIoTHttpClient:
|
||||
self._get_prop_timer.cancel()
|
||||
self._get_prop_timer = None
|
||||
for item in self._get_prop_list.values():
|
||||
fut: asyncio.Future = item.get('fut')
|
||||
fut.cancel()
|
||||
fut: Optional[asyncio.Future] = item.get('fut', None)
|
||||
if fut:
|
||||
fut.cancel()
|
||||
self._get_prop_list.clear()
|
||||
if self._session and not self._session.closed:
|
||||
await self._session.close()
|
||||
@ -270,9 +271,7 @@ class MIoTHttpClient:
|
||||
access_token: Optional[str] = None
|
||||
) -> None:
|
||||
if isinstance(cloud_server, str):
|
||||
if cloud_server == 'cn':
|
||||
self._host = DEFAULT_OAUTH2_API_HOST
|
||||
else:
|
||||
if cloud_server != 'cn':
|
||||
self._host = f'{cloud_server}.{DEFAULT_OAUTH2_API_HOST}'
|
||||
self._base_url = f'https://{self._host}'
|
||||
if isinstance(client_id, str):
|
||||
@ -350,8 +349,8 @@ class MIoTHttpClient:
|
||||
async def get_user_info_async(self) -> dict:
|
||||
http_res = await self._session.get(
|
||||
url='https://open.account.xiaomi.com/user/profile',
|
||||
params={'clientId': self._client_id,
|
||||
'token': self._access_token},
|
||||
params={
|
||||
'clientId': self._client_id, 'token': self._access_token},
|
||||
headers={'content-type': 'application/x-www-form-urlencoded'},
|
||||
timeout=MIHOME_HTTP_API_TIMEOUT
|
||||
)
|
||||
@ -386,7 +385,9 @@ class MIoTHttpClient:
|
||||
|
||||
return cert
|
||||
|
||||
async def __get_dev_room_page_async(self, max_id: str = None) -> dict:
|
||||
async def __get_dev_room_page_async(
|
||||
self, max_id: Optional[str] = None
|
||||
) -> dict:
|
||||
res_obj = await self.__mihome_api_post_async(
|
||||
url_path='/app/v2/homeroom/get_dev_room_page',
|
||||
data={
|
||||
@ -442,7 +443,7 @@ class MIoTHttpClient:
|
||||
if 'result' not in res_obj:
|
||||
raise MIoTHttpError('invalid response result')
|
||||
|
||||
uid: str = None
|
||||
uid: Optional[str] = None
|
||||
home_infos: dict = {}
|
||||
for device_source in ['homelist', 'share_home_list']:
|
||||
home_infos.setdefault(device_source, {})
|
||||
@ -507,7 +508,7 @@ class MIoTHttpClient:
|
||||
return (await self.get_homeinfos_async()).get('uid', None)
|
||||
|
||||
async def __get_device_list_page_async(
|
||||
self, dids: list[str], start_did: str = None
|
||||
self, dids: list[str], start_did: Optional[str] = None
|
||||
) -> dict[str, dict]:
|
||||
req_data: dict = {
|
||||
'limit': 200,
|
||||
@ -575,9 +576,9 @@ class MIoTHttpClient:
|
||||
|
||||
async def get_devices_with_dids_async(
|
||||
self, dids: list[str]
|
||||
) -> dict[str, dict]:
|
||||
) -> Optional[dict[str, dict]]:
|
||||
results: list[dict[str, dict]] = await asyncio.gather(
|
||||
*[self.__get_device_list_page_async(dids[index:index+150])
|
||||
*[self.__get_device_list_page_async(dids=dids[index:index+150])
|
||||
for index in range(0, len(dids), 150)])
|
||||
devices = {}
|
||||
for result in results:
|
||||
@ -587,7 +588,7 @@ class MIoTHttpClient:
|
||||
return devices
|
||||
|
||||
async def get_devices_async(
|
||||
self, home_ids: list[str] = None
|
||||
self, home_ids: Optional[list[str]] = None
|
||||
) -> dict[str, dict]:
|
||||
homeinfos = await self.get_homeinfos_async()
|
||||
homes: dict[str, dict[str, Any]] = {}
|
||||
@ -627,8 +628,9 @@ class MIoTHttpClient:
|
||||
'group_id': group_id
|
||||
} for did in room_info.get('dids', [])})
|
||||
dids = sorted(list(devices.keys()))
|
||||
results: dict[str, dict] = await self.get_devices_with_dids_async(
|
||||
dids=dids)
|
||||
results = await self.get_devices_with_dids_async(dids=dids)
|
||||
if results is None:
|
||||
raise MIoTHttpError('get devices failed')
|
||||
for did in dids:
|
||||
if did not in results:
|
||||
devices.pop(did, None)
|
||||
@ -706,7 +708,7 @@ class MIoTHttpClient:
|
||||
key = f'{result["did"]}.{result["siid"]}.{result["piid"]}'
|
||||
prop_obj = self._get_prop_list.pop(key, None)
|
||||
if prop_obj is None:
|
||||
_LOGGER.error('get prop error, key not exists, %s', result)
|
||||
_LOGGER.info('get prop error, key not exists, %s', result)
|
||||
continue
|
||||
prop_obj['fut'].set_result(result['value'])
|
||||
props_req.remove(key)
|
||||
@ -717,7 +719,7 @@ class MIoTHttpClient:
|
||||
continue
|
||||
prop_obj['fut'].set_result(None)
|
||||
if props_req:
|
||||
_LOGGER.error(
|
||||
_LOGGER.info(
|
||||
'get prop from cloud failed, %s, %s', len(key), props_req)
|
||||
|
||||
if self._get_prop_list:
|
||||
|
@ -53,6 +53,7 @@ from dataclasses import dataclass
|
||||
from enum import Enum, auto
|
||||
import subprocess
|
||||
from typing import Callable, Coroutine, Optional
|
||||
import aiohttp
|
||||
import psutil
|
||||
import ipaddress
|
||||
|
||||
@ -77,38 +78,54 @@ class NetworkInfo:
|
||||
|
||||
class MIoTNetwork:
|
||||
"""MIoT network utilities."""
|
||||
PING_ADDRESS_LIST = [
|
||||
_IP_ADDRESS_LIST: list[str] = [
|
||||
'1.2.4.8', # CNNIC sDNS
|
||||
'8.8.8.8', # Google Public DNS
|
||||
'233.5.5.5', # AliDNS
|
||||
'1.1.1.1', # Cloudflare DNS
|
||||
'114.114.114.114', # 114 DNS
|
||||
'208.67.222.222', # OpenDNS
|
||||
'9.9.9.9', # Quad9 DNS
|
||||
'9.9.9.9' # Quad9
|
||||
]
|
||||
_URL_ADDRESS_LIST: list[str] = [
|
||||
'https://www.bing.com',
|
||||
'https://www.google.com',
|
||||
'https://www.baidu.com'
|
||||
]
|
||||
_REFRESH_INTERVAL = 30
|
||||
_DETECT_TIMEOUT = 6
|
||||
|
||||
_main_loop: asyncio.AbstractEventLoop
|
||||
|
||||
_ip_addr_map: dict[str, float]
|
||||
_url_addr_list: dict[str, float]
|
||||
_http_session: aiohttp.ClientSession
|
||||
|
||||
_refresh_interval: int
|
||||
_refresh_task: asyncio.Task
|
||||
_refresh_timer: asyncio.TimerHandle
|
||||
_refresh_task: Optional[asyncio.Task]
|
||||
_refresh_timer: Optional[asyncio.TimerHandle]
|
||||
|
||||
_network_status: bool
|
||||
_network_info: dict[str, NetworkInfo]
|
||||
|
||||
_sub_list_network_status: dict[str, Callable[[bool], asyncio.Future]]
|
||||
_sub_list_network_status: dict[str, Callable[[bool], Coroutine]]
|
||||
_sub_list_network_info: dict[str, Callable[[
|
||||
InterfaceStatus, NetworkInfo], Coroutine]]
|
||||
|
||||
_ping_address_priority: int
|
||||
|
||||
_done_event: asyncio.Event
|
||||
|
||||
def __init__(
|
||||
self, loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
self,
|
||||
ip_addr_list: Optional[list[str]] = None,
|
||||
url_addr_list: Optional[list[str]] = None,
|
||||
refresh_interval: Optional[int] = None,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
) -> None:
|
||||
self._main_loop = loop or asyncio.get_running_loop()
|
||||
self._ip_addr_map = {
|
||||
ip: self._DETECT_TIMEOUT for ip in
|
||||
ip_addr_list or self._IP_ADDRESS_LIST}
|
||||
self._http_addr_map = {
|
||||
url: self._DETECT_TIMEOUT for url in
|
||||
url_addr_list or self._URL_ADDRESS_LIST}
|
||||
self._http_session = aiohttp.ClientSession()
|
||||
self._refresh_interval = refresh_interval or self._REFRESH_INTERVAL
|
||||
|
||||
self._refresh_interval = None
|
||||
self._refresh_task = None
|
||||
self._refresh_timer = None
|
||||
|
||||
@ -118,10 +135,28 @@ class MIoTNetwork:
|
||||
self._sub_list_network_status = {}
|
||||
self._sub_list_network_info = {}
|
||||
|
||||
self._ping_address_priority = 0
|
||||
|
||||
self._done_event = asyncio.Event()
|
||||
|
||||
async def init_async(self) -> bool:
|
||||
self.__refresh_timer_handler()
|
||||
# MUST get network info before starting
|
||||
return await self._done_event.wait()
|
||||
|
||||
async def deinit_async(self) -> None:
|
||||
if self._refresh_task:
|
||||
self._refresh_task.cancel()
|
||||
self._refresh_task = None
|
||||
if self._refresh_timer:
|
||||
self._refresh_timer.cancel()
|
||||
self._refresh_timer = None
|
||||
await self._http_session.close()
|
||||
|
||||
self._network_status = False
|
||||
self._network_info.clear()
|
||||
self._sub_list_network_status.clear()
|
||||
self._sub_list_network_info.clear()
|
||||
self._done_event.clear()
|
||||
|
||||
@property
|
||||
def network_status(self) -> bool:
|
||||
return self._network_status
|
||||
@ -130,23 +165,28 @@ class MIoTNetwork:
|
||||
def network_info(self) -> dict[str, NetworkInfo]:
|
||||
return self._network_info
|
||||
|
||||
async def deinit_async(self) -> None:
|
||||
if self._refresh_task:
|
||||
self._refresh_task.cancel()
|
||||
self._refresh_task = None
|
||||
if self._refresh_timer:
|
||||
self._refresh_timer.cancel()
|
||||
self._refresh_timer = None
|
||||
|
||||
self._refresh_interval = None
|
||||
self._network_status = False
|
||||
self._network_info.clear()
|
||||
self._sub_list_network_status.clear()
|
||||
self._sub_list_network_info.clear()
|
||||
self._done_event.clear()
|
||||
async def update_addr_list_async(
|
||||
self,
|
||||
ip_addr_list: Optional[list[str]] = None,
|
||||
url_addr_list: Optional[list[str]] = None,
|
||||
) -> None:
|
||||
new_ip_map: dict = {}
|
||||
for ip in ip_addr_list or self._IP_ADDRESS_LIST:
|
||||
if ip in self._ip_addr_map:
|
||||
new_ip_map[ip] = self._ip_addr_map[ip]
|
||||
else:
|
||||
new_ip_map[ip] = self._DETECT_TIMEOUT
|
||||
self._ip_addr_map = new_ip_map
|
||||
new_url_map: dict = {}
|
||||
for url in url_addr_list or self._URL_ADDRESS_LIST:
|
||||
if url in self._http_addr_map:
|
||||
new_url_map[url] = self._http_addr_map[url]
|
||||
else:
|
||||
new_url_map[url] = self._DETECT_TIMEOUT
|
||||
self._http_addr_map = new_url_map
|
||||
|
||||
def sub_network_status(
|
||||
self, key: str, handler: Callable[[bool], asyncio.Future]
|
||||
self, key: str, handler: Callable[[bool], Coroutine]
|
||||
) -> None:
|
||||
self._sub_list_network_status[key] = handler
|
||||
|
||||
@ -162,58 +202,107 @@ class MIoTNetwork:
|
||||
def unsub_network_info(self, key: str) -> None:
|
||||
self._sub_list_network_info.pop(key, None)
|
||||
|
||||
async def init_async(self, refresh_interval: int = 30) -> bool:
|
||||
self._refresh_interval = refresh_interval
|
||||
self.__refresh_timer_handler()
|
||||
# MUST get network info before starting
|
||||
return await self._done_event.wait()
|
||||
|
||||
async def refresh_async(self) -> None:
|
||||
self.__refresh_timer_handler()
|
||||
|
||||
async def get_network_status_async(self, timeout: int = 6) -> bool:
|
||||
return await self._main_loop.run_in_executor(
|
||||
None, self.__get_network_status, False, timeout)
|
||||
async def get_network_status_async(self) -> bool:
|
||||
try:
|
||||
ip_addr: str = ''
|
||||
ip_ts: float = self._DETECT_TIMEOUT
|
||||
for ip, ts in self._ip_addr_map.items():
|
||||
if ts < ip_ts:
|
||||
ip_addr = ip
|
||||
ip_ts = ts
|
||||
if (
|
||||
ip_ts < self._DETECT_TIMEOUT
|
||||
and await self.ping_multi_async(ip_list=[ip_addr])
|
||||
):
|
||||
return True
|
||||
url_addr: str = ''
|
||||
url_ts: float = self._DETECT_TIMEOUT
|
||||
for http, ts in self._http_addr_map.items():
|
||||
if ts < url_ts:
|
||||
url_addr = http
|
||||
url_ts = ts
|
||||
if (
|
||||
url_ts < self._DETECT_TIMEOUT
|
||||
and await self.http_multi_async(url_list=[url_addr])
|
||||
):
|
||||
return True
|
||||
# Detect all addresses
|
||||
results = await asyncio.gather(
|
||||
*[self.ping_multi_async(), self.http_multi_async()])
|
||||
return any(results)
|
||||
except Exception as err: # pylint: disable=broad-exception-caught
|
||||
_LOGGER.error('get network status error, %s', err)
|
||||
return False
|
||||
|
||||
async def get_network_info_async(self) -> dict[str, NetworkInfo]:
|
||||
return await self._main_loop.run_in_executor(
|
||||
None, self.__get_network_info)
|
||||
|
||||
async def ping_multi_async(
|
||||
self, ip_list: Optional[list[str]] = None
|
||||
) -> bool:
|
||||
addr_list = ip_list or list(self._ip_addr_map.keys())
|
||||
tasks = []
|
||||
for addr in addr_list:
|
||||
tasks.append(self.__ping_async(addr))
|
||||
results = await asyncio.gather(*tasks)
|
||||
for addr, ts in zip(addr_list, results):
|
||||
if addr in self._ip_addr_map:
|
||||
self._ip_addr_map[addr] = ts
|
||||
return any([ts < self._DETECT_TIMEOUT for ts in results])
|
||||
|
||||
async def http_multi_async(
|
||||
self, url_list: Optional[list[str]] = None
|
||||
) -> bool:
|
||||
addr_list = url_list or list(self._http_addr_map.keys())
|
||||
tasks = []
|
||||
for addr in addr_list:
|
||||
tasks.append(self.__http_async(url=addr))
|
||||
results = await asyncio.gather(*tasks)
|
||||
for addr, ts in zip(addr_list, results):
|
||||
if addr in self._http_addr_map:
|
||||
self._http_addr_map[addr] = ts
|
||||
return any([ts < self._DETECT_TIMEOUT for ts in results])
|
||||
|
||||
def __calc_network_address(self, ip: str, netmask: str) -> str:
|
||||
return str(ipaddress.IPv4Network(
|
||||
f'{ip}/{netmask}', strict=False).network_address)
|
||||
|
||||
def __ping(
|
||||
self, address: Optional[str] = None, timeout: int = 6
|
||||
) -> bool:
|
||||
param = '-n' if platform.system().lower() == 'windows' else '-c'
|
||||
command = ['ping', param, '1', address]
|
||||
async def __ping_async(self, address: Optional[str] = None) -> float:
|
||||
start_ts: float = self._main_loop.time()
|
||||
try:
|
||||
output = subprocess.run(
|
||||
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
check=True, timeout=timeout)
|
||||
return output.returncode == 0
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
*(
|
||||
[
|
||||
'ping', '-n', '1', '-w',
|
||||
str(self._DETECT_TIMEOUT*1000), address]
|
||||
if platform.system().lower() == 'windows' else
|
||||
[
|
||||
'ping', '-c', '1', '-w',
|
||||
str(self._DETECT_TIMEOUT), address]),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE
|
||||
)
|
||||
await process.communicate()
|
||||
if process.returncode == 0:
|
||||
return self._main_loop.time() - start_ts
|
||||
return self._DETECT_TIMEOUT
|
||||
except Exception as err: # pylint: disable=broad-exception-caught
|
||||
print(err)
|
||||
return self._DETECT_TIMEOUT
|
||||
|
||||
async def __http_async(self, url: str) -> float:
|
||||
start_ts: float = self._main_loop.time()
|
||||
try:
|
||||
async with self._http_session.get(
|
||||
url, timeout=self._DETECT_TIMEOUT):
|
||||
return self._main_loop.time() - start_ts
|
||||
except Exception: # pylint: disable=broad-exception-caught
|
||||
return False
|
||||
|
||||
def __get_network_status(
|
||||
self, with_retry: bool = True, timeout: int = 6
|
||||
) -> bool:
|
||||
if self._ping_address_priority >= len(self.PING_ADDRESS_LIST):
|
||||
self._ping_address_priority = 0
|
||||
|
||||
if self.__ping(
|
||||
self.PING_ADDRESS_LIST[self._ping_address_priority], timeout):
|
||||
return True
|
||||
if not with_retry:
|
||||
return False
|
||||
for index in range(len(self.PING_ADDRESS_LIST)):
|
||||
if index == self._ping_address_priority:
|
||||
continue
|
||||
if self.__ping(self.PING_ADDRESS_LIST[index], timeout):
|
||||
self._ping_address_priority = index
|
||||
return True
|
||||
return False
|
||||
pass
|
||||
return self._DETECT_TIMEOUT
|
||||
|
||||
def __get_network_info(self) -> dict[str, NetworkInfo]:
|
||||
interfaces = psutil.net_if_addrs()
|
||||
@ -246,12 +335,10 @@ class MIoTNetwork:
|
||||
for handler in self._sub_list_network_info.values():
|
||||
self._main_loop.create_task(handler(status, info))
|
||||
|
||||
async def __update_status_and_info_async(self, timeout: int = 6) -> None:
|
||||
async def __update_status_and_info_async(self) -> None:
|
||||
try:
|
||||
status: bool = await self._main_loop.run_in_executor(
|
||||
None, self.__get_network_status, timeout)
|
||||
infos = await self._main_loop.run_in_executor(
|
||||
None, self.__get_network_info)
|
||||
status: bool = await self.get_network_status_async()
|
||||
infos = await self.get_network_info_async()
|
||||
|
||||
if self._network_status != status:
|
||||
for handler in self._sub_list_network_status.values():
|
||||
@ -273,7 +360,7 @@ class MIoTNetwork:
|
||||
# Remove
|
||||
self.__call_network_info_change(
|
||||
InterfaceStatus.REMOVE,
|
||||
self._network_info.pop(name, None))
|
||||
self._network_info.pop(name))
|
||||
# Add
|
||||
for name, info in infos.items():
|
||||
self._network_info[name] = info
|
||||
|
Reference in New Issue
Block a user