mijiaAPI 1.5.0__tar.gz → 2.0.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mijiaAPI
3
- Version: 1.5.0
3
+ Version: 2.0.0
4
4
  Summary: A Python API for Xiaomi Mijia
5
5
  License: GPLv3
6
6
  Author: Do1e
@@ -30,6 +30,12 @@ Description-Content-Type: text/markdown
30
30
  [![PyPI](https://img.shields.io/badge/PyPI-mijiaAPI-blue)](https://pypi.org/project/mijiaAPI/)
31
31
  [![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-green.svg)](https://opensource.org/licenses/GPL-3.0)
32
32
 
33
+ ## ⚠️ 重要提醒
34
+
35
+ **自 v1.5.0 版本以来,本项目包含多项破坏性变更!**
36
+
37
+ 如果您正在从旧版本升级,请务必查看 [CHANGELOG.md](CHANGELOG.md) 以了解详细的变更内容和迁移指南。
38
+
33
39
  ## 安装
34
40
 
35
41
  ### 从 PyPI 安装(推荐)
@@ -91,15 +97,18 @@ yay -S python-mijia-api
91
97
 
92
98
  #### 设备与场景获取与控制:
93
99
 
100
+ 下述方法可参考 [demos/test_apis.py](demos/test_apis.py) 中的示例。
101
+
94
102
  * `get_devices_list() -> list`:获取设备列表
95
103
  * `get_homes_list() -> list`:获取家庭列表(包含房间信息)
96
104
  * `get_scenes_list(home_id: str) -> list`:获取手动场景列表
97
105
  - 在米家 App 中通过 **米家→添加→手动控制** 设置
98
106
  * `run_scene(scene_id: str) -> bool`:运行指定场景
99
- * `get_consumable_items(home_id: str) -> list`:获取设备的耗材信息
107
+ * `get_consumable_items(home_id: str, owner_id: Optional[int] = None) -> list`:获取设备的耗材信息,如果是共享家庭,需要额外指定 `owner_id` 参数
100
108
  * `get_devices_prop(data: list) -> list`:获取设备属性
101
109
  * `set_devices_prop(data: list) -> list`:设置设备属性
102
110
  * `run_action(data: dict) -> dict`:执行设备的特定动作
111
+ * `get_statistics(data: dict) -> list`:获取设备的统计信息,如空调每个月的耗电量,参考 [demos/test_get_statistics.py](demos/test_get_statistics.py)
103
112
 
104
113
  设备属性和动作的相关参数(`siid`, `piid`, `aiid`)可以从 [米家产品库](https://home.miot-spec.com) 查询:
105
114
  * 访问 `https://home.miot-spec.com/spec/{model}`(`model` 在设备列表中获取)
@@ -145,9 +154,9 @@ mijiaDevice(api: mijiaAPI, dev_info: dict = None, dev_name: str = None, did: str
145
154
 
146
155
  #### 使用方法控制:
147
156
 
148
- * `set(name: str, did: str, value: Union[bool, int]) -> bool`:设置设备属性
149
- * `get(name: str, did: str) -> Union[bool, int, float, str]`:获取设备属性
150
- * `run_action(name: str, did: str = None, value: Any = None, **kwargs) -> bool`:执行设备动作
157
+ * `set(name: str, value: Union[bool, int, float, str], did: Optional[str] = None) -> bool`:设置设备属性
158
+ * `get(name: str, did: Optional[str] = None) -> Union[bool, int, float, str]`:获取设备属性
159
+ * `run_action(name: str, did: Optional[str] = None, value: Optional[Union[list, tuple]] = None, **kwargs) -> bool`:执行设备动作
151
160
 
152
161
  #### 属性样式访问:
153
162
 
@@ -255,6 +264,23 @@ mijiaAPI --run 明天天气如何
255
264
  mijiaAPI --run 打开台灯并将亮度调至最大 --quiet
256
265
  ```
257
266
 
267
+ ## 常见问题
268
+
269
+ ### 账号密码登录失败
270
+
271
+ 现在登录似乎100%遇到验证码,建议使用扫码登录。
272
+
273
+ ### XXX设备的XXX如何获取/设置
274
+
275
+ 我拥有的设备有限,无法保证能解答这类问题,但也欢迎提交 [issue](https://github.com/Do1e/mijia-api/issues),可能需要你将设备共享给我进行抓包或者自行抓包给我提供请求和响应,提供har文件的话注意自行删除cookie等敏感信息。
276
+
277
+ ### 如何抓包
278
+
279
+ 小米官方给了一个[抓包教程](https://iot.mi.com/new/doc/accesses/direct-access/extension-development/troubleshooting/packet_capture),我没试过,不确定是否能行,如果抓包成功数据是加密的,可以使用 [demos/decrypt.py](demos/decrypt.py) 解密。
280
+
281
+ 我自己的解决方案是使用一个获取了root的手机,安装 [reqable](https://reqable.com/zh-CN/) 进行抓包,导出 HAR 文件后使用 [demos/decrypt_har.py](demos/decrypt_har.py) 解密。
282
+
283
+
258
284
  ## 致谢
259
285
 
260
286
  * [janzlan/mijia-api](https://gitee.com/janzlan/mijia-api/tree/master)
@@ -6,6 +6,12 @@
6
6
  [![PyPI](https://img.shields.io/badge/PyPI-mijiaAPI-blue)](https://pypi.org/project/mijiaAPI/)
7
7
  [![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-green.svg)](https://opensource.org/licenses/GPL-3.0)
8
8
 
9
+ ## ⚠️ 重要提醒
10
+
11
+ **自 v1.5.0 版本以来,本项目包含多项破坏性变更!**
12
+
13
+ 如果您正在从旧版本升级,请务必查看 [CHANGELOG.md](CHANGELOG.md) 以了解详细的变更内容和迁移指南。
14
+
9
15
  ## 安装
10
16
 
11
17
  ### 从 PyPI 安装(推荐)
@@ -67,15 +73,18 @@ yay -S python-mijia-api
67
73
 
68
74
  #### 设备与场景获取与控制:
69
75
 
76
+ 下述方法可参考 [demos/test_apis.py](demos/test_apis.py) 中的示例。
77
+
70
78
  * `get_devices_list() -> list`:获取设备列表
71
79
  * `get_homes_list() -> list`:获取家庭列表(包含房间信息)
72
80
  * `get_scenes_list(home_id: str) -> list`:获取手动场景列表
73
81
  - 在米家 App 中通过 **米家→添加→手动控制** 设置
74
82
  * `run_scene(scene_id: str) -> bool`:运行指定场景
75
- * `get_consumable_items(home_id: str) -> list`:获取设备的耗材信息
83
+ * `get_consumable_items(home_id: str, owner_id: Optional[int] = None) -> list`:获取设备的耗材信息,如果是共享家庭,需要额外指定 `owner_id` 参数
76
84
  * `get_devices_prop(data: list) -> list`:获取设备属性
77
85
  * `set_devices_prop(data: list) -> list`:设置设备属性
78
86
  * `run_action(data: dict) -> dict`:执行设备的特定动作
87
+ * `get_statistics(data: dict) -> list`:获取设备的统计信息,如空调每个月的耗电量,参考 [demos/test_get_statistics.py](demos/test_get_statistics.py)
79
88
 
80
89
  设备属性和动作的相关参数(`siid`, `piid`, `aiid`)可以从 [米家产品库](https://home.miot-spec.com) 查询:
81
90
  * 访问 `https://home.miot-spec.com/spec/{model}`(`model` 在设备列表中获取)
@@ -121,9 +130,9 @@ mijiaDevice(api: mijiaAPI, dev_info: dict = None, dev_name: str = None, did: str
121
130
 
122
131
  #### 使用方法控制:
123
132
 
124
- * `set(name: str, did: str, value: Union[bool, int]) -> bool`:设置设备属性
125
- * `get(name: str, did: str) -> Union[bool, int, float, str]`:获取设备属性
126
- * `run_action(name: str, did: str = None, value: Any = None, **kwargs) -> bool`:执行设备动作
133
+ * `set(name: str, value: Union[bool, int, float, str], did: Optional[str] = None) -> bool`:设置设备属性
134
+ * `get(name: str, did: Optional[str] = None) -> Union[bool, int, float, str]`:获取设备属性
135
+ * `run_action(name: str, did: Optional[str] = None, value: Optional[Union[list, tuple]] = None, **kwargs) -> bool`:执行设备动作
127
136
 
128
137
  #### 属性样式访问:
129
138
 
@@ -231,6 +240,23 @@ mijiaAPI --run 明天天气如何
231
240
  mijiaAPI --run 打开台灯并将亮度调至最大 --quiet
232
241
  ```
233
242
 
243
+ ## 常见问题
244
+
245
+ ### 账号密码登录失败
246
+
247
+ 现在登录似乎100%遇到验证码,建议使用扫码登录。
248
+
249
+ ### XXX设备的XXX如何获取/设置
250
+
251
+ 我拥有的设备有限,无法保证能解答这类问题,但也欢迎提交 [issue](https://github.com/Do1e/mijia-api/issues),可能需要你将设备共享给我进行抓包或者自行抓包给我提供请求和响应,提供har文件的话注意自行删除cookie等敏感信息。
252
+
253
+ ### 如何抓包
254
+
255
+ 小米官方给了一个[抓包教程](https://iot.mi.com/new/doc/accesses/direct-access/extension-development/troubleshooting/packet_capture),我没试过,不确定是否能行,如果抓包成功数据是加密的,可以使用 [demos/decrypt.py](demos/decrypt.py) 解密。
256
+
257
+ 我自己的解决方案是使用一个获取了root的手机,安装 [reqable](https://reqable.com/zh-CN/) 进行抓包,导出 HAR 文件后使用 [demos/decrypt_har.py](demos/decrypt_har.py) 解密。
258
+
259
+
234
260
  ## 致谢
235
261
 
236
262
  * [janzlan/mijia-api](https://gitee.com/janzlan/mijia-api/tree/master)
@@ -0,0 +1,3 @@
1
+ from .login import mijiaLogin
2
+ from .apis import mijiaAPI
3
+ from .devices import mijiaDevice, get_device_info
@@ -146,10 +146,6 @@ def init_api(auth_path: str) -> mijiaAPI:
146
146
 
147
147
  def get_devices_list(api: mijiaAPI, verbose: bool = True) -> dict:
148
148
  devices = api.get_devices_list()
149
- if 'list' in devices:
150
- devices = devices['list']
151
- else:
152
- devices = []
153
149
  if verbose:
154
150
  print("Devices:")
155
151
  for device in devices:
@@ -165,10 +161,6 @@ def get_homes_list(api: mijiaAPI, verbose: bool = True, device_mapping: Optional
165
161
  if device_mapping is None:
166
162
  device_mapping = get_devices_list(api, verbose=False)
167
163
  homes = api.get_homes_list()
168
- if 'homelist' in homes:
169
- homes = homes['homelist']
170
- else:
171
- homes = []
172
164
  if verbose:
173
165
  print("Homes:")
174
166
  for home in homes:
@@ -189,7 +181,7 @@ def get_homes_list(api: mijiaAPI, verbose: bool = True, device_mapping: Optional
189
181
  dids = ', '.join(devices_name)
190
182
  print(f" - {room['name']}\n"
191
183
  f" id: {room['id']}\n"
192
- f" dids: {dids}\n"
184
+ f" devices: {dids}\n"
193
185
  f" create time: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(room['create_time']))}")
194
186
  home_mapping = {home['id']: home for home in homes}
195
187
  return home_mapping
@@ -200,10 +192,6 @@ def get_scenes_list(api: mijiaAPI, verbose: bool = True, home_mapping: Optional[
200
192
  scene_mapping = {}
201
193
  for home_id, home in home_mapping.items():
202
194
  scenes = api.get_scenes_list(home_id)
203
- if 'scene_info_list' in scenes:
204
- scenes = scenes['scene_info_list']
205
- else:
206
- scenes = []
207
195
  if scenes and verbose:
208
196
  print(f"Scenes in {home['name']} ({home_id}):")
209
197
  for scene in scenes:
@@ -218,15 +206,12 @@ def get_consumable_items(api: mijiaAPI, home_mapping: Optional[dict] = None):
218
206
  if home_mapping is None:
219
207
  home_mapping = get_homes_list(api, verbose=False)
220
208
  for home_id, home in home_mapping.items():
221
- items = api.get_consumable_items(home_id)
222
- if 'items' in items:
223
- items = items['items'][0]['consumes_data']
224
- else:
225
- items = []
209
+ items = api.get_consumable_items(home_id, home['uid'])
226
210
  print(f"Consumable items in {home['name']} ({home_id}):")
227
211
  for item in items:
228
- print(f" - {item['details'][0]['description']} in {item['name']}({item['did']})\n"
229
- f" value: {item['details'][0]['value']}")
212
+ for consumes_data in item['consumes_data']:
213
+ print(f" - {consumes_data['details'][0]['description']} in {consumes_data['name']}({consumes_data['did']})\n"
214
+ f" value: {consumes_data['details'][0]['value']}")
230
215
 
231
216
  def run_scene(api: mijiaAPI, scene_id: str, scene_mapping: Optional[dict] = None) -> bool:
232
217
  if scene_mapping is None:
@@ -261,7 +246,7 @@ def get(args):
261
246
  def set(args):
262
247
  api = init_api(args.auth_path)
263
248
  device = mijiaDevice(api, dev_name=args.dev_name)
264
- ret = device.set_v2(args.prop_name, args.value)
249
+ ret = device.set(args.prop_name, args.value)
265
250
  unit = device.prop_list[args.prop_name].unit
266
251
  if ret:
267
252
  print(f"The {args.prop_name} of {args.dev_name} is set to {args.value} {unit if unit else ''}")
@@ -1,5 +1,5 @@
1
1
  from datetime import datetime
2
- from typing import Union
2
+ from typing import Union, Optional
3
3
 
4
4
  import requests
5
5
  import requests.cookies
@@ -53,16 +53,30 @@ class mijiaAPI(object):
53
53
  return True
54
54
  return False
55
55
 
56
- def get_devices_list(self) -> dict:
56
+ def get_devices_list(self) -> list:
57
57
  """
58
58
  获取设备列表。
59
59
 
60
60
  Returns:
61
61
  dict: 设备列表。
62
62
  """
63
- uri = '/home/device_list'
64
- data = {"getVirtualModel": False, "getHuamiDevices": 0}
65
- return self._post_process(post_data(self.session, self.ssecurity, uri, data))
63
+ uri = '/home/home_device_list'
64
+ home_list = self.get_homes_list()
65
+ devices = []
66
+ for home in home_list:
67
+ data = {
68
+ "home_owner": home['uid'],
69
+ "home_id": int(home['id']),
70
+ "limit": 200,
71
+ "get_split_device": True,
72
+ "support_smart_home": True,
73
+ "get_cariot_device": True,
74
+ "get_third_device": True
75
+ }
76
+ ret = self._post_process(post_data(self.session, self.ssecurity, uri, data))
77
+ if ret and ret.get('device_info'):
78
+ devices.extend(ret['device_info'])
79
+ return devices
66
80
 
67
81
  def get_homes_list(self) -> list:
68
82
  """
@@ -71,9 +85,9 @@ class mijiaAPI(object):
71
85
  Returns:
72
86
  list: 家庭列表,包括房间信息。
73
87
  """
74
- uri = '/v2/homeroom/gethome'
75
- data = {"fg": False, "fetch_share": True, "fetch_share_dev": True, "limit": 300, "app_ver": 7}
76
- return self._post_process(post_data(self.session, self.ssecurity, uri, data))
88
+ uri = '/v2/homeroom/gethome_merged'
89
+ data = {"fg": True, "fetch_share": True, "fetch_share_dev": True, "limit": 300, "app_ver": 7}
90
+ return self._post_process(post_data(self.session, self.ssecurity, uri, data))['homelist']
77
91
 
78
92
  def get_scenes_list(self, home_id: str) -> list:
79
93
  """
@@ -89,7 +103,10 @@ class mijiaAPI(object):
89
103
  """
90
104
  uri = '/appgateway/miot/appsceneservice/AppSceneService/GetSceneList'
91
105
  data = {"home_id": home_id}
92
- return self._post_process(post_data(self.session, self.ssecurity, uri, data))
106
+ ret = self._post_process(post_data(self.session, self.ssecurity, uri, data))
107
+ if ret and 'scene_info_list' in ret:
108
+ return ret['scene_info_list']
109
+ return []
93
110
 
94
111
  def run_scene(self, scene_id: str) -> bool:
95
112
  """
@@ -105,19 +122,23 @@ class mijiaAPI(object):
105
122
  data = {"scene_id": scene_id, "trigger_key": "user.click"}
106
123
  return self._post_process(post_data(self.session, self.ssecurity, uri, data))
107
124
 
108
- def get_consumable_items(self, home_id: str) -> list:
125
+ def get_consumable_items(self, home_id: str, owner_id: Optional[int] = None) -> list:
109
126
  """
110
127
  获取耗材列表。
111
128
 
112
129
  Args:
113
130
  home_id (str): 家庭ID,从get_homes_list获取。
131
+ owner_id (str, optional): 用户ID,默认为None,如果`home_id`为共享家庭,则需要提供owner_id。
114
132
 
115
133
  Returns:
116
134
  list: 耗材列表。
117
135
  """
118
136
  uri = '/v2/home/standard_consumable_items'
119
- data = {"home_id": int(home_id), "owner_id": self.userId}
120
- return self._post_process(post_data(self.session, self.ssecurity, uri, data))
137
+ data = {"home_id": int(home_id), "owner_id": int(owner_id) if owner_id else self.userId}
138
+ ret = self._post_process(post_data(self.session, self.ssecurity, uri, data))
139
+ if ret and 'items' in ret:
140
+ return ret['items']
141
+ return []
121
142
 
122
143
  def get_devices_prop(self, data: list) -> list:
123
144
  """
@@ -155,7 +176,7 @@ class mijiaAPI(object):
155
176
 
156
177
  示例(yeelink.light.lamp4):
157
178
  [
158
- {"did": "1234567890", "siid": 2, "piid": 2, "value": 50} # 设置亮度为50%
179
+ {"did": "1234567890", "siid": 2, "piid": 2, "value": 50}, # 设置亮度为50%
159
180
  {"did": "1234567890", "siid": 2, "piid": 3, "value": 2700} # 设置色温为2700K
160
181
  ]
161
182
 
@@ -178,7 +199,7 @@ class mijiaAPI(object):
178
199
  - value: 参数列表
179
200
 
180
201
  示例(xiaomi.feeder.pi2001):
181
- {"did": "1234567890", "siid": 2, "aiid": 1, "value": [2]}, # 远程喂食2份
202
+ {"did": "1234567890", "siid": 2, "aiid": 1, "value": [2]} # 远程喂食2份
182
203
 
183
204
  Returns:
184
205
  dict: 操作结果。
@@ -186,3 +207,36 @@ class mijiaAPI(object):
186
207
  uri = '/miotspec/action'
187
208
  data = {"params": data}
188
209
  return self._post_process(post_data(self.session, self.ssecurity, uri, data))
210
+
211
+ def get_statistics(self, data: dict) -> list:
212
+ """
213
+ 获取设备的统计信息。
214
+
215
+ Args:
216
+ data (dict): 请求参数,包含以下键:
217
+ - did: 设备ID,从get_devices_list获取
218
+ - key: siid.piid,表示要获取统计数据的属性
219
+ - data_type: 统计类型,可选值包括:
220
+ - 'stat_hour_v3': 按小时统计
221
+ - 'stat_day_v3': 按天统计
222
+ - 'stat_week_v3': 按周统计
223
+ - 'stat_month_v3': 按月统计
224
+ - limit: 返回的最大条目数,可选参数
225
+ - time_start: 开始时间戳,单位为秒
226
+ - time_end: 结束时间戳,单位为秒
227
+
228
+ 示例(lumi.acpartner.mcn04 的 power-consumption):
229
+ {
230
+ "did": "1234567890",
231
+ "key": "7.1",
232
+ "data_type": "stat_month_v3",
233
+ "limit": 24,
234
+ "time_start": 1685548800,
235
+ "time_end": 1750694400,
236
+ } # 2023-06-01 00:00:00 到 2025-06-24 00:00:00 的月度统计数据
237
+
238
+ Returns:
239
+ list: 统计信息列表。
240
+ """
241
+ uri = '/v2/user/statistics'
242
+ return self._post_process(post_data(self.session, self.ssecurity, uri, data))
@@ -113,7 +113,7 @@ class mijiaDevice(object):
113
113
  self.api = api
114
114
  if dev_info is None:
115
115
  devices_list = self.api.get_devices_list()
116
- matches = [device for device in devices_list.get('list', []) if device['name'] == dev_name]
116
+ matches = [device for device in devices_list if device['name'] == dev_name]
117
117
  if not matches:
118
118
  raise ValueError(f"Device {dev_name} not found")
119
119
  elif len(matches) > 1:
@@ -152,14 +152,14 @@ class mijiaDevice(object):
152
152
  f"Properties:\n{prop_list_str if prop_list_str else 'No properties available'}\n"
153
153
  f"Actions:\n{action_list_str if action_list_str else 'No actions available'}")
154
154
 
155
- def set(self, name: str, did: str, value: Union[bool, int, float, str]) -> bool:
155
+ def set(self, name: str, value: Union[bool, int, float, str], did: Optional[str] = None) -> bool:
156
156
  """
157
157
  设置设备的属性值。
158
158
 
159
159
  Args:
160
160
  name (str): 属性名称。
161
- did (str): 设备ID。
162
161
  value (Union[bool, int, float, str]): 属性值。
162
+ did (str, optional): 设备ID。如未指定,则使用实例化时的did。默认为None。
163
163
 
164
164
  Returns:
165
165
  bool: 执行结果(True/False)。
@@ -168,6 +168,10 @@ class mijiaDevice(object):
168
168
  ValueError: 如果属性不存在、属性为只读或值无效。
169
169
  RuntimeError: 如果设置属性失败。
170
170
  """
171
+ if did is None:
172
+ did = self.did
173
+ if did is None:
174
+ raise ValueError('Please specify the did')
171
175
  if name not in self.prop_list:
172
176
  raise ValueError(f'Unsupported property: {name}, available properties: {list(self.prop_list.keys())}')
173
177
  prop = self.prop_list[name]
@@ -232,28 +236,6 @@ class mijiaDevice(object):
232
236
  logger.debug(f"Set property: {self.name} -> {name}, value: {value}, result: {result}")
233
237
  return result['code'] == 0
234
238
 
235
- def set_v2(self, name: str, value: Union[bool, int, float, str], did: Optional[str] = None) -> bool:
236
- """
237
- 设置设备的属性值(v2版本,需在实例化时指定did或在调用时提供)。
238
-
239
- Args:
240
- name (str): 属性名称。
241
- value (Union[bool, int, float, str]): 属性值。
242
- did (str, optional): 设备ID。如未指定,则使用实例化时的did。默认为None。
243
-
244
- Returns:
245
- bool: 执行结果(True/False)。
246
-
247
- Raises:
248
- ValueError: 如果未指定设备ID。
249
- """
250
- if did is not None:
251
- return self.set(name, did, value)
252
- elif self.did is not None:
253
- return self.set(name, self.did, value)
254
- else:
255
- raise ValueError('Please specify the did')
256
-
257
239
  def get(self, name: str, did: Optional[str] = None) -> Union[bool, int, float, str]:
258
240
  """
259
241
  获取设备的属性值。
@@ -303,7 +285,7 @@ class mijiaDevice(object):
303
285
  RuntimeError: 如果设置属性失败。
304
286
  """
305
287
  if 'prop_list' in self.__dict__ and name in self.prop_list:
306
- if not self.set_v2(name, value):
288
+ if not self.set(name, value):
307
289
  raise RuntimeError(f'Failed to set property: {name}')
308
290
  else:
309
291
  super().__setattr__(name, value)
@@ -376,41 +358,6 @@ class mijiaDevice(object):
376
358
  return result['code'] == 0
377
359
 
378
360
 
379
- class mijiaDevices(mijiaDevice):
380
- def __init__(
381
- self,
382
- api: mijiaAPI,
383
- dev_info: Optional[dict] = None,
384
- dev_name: Optional[str] = None,
385
- did: Optional[str] = None,
386
- sleep_time: Optional[Union[int, float]] = 0.5
387
- ):
388
- """
389
- 初始化设备对象。
390
-
391
- 如果未提供设备信息,则根据设备名称获取设备信息。如果两者均未提供,则抛出异常。
392
- 如果同时提供了设备信息和设备名称,则以设备信息为准。
393
-
394
- Args:
395
- api (mijiaAPI): 米家API对象。
396
- dev_info (dict, optional): 设备信息字典,从get_device_info获取。默认为None。
397
- dev_name (str, optional): 设备名称,从get_devices_list获取。默认为None。
398
- did (str, optional): 设备ID,如未指定,则需要在调用get/set时指定。默认为None。
399
- sleep_time ([int, float], optional): 调用设备属性的间隔时间。默认为0.5秒。
400
-
401
- Raises:
402
- RuntimeError: 如果dev_info和dev_name都未提供。
403
- ValueError: 如果找不到指定设备或找到多个同名设备。
404
-
405
- Note:
406
- - 如果同时提供了dev_info和dev_name,则以dev_info为准。
407
- - 如果只提供了dev_name,则根据名称自动获取设备信息。
408
- - 如果只提供了dev_info,则直接使用该信息。
409
- """
410
- super().__init__(api, dev_info, dev_name, did, sleep_time)
411
- logger.warning("`mijiaDevices` will be deprecated in future versions, use `mijiaDevice` instead.")
412
-
413
-
414
361
  def get_device_info(device_model: str, cache_path: Optional[str] = os.path.join(os.path.expanduser("~"), ".config/mijia-api")) -> dict:
415
362
  """
416
363
  获取设备信息,用于初始化mijiaDevice对象。
@@ -122,6 +122,8 @@ class mijiaLogin(object):
122
122
  latest_utc_time = max(parsed_times)
123
123
  china_time = latest_utc_time + timedelta(hours=8)
124
124
 
125
+ # [FIXME] 实测此处的过期时间并不准确,实际过期时间可能大于此处获取的时间
126
+ # cookie 中唯一用到的 serviceToken 并无过期时间
125
127
  return china_time
126
128
 
127
129
  def _save_auth(self) -> None:
@@ -188,6 +190,7 @@ class mijiaLogin(object):
188
190
  'ssecurity': ret_data['ssecurity'],
189
191
  'deviceId': data['deviceId'],
190
192
  'serviceToken': cookies['serviceToken'],
193
+ 'cUserId': cookies['cUserId'],
191
194
  'expireTime': self._extract_latest_gmt_datetime(cookies).strftime('%Y-%m-%d %H:%M:%S'),
192
195
  'account_info': self._get_account_info(ret_data['userId'])
193
196
  }
@@ -273,6 +276,7 @@ class mijiaLogin(object):
273
276
  'ssecurity': ret_data['ssecurity'],
274
277
  'deviceId': data['deviceId'],
275
278
  'serviceToken': cookies['serviceToken'],
279
+ 'cUserId': cookies['cUserId'],
276
280
  'expireTime': self._extract_latest_gmt_datetime(cookies).strftime('%Y-%m-%d %H:%M:%S'),
277
281
  'account_info': self._get_account_info(ret_data['userId'])
278
282
  }
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mijiaAPI"
3
- version = "1.5.0"
3
+ version = "2.0.0"
4
4
  description = "A Python API for Xiaomi Mijia"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.9,<4.0"
@@ -15,7 +15,7 @@ mijiaAPI = "mijiaAPI.__main__:cli"
15
15
 
16
16
  [tool.poetry]
17
17
  name = "mijiaAPI"
18
- version = "1.5.0"
18
+ version = "2.0.0"
19
19
  description = "A Python API for Xiaomi Mijia"
20
20
  authors = ["Do1e <dpj.email@qq.com>"]
21
21
  license = "GPLv3"
@@ -1,3 +0,0 @@
1
- from .login import mijiaLogin
2
- from .apis import mijiaAPI
3
- from .devices import mijiaDevice, mijiaDevices, get_device_info
File without changes
File without changes
File without changes
File without changes
File without changes