Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

请求api返回小米账号登录信息失效时,自动重新登陆 #508

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions custom_components/xiaomi_miot_raw/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ async def async_remove_entry(hass, entry):
async def _setup_micloud_entry(hass, config_entry):
"""Thanks to @AlexxIT """
data: dict = config_entry.data.copy()
hass.data[DOMAIN]['micloud_config'] = data
server_location = data.get('server_location') or 'cn'

session = aiohttp_client.async_create_clientsession(hass, auto_cleanup=False)
Expand Down
57 changes: 54 additions & 3 deletions custom_components/xiaomi_miot_raw/basic_dev_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import json
import time
import logging
from datetime import timedelta
from datetime import timedelta, datetime
from functools import partial
from dataclasses import dataclass

Expand Down Expand Up @@ -62,7 +62,9 @@

class GenericMiotDevice(Entity):
"""通用 MiOT 设备"""


lastAutoUpdateAccountTime=datetime.now()-timedelta(seconds=3600)

def __init__(self, device, config, device_info, hass = None, mi_type = None):
"""Initialize the entity."""

Expand Down Expand Up @@ -506,7 +508,56 @@ def pre_process_data(key, value):
statedict[key] = pre_process_data(key, dict1[value['siid']][value['piid']])

else:
pass
# auth err
# 小米账号登录信息失效
# 自动重新登录,间隔3600秒
lostTime=(datetime.now()-GenericMiotDevice.lastAutoUpdateAccountTime).total_seconds()
_LOGGER.debug("miaccount auth err:lostTime:%d" % (lostTime))
if (lostTime>3600):
_LOGGER.warning("auto update mi_account token")
GenericMiotDevice.lastAutoUpdateAccountTime=datetime.now()

config=self.hass.data[DOMAIN]['micloud_config']
#_LOGGER.debug(f"self.hass.data[DOMAIN]['config']: {json.dumps (config)}")
if 'username' in config:
cloud=self._cloud_instance
resp = await cloud.login(config['username'],
config['password'])
if resp == (0, None):
#让新 token 实时生效
for item in self.hass.data[DOMAIN]['cloud_instance_list']:
mc = item['cloud_instance']
mc.login_by_credientals(
cloud.auth["user_id"],
cloud.auth['service_token'],
cloud.auth['ssecurity']
)

if self.hass.config_entries.async_entries(DOMAIN): #更新每个设备的token
_LOGGER.warning("Found existing config entries")
for entry in self.hass.config_entries.async_entries(DOMAIN):
if (
entry.data.get("update_from_cloud")
):
_LOGGER.warning("Updating existing entry")
update_from_cloud=entry.data.get("update_from_cloud")
update_from_cloud_new={
"did": update_from_cloud["did"],
"userId": update_from_cloud["userId"],
"serviceToken": cloud.auth['service_token'],
"ssecurity": cloud.auth['ssecurity'],
"server_location": update_from_cloud["server_location"]
}
entry_data_new=dict(entry.data)
entry_data_new.update({"update_from_cloud":update_from_cloud_new})
entry_id = entry.entry_id
self.hass.data[DOMAIN]['configs'][entry_id] = entry_data_new
self.hass.config_entries.async_update_entry( #保存新token到文件
entry,
data=entry_data_new,
)
else:
_LOGGER.error("config.data no username")

self._fail_count = 0
self._state_attrs.update(statedict)
Expand Down
37 changes: 37 additions & 0 deletions custom_components/xiaomi_miot_raw/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import re

import logging
import asyncio
from types import coroutine
from typing import OrderedDict
Expand Down Expand Up @@ -40,6 +41,8 @@
from .deps.special_devices import SPECIAL_DEVICES
from .deps.xiaomi_cloud_new import MiCloud

_LOGGER = logging.getLogger(__name__)

SERVERS = {
'cn': "China",
'de': "Europe",
Expand Down Expand Up @@ -735,6 +738,40 @@ async def async_step_update_xiaomi_account(self, user_input=None, error=None, hi
if resp == (0, None):
self._all_config.update(user_input)
self._all_config.update(cloud.auth)

#让新 token 实时生效
for item in self.hass.data[DOMAIN]['cloud_instance_list']:
mc = item['cloud_instance']
mc.login_by_credientals(
cloud.auth["user_id"],
cloud.auth['service_token'],
cloud.auth['ssecurity']
)

if self.hass.config_entries.async_entries(DOMAIN): #更新每个设备的token
_LOGGER.info("Found existing config entries")
for entry in self.hass.config_entries.async_entries(DOMAIN):
if (
entry.data.get("update_from_cloud")
):
_LOGGER.info("Updating existing entry")
update_from_cloud=entry.data.get("update_from_cloud")
update_from_cloud_new={
"did": update_from_cloud["did"],
"userId": update_from_cloud["userId"],
"serviceToken": cloud.auth['service_token'],
"ssecurity": cloud.auth['ssecurity'],
"server_location": update_from_cloud["server_location"]
}
entry_data_new=dict(entry.data)
entry_data_new.update({"update_from_cloud":update_from_cloud_new})
entry_id = entry.entry_id
self.hass.data[DOMAIN]['configs'][entry_id] = entry_data_new
self.hass.config_entries.async_update_entry( #保存新token到文件
entry,
data=entry_data_new,
)

self._steps.pop(0)
return await self._steps[0]
elif resp[0] == -2:
Expand Down
8 changes: 6 additions & 2 deletions custom_components/xiaomi_miot_raw/deps/xiaomi_cloud_new.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ async def login(self, username: str, password: str):
'ssecurity': data['ssecurity'],
'service_token': token
}
_LOGGER.info(f"user_id:{data['userId']},service_token: {token}")
return (0, None)

except Exception as e:
Expand Down Expand Up @@ -160,6 +161,7 @@ async def get_devices(self, server: str):
except Exception:
loc = "en_US"
try:
_LOGGER.info(f"user_id:{self.auth['user_id']},token:{self.auth['service_token']}")
r = await self.session.post(baseurl + url, cookies={
'userId': self.auth['user_id'],
'serviceToken': self.auth['service_token'],
Expand All @@ -171,7 +173,7 @@ async def get_devices(self, server: str):
'signature': signature,
'_nonce': nonce,
'data': data
}, timeout=5)
}, timeout=30)

resp = await r.json(content_type=None)
assert resp['code'] == 0, resp
Expand Down Expand Up @@ -203,6 +205,7 @@ async def request_miot_api(self, api, data = None, server: str = None):
'cache-control': "no-cache",
}
try:
_LOGGER.info(f"user_id:{self.auth['user_id']},token:{self.auth['service_token']}")
r = await self.session.post(url, cookies={
'userId': self.auth['user_id'],
'serviceToken': self.auth['service_token'],
Expand All @@ -213,7 +216,7 @@ async def request_miot_api(self, api, data = None, server: str = None):
'signature': signature,
'_nonce': nonce,
'data': data
}, timeout=5)
}, timeout=30)

self._fail_count = 0
resp = await r.json(content_type=None)
Expand All @@ -230,6 +233,7 @@ async def request_miot_api(self, api, data = None, server: str = None):
return resp

except (asyncio.TimeoutError, ClientConnectorError) as ex:
_LOGGER.exception("request_miot_api:")
if self._fail_count < 3 and api == "/miotspec/prop/get":
self._fail_count += 1
_LOGGER.info(f"Error while requesting MIoT api {api} : {ex} ({self._fail_count})")
Expand Down