mijiaAPI 1.3.12__tar.gz → 1.3.13__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mijiaapi-1.3.12 → mijiaapi-1.3.13}/PKG-INFO +1 -1
- {mijiaapi-1.3.12 → mijiaapi-1.3.13}/mijiaAPI/apis.py +7 -6
- {mijiaapi-1.3.12 → mijiaapi-1.3.13}/mijiaAPI/login.py +55 -22
- {mijiaapi-1.3.12 → mijiaapi-1.3.13}/pyproject.toml +2 -2
- mijiaapi-1.3.12/mijiaAPI/__main__.py +0 -27
- {mijiaapi-1.3.12 → mijiaapi-1.3.13}/LICENSE +0 -0
- {mijiaapi-1.3.12 → mijiaapi-1.3.13}/README.md +0 -0
- {mijiaapi-1.3.12 → mijiaapi-1.3.13}/mijiaAPI/__init__.py +0 -0
- {mijiaapi-1.3.12 → mijiaapi-1.3.13}/mijiaAPI/code.py +0 -0
- {mijiaapi-1.3.12 → mijiaapi-1.3.13}/mijiaAPI/devices.py +0 -0
- {mijiaapi-1.3.12 → mijiaapi-1.3.13}/mijiaAPI/logger.py +0 -0
- {mijiaapi-1.3.12 → mijiaapi-1.3.13}/mijiaAPI/urls.py +0 -0
- {mijiaapi-1.3.12 → mijiaapi-1.3.13}/mijiaAPI/utils.py +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
from datetime import datetime
|
|
1
2
|
from typing import Union
|
|
3
|
+
|
|
2
4
|
import requests
|
|
3
5
|
import requests.cookies
|
|
4
6
|
|
|
@@ -43,13 +45,12 @@ class mijiaAPI(object):
|
|
|
43
45
|
Returns:
|
|
44
46
|
bool: API可用返回True,否则返回False。
|
|
45
47
|
"""
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
if 'expireTime' in self.session.cookies:
|
|
49
|
+
expire_time = datetime.strptime(self.session.cookies['expireTime'], '%Y-%m-%d %H:%M:%S')
|
|
50
|
+
if expire_time < datetime.now():
|
|
51
|
+
return False
|
|
50
52
|
return True
|
|
51
|
-
|
|
52
|
-
return False
|
|
53
|
+
return False
|
|
53
54
|
|
|
54
55
|
def get_devices_list(self) -> dict:
|
|
55
56
|
"""
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
1
|
import hashlib
|
|
3
2
|
import json
|
|
4
3
|
import os
|
|
5
4
|
import random
|
|
5
|
+
import re
|
|
6
6
|
import string
|
|
7
7
|
import time
|
|
8
|
+
from datetime import datetime, timedelta
|
|
9
|
+
from typing import Optional
|
|
8
10
|
from urllib import parse
|
|
9
11
|
|
|
10
|
-
from qrcode import QRCode
|
|
11
12
|
import requests
|
|
13
|
+
from qrcode import QRCode
|
|
12
14
|
|
|
15
|
+
from .logger import logger
|
|
13
16
|
from .urls import msgURL, loginURL, qrURL, accountURL
|
|
14
17
|
from .utils import defaultUA
|
|
15
|
-
from .logger import logger
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
class LoginError(Exception):
|
|
@@ -94,6 +96,34 @@ class mijiaLogin(object):
|
|
|
94
96
|
}
|
|
95
97
|
return data
|
|
96
98
|
|
|
99
|
+
@staticmethod
|
|
100
|
+
def extract_latest_gmt_datetime(data: dict) -> datetime:
|
|
101
|
+
"""
|
|
102
|
+
提取过期时间并转换为中国时区。
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
data (dict): 用户凭证数据,包含GMT时间的键值对。
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
datetime: 转换后的中国时区时间。
|
|
109
|
+
|
|
110
|
+
Raises:
|
|
111
|
+
LoginError: 如果没有找到GMT时间键或解析失败,抛出登录错误。
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
gmt_time_keys = [
|
|
115
|
+
k for k in data.keys() if
|
|
116
|
+
isinstance(k, str) and re.match(r'\d{2}-[A-Za-z]{3}-\d{4} \d{2}:\d{2}:\d{2} GMT', k)
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
if not gmt_time_keys:
|
|
120
|
+
raise LoginError(-1, 'No GMT time keys found in the data')
|
|
121
|
+
parsed_times = [datetime.strptime(k, '%d-%b-%Y %H:%M:%S GMT') for k in gmt_time_keys]
|
|
122
|
+
latest_utc_time = max(parsed_times)
|
|
123
|
+
china_time = latest_utc_time + timedelta(hours=8)
|
|
124
|
+
|
|
125
|
+
return china_time
|
|
126
|
+
|
|
97
127
|
def _save_auth(self) -> None:
|
|
98
128
|
"""
|
|
99
129
|
保存认证数据到文件。
|
|
@@ -127,7 +157,8 @@ class mijiaLogin(object):
|
|
|
127
157
|
Raises:
|
|
128
158
|
LoginError: 登录失败时抛出。
|
|
129
159
|
"""
|
|
130
|
-
logger.warning(
|
|
160
|
+
logger.warning(
|
|
161
|
+
'There is a high probability of verification code with account and password. Please try other login methods')
|
|
131
162
|
data = self._get_index()
|
|
132
163
|
post_data = {
|
|
133
164
|
'qs': data['qs'],
|
|
@@ -148,21 +179,22 @@ class mijiaLogin(object):
|
|
|
148
179
|
raise LoginError(-1, 'Failed to get location')
|
|
149
180
|
if 'notificationUrl' in ret_data:
|
|
150
181
|
raise LoginError(-1, 'Verification code required, please try other login methods')
|
|
151
|
-
auth_data = {
|
|
152
|
-
'userId': ret_data['userId'],
|
|
153
|
-
'ssecurity': ret_data['ssecurity'],
|
|
154
|
-
'deviceId': data['deviceId'],
|
|
155
|
-
}
|
|
156
182
|
ret = self.session.get(ret_data['location'])
|
|
157
183
|
if ret.status_code != 200:
|
|
158
184
|
raise LoginError(ret.status_code, f'Failed to get location, {ret.text}')
|
|
159
185
|
cookies = self.session.cookies.get_dict()
|
|
160
|
-
|
|
161
|
-
self.auth_data =
|
|
162
|
-
|
|
186
|
+
|
|
187
|
+
self.auth_data = {
|
|
188
|
+
'userId': ret_data['userId'],
|
|
189
|
+
'ssecurity': ret_data['ssecurity'],
|
|
190
|
+
'deviceId': data['deviceId'],
|
|
191
|
+
'serviceToken': cookies['serviceToken'],
|
|
192
|
+
'expireTime': self.extract_latest_gmt_datetime(cookies).strftime('%Y-%m-%d %H:%M:%S'),
|
|
193
|
+
**self._get_account(ret_data['userId'])
|
|
194
|
+
}
|
|
163
195
|
|
|
164
196
|
self._save_auth()
|
|
165
|
-
return auth_data
|
|
197
|
+
return self.auth_data
|
|
166
198
|
|
|
167
199
|
@staticmethod
|
|
168
200
|
def _print_qr(loginurl: str, box_size: int = 10) -> None:
|
|
@@ -232,21 +264,22 @@ class mijiaLogin(object):
|
|
|
232
264
|
ret_data = json.loads(ret.text[11:])
|
|
233
265
|
if ret_data['code'] != 0:
|
|
234
266
|
raise LoginError(ret_data['code'], ret_data['desc'])
|
|
235
|
-
auth_data = {
|
|
236
|
-
'userId': ret_data['userId'],
|
|
237
|
-
'ssecurity': ret_data['ssecurity'],
|
|
238
|
-
'deviceId': data['deviceId'],
|
|
239
|
-
}
|
|
240
267
|
ret = self.session.get(ret_data['location'])
|
|
241
268
|
if ret.status_code != 200:
|
|
242
269
|
raise LoginError(ret.status_code, f'Failed to get location, {ret.text}')
|
|
243
270
|
cookies = self.session.cookies.get_dict()
|
|
244
|
-
|
|
245
|
-
self.auth_data =
|
|
246
|
-
|
|
271
|
+
|
|
272
|
+
self.auth_data = {
|
|
273
|
+
'userId': ret_data['userId'],
|
|
274
|
+
'ssecurity': ret_data['ssecurity'],
|
|
275
|
+
'deviceId': data['deviceId'],
|
|
276
|
+
'serviceToken': cookies['serviceToken'],
|
|
277
|
+
'expireTime': self.extract_latest_gmt_datetime(cookies).strftime('%Y-%m-%d %H:%M:%S'),
|
|
278
|
+
**self._get_account(ret_data['userId'])
|
|
279
|
+
}
|
|
247
280
|
|
|
248
281
|
self._save_auth()
|
|
249
|
-
return auth_data
|
|
282
|
+
return self.auth_data
|
|
250
283
|
|
|
251
284
|
def __del__(self):
|
|
252
285
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mijiaAPI"
|
|
3
|
-
version = "1.3.
|
|
3
|
+
version = "1.3.13"
|
|
4
4
|
description = "A Python API for Xiaomi Mijia"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.9,<4.0"
|
|
@@ -12,7 +12,7 @@ dependencies = [
|
|
|
12
12
|
|
|
13
13
|
[tool.poetry]
|
|
14
14
|
name = "mijiaAPI"
|
|
15
|
-
version = "1.3.
|
|
15
|
+
version = "1.3.13"
|
|
16
16
|
description = "A Python API for Xiaomi Mijia"
|
|
17
17
|
authors = ["Do1e <dpj.email@qq.com>"]
|
|
18
18
|
license = "GPLv3"
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import argparse
|
|
2
|
-
import sys
|
|
3
|
-
|
|
4
|
-
from .login import mijiaLogin
|
|
5
|
-
|
|
6
|
-
def parse_args(args):
|
|
7
|
-
parser = argparse.ArgumentParser(description="Mijia API CLI")
|
|
8
|
-
parser.add_argument(
|
|
9
|
-
'-i', '--login',
|
|
10
|
-
action='store_true',
|
|
11
|
-
help="Login by QR code and save cookies to file",
|
|
12
|
-
)
|
|
13
|
-
parser.add_argument(
|
|
14
|
-
'-c', '--cookie_path',
|
|
15
|
-
type=str,
|
|
16
|
-
help="Path to the cookies file",
|
|
17
|
-
)
|
|
18
|
-
return parser.parse_args(args)
|
|
19
|
-
|
|
20
|
-
def main(args):
|
|
21
|
-
args = parse_args(args)
|
|
22
|
-
if args.login:
|
|
23
|
-
api = mijiaLogin(save_path=args.cookie_path)
|
|
24
|
-
auth = api.QRlogin()
|
|
25
|
-
|
|
26
|
-
if __name__ == "__main__":
|
|
27
|
-
main(sys.argv[1:])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|