mijiaAPI 4.1.3__tar.gz → 4.2.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,108 +1,108 @@
1
- Metadata-Version: 2.4
2
- Name: mijiaAPI
3
- Version: 4.1.3
4
- Summary: A Python API for Xiaomi Mijia
5
- Author-email: Do1e <i@do1e.cn>
6
- License-Expression: GPL-3.0-or-later
7
- Project-URL: Homepage, https://mijia-api.do1e.com/
8
- Project-URL: Repository, https://github.com/Do1e/mijia-api
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: Operating System :: OS Independent
11
- Requires-Python: <4.0,>=3.10
12
- Description-Content-Type: text/markdown
13
- License-File: LICENSE
14
- Requires-Dist: fastmcp>=3.4.2
15
- Requires-Dist: pillow>=11.3.0
16
- Requires-Dist: pycryptodome>=3.23.0
17
- Requires-Dist: qrcode>=8.2
18
- Requires-Dist: requests>=2.32.5
19
- Requires-Dist: tzlocal>=5.3.1
20
- Dynamic: license-file
21
-
22
- # mijiaAPI
23
-
24
- 米家 API,可以使用代码、CLI、MCP 直接控制米家设备。
25
-
26
- > 🎉 **v4.0.0 版本已支持 MCP**,详见 [MCP 使用文档](https://mijia-api.do1e.com/usage/mcp)
27
- > 🎉 **v4.1.0 版本已支持 Agent Skill**,详见 [Agent Skill 使用文档](https://mijia-api.do1e.com/usage/skill)
28
-
29
- [![GitHub](https://img.shields.io/badge/GitHub-Do1e%2Fmijia--api-blue)](https://github.com/Do1e/mijia-api)
30
- [![PyPI](https://img.shields.io/badge/PyPI-mijiaAPI-blue)](https://pypi.org/project/mijiaAPI/)
31
- [![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-green.svg)](https://opensource.org/licenses/GPL-3.0)
32
-
33
- 📖 **完整文档请见 [mijia-api.do1e.com](https://mijia-api.do1e.com)**
34
-
35
- [常见问题](https://mijia-api.do1e.com/faq) | [更新日志](https://mijia-api.do1e.com/changelog)
36
-
37
- ## 安装
38
-
39
- > 要求 Python >= 3.10
40
-
41
- ```bash
42
- pip install mijiaAPI
43
- # Or `uv add mijiaAPI` for uv users
44
- ```
45
-
46
- 其他安装方式(源码安装、AUR)请参考[文档](https://mijia-api.do1e.com/guide/installation)。
47
-
48
- ## 快速开始
49
-
50
- ```python
51
- from mijiaAPI import mijiaAPI, mijiaDevice
52
-
53
- # 初始化并扫码登录(认证文件默认保存在 ~/.config/mijia-api/auth.json)
54
- api = mijiaAPI()
55
- api.login()
56
-
57
- # 通过设备名称控制设备(推荐)
58
- device = mijiaDevice(api, dev_name="我的台灯")
59
- device.on = True # 打开设备
60
- device.brightness = 60 # 设置亮度为 60%
61
-
62
- # 查看设备支持的所有属性和动作
63
- print(device)
64
- ```
65
-
66
- CLI 用法:
67
-
68
- ```bash
69
- mijiaAPI login # 扫码登录
70
- mijiaAPI -l # 列出所有设备
71
- mijiaAPI set --dev_name "台灯" --prop_name "brightness" --value 60
72
- ```
73
-
74
- MCP 用法:
75
-
76
- 执行 `uvx mijiaAPI login -p /path/to/auth.json` 登录后,在 MCP 客户端配置中添加以下内容即可接入米家:
77
-
78
- ```json
79
- {
80
- "mcpServers": {
81
- "mijia-api": {
82
- "command": "uvx",
83
- "args": ["mijiaAPI", "mcp", "-p", "/path/to/auth.json"]
84
- }
85
- }
86
- }
87
- ```
88
-
89
- 更多用法(API 基础调用、MCP Server、CLI 完整参数、最佳实践等)请查阅[完整文档](https://mijia-api.do1e.com)。
90
-
91
- ## 致谢
92
-
93
- * [janzlan/mijia-api](https://gitee.com/janzlan/mijia-api/tree/master)
94
- * [米家 APP 网络请求的抓包、加解密与构造的代码笔记](https://imkero.net/posts/mihome-app-api/)
95
- * [al-one/hass-xiaomi-miot](https://github.com/al-one/hass-xiaomi-miot)
96
-
97
- ## 开源许可
98
-
99
- 本项目采用 [GPL-3.0](LICENSE) 开源许可证。
100
-
101
- **请注意:GPL-3.0 是具有“强传染性”的开源许可证。**
102
- 如果您在您的项目中使用、修改或分发本项目的代码(包括作为库依赖),您的整个项目也**必须**以 GPL-3.0 或兼容许可证开源发布。
103
-
104
- ## 免责声明
105
-
106
- * 本项目仅供学习交流使用,不得用于商业用途,如有侵权请联系删除
107
- * 用户使用本项目所产生的任何后果,需自行承担风险
108
- * 开发者不对使用本项目产生的任何直接或间接损失负责
1
+ Metadata-Version: 2.4
2
+ Name: mijiaAPI
3
+ Version: 4.2.0
4
+ Summary: A Python API for Xiaomi Mijia
5
+ Author-email: Do1e <i@do1e.cn>
6
+ License-Expression: GPL-3.0-or-later
7
+ Project-URL: Homepage, https://mijia-api.do1e.com/
8
+ Project-URL: Repository, https://github.com/Do1e/mijia-api
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: <4.0,>=3.10
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: fastmcp>=3.4.2
15
+ Requires-Dist: pillow>=11.3.0
16
+ Requires-Dist: pycryptodome>=3.23.0
17
+ Requires-Dist: qrcode>=8.2
18
+ Requires-Dist: requests>=2.32.5
19
+ Requires-Dist: tzlocal>=5.3.1
20
+ Dynamic: license-file
21
+
22
+ # mijiaAPI
23
+
24
+ 米家 API,可以使用代码、CLI、MCP 直接控制米家设备。
25
+
26
+ > 🎉 **v4.0.0 版本已支持 MCP**,详见 [MCP 使用文档](https://mijia-api.do1e.com/usage/mcp)
27
+ > 🎉 **v4.1.0 版本已支持 Agent Skill**,详见 [Agent Skill 使用文档](https://mijia-api.do1e.com/usage/skill)
28
+
29
+ [![GitHub](https://img.shields.io/badge/GitHub-Do1e%2Fmijia--api-blue)](https://github.com/Do1e/mijia-api)
30
+ [![PyPI](https://img.shields.io/badge/PyPI-mijiaAPI-blue)](https://pypi.org/project/mijiaAPI/)
31
+ [![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-green.svg)](https://opensource.org/licenses/GPL-3.0)
32
+
33
+ 📖 **完整文档请见 [mijia-api.do1e.com](https://mijia-api.do1e.com)**
34
+
35
+ [常见问题](https://mijia-api.do1e.com/faq) | [更新日志](https://mijia-api.do1e.com/changelog)
36
+
37
+ ## 安装
38
+
39
+ > 要求 Python >= 3.10
40
+
41
+ ```bash
42
+ pip install mijiaAPI
43
+ # Or `uv add mijiaAPI` for uv users
44
+ ```
45
+
46
+ 其他安装方式(源码安装、AUR)请参考[文档](https://mijia-api.do1e.com/guide/installation)。
47
+
48
+ ## 快速开始
49
+
50
+ ```python
51
+ from mijiaAPI import mijiaAPI, mijiaDevice
52
+
53
+ # 初始化并扫码登录(认证文件默认保存在 ~/.config/mijia-api/auth.json)
54
+ api = mijiaAPI()
55
+ api.login()
56
+
57
+ # 通过设备名称控制设备(推荐)
58
+ device = mijiaDevice(api, dev_name="我的台灯")
59
+ device.on = True # 打开设备
60
+ device.brightness = 60 # 设置亮度为 60%
61
+
62
+ # 查看设备支持的所有属性和动作
63
+ print(device)
64
+ ```
65
+
66
+ CLI 用法:
67
+
68
+ ```bash
69
+ mijiaAPI login # 扫码登录
70
+ mijiaAPI -l # 列出所有设备
71
+ mijiaAPI set --dev_name "台灯" --prop_name "brightness" --value 60
72
+ ```
73
+
74
+ MCP 用法:
75
+
76
+ 执行 `uvx mijiaAPI login -p /path/to/auth.json` 登录后,在 MCP 客户端配置中添加以下内容即可接入米家:
77
+
78
+ ```json
79
+ {
80
+ "mcpServers": {
81
+ "mijia-api": {
82
+ "command": "uvx",
83
+ "args": ["mijiaAPI", "mcp", "-p", "/path/to/auth.json"]
84
+ }
85
+ }
86
+ }
87
+ ```
88
+
89
+ 更多用法(API 基础调用、MCP Server、CLI 完整参数、最佳实践等)请查阅[完整文档](https://mijia-api.do1e.com)。
90
+
91
+ ## 致谢
92
+
93
+ * [janzlan/mijia-api](https://gitee.com/janzlan/mijia-api/tree/master)
94
+ * [米家 APP 网络请求的抓包、加解密与构造的代码笔记](https://imkero.net/posts/mihome-app-api/)
95
+ * [al-one/hass-xiaomi-miot](https://github.com/al-one/hass-xiaomi-miot)
96
+
97
+ ## 开源许可
98
+
99
+ 本项目采用 [GPL-3.0](LICENSE) 开源许可证。
100
+
101
+ **请注意:GPL-3.0 是具有“强传染性”的开源许可证。**
102
+ 如果您在您的项目中使用、修改或分发本项目的代码(包括作为库依赖),您的整个项目也**必须**以 GPL-3.0 或兼容许可证开源发布。
103
+
104
+ ## 免责声明
105
+
106
+ * 本项目仅供学习交流使用,不得用于商业用途,如有侵权请联系删除
107
+ * 用户使用本项目所产生的任何后果,需自行承担风险
108
+ * 开发者不对使用本项目产生的任何直接或间接损失负责
@@ -1,6 +1,7 @@
1
1
  import json
2
2
  import re
3
3
  import time
4
+ from collections import Counter
4
5
  from pathlib import Path
5
6
  from typing import Optional, Union
6
7
 
@@ -20,6 +21,19 @@ from .version import version
20
21
 
21
22
 
22
23
  device_url = "https://home.miot-spec.com/spec/"
24
+ device_info_version = 1
25
+
26
+
27
+ def _deduplicate_names(items: list[dict], iid_key: str) -> None:
28
+ name_counts = Counter(item["name"] for item in items)
29
+ for item in items:
30
+ if name_counts[item["name"]] > 1:
31
+ item["name"] = f"{item['name']}-{item['method']['siid']}"
32
+
33
+ name_counts = Counter(item["name"] for item in items)
34
+ for item in items:
35
+ if name_counts[item["name"]] > 1:
36
+ item["name"] = f"{item['name']}-{item['method'][iid_key]}"
23
37
 
24
38
 
25
39
  class DevProp():
@@ -252,6 +266,7 @@ def get_device_info(device_model: str, cache_path: Optional[Union[str, Path]] =
252
266
 
253
267
  返回值:
254
268
  dict: 设备规格信息字典,包含以下字段:
269
+ - version (int): 设备信息缓存格式版本
255
270
  - name (str): 设备名称
256
271
  - model (str): 设备型号
257
272
  - properties (list): 设备属性列表,每个属性包含以下字段:
@@ -275,12 +290,16 @@ def get_device_info(device_model: str, cache_path: Optional[Union[str, Path]] =
275
290
  >>> print(info['name']) # 输出设备名称
276
291
  >>> print(info['properties'][0]['name']) # 输出第一个属性的名称
277
292
  """
293
+ cache_file = None
278
294
  if cache_path is not None:
279
295
  cache_file = Path(cache_path) / f"{device_model}.json"
280
296
  if cache_file.exists():
281
297
  logger.debug(f"从缓存加载设备信息: {cache_file}")
282
298
  with cache_file.open("r", encoding="utf-8") as f:
283
- return json.load(f)
299
+ cached_result = json.load(f)
300
+ if cached_result.get("version") == device_info_version:
301
+ return cached_result
302
+ logger.debug(f"设备信息缓存版本不匹配,重新获取: {cache_file}")
284
303
  response = requests.get(device_url + device_model, headers={
285
304
  "User-Agent": f"mijiaAPI/{version}"
286
305
  })
@@ -297,6 +316,7 @@ def get_device_info(device_model: str, cache_path: Optional[Union[str, Path]] =
297
316
  model = product["model"]
298
317
  i18n_zh = content["props"]["i18n"]["zh_cn"]
299
318
  result = {
319
+ "version": device_info_version,
300
320
  "name": name,
301
321
  "model": model,
302
322
  "properties": [],
@@ -304,11 +324,8 @@ def get_device_info(device_model: str, cache_path: Optional[Union[str, Path]] =
304
324
  }
305
325
  services = content["props"]["tree"]["services"]
306
326
 
307
- properties_name = []
308
- actions_name = []
309
327
  for svc in services:
310
328
  siid = svc["iid"]
311
- svc_type = svc["type"]
312
329
  for prop in svc.get("properties", []):
313
330
  piid = prop["iid"]
314
331
  if prop["format"].startswith("int"):
@@ -345,9 +362,6 @@ def get_device_info(device_model: str, cache_path: Optional[Union[str, Path]] =
345
362
  if vl_zh:
346
363
  vl_entry["desc_zh_cn"] = vl_zh
347
364
  item["value-list"].append(vl_entry)
348
- if item["name"] in properties_name:
349
- item["name"] = f"{svc_type}-{item['name']}"
350
- properties_name.append(item["name"])
351
365
  result["properties"].append(item)
352
366
  for act in svc.get("actions", []):
353
367
  aiid = act["iid"]
@@ -360,15 +374,13 @@ def get_device_info(device_model: str, cache_path: Optional[Union[str, Path]] =
360
374
  "aiid": aiid
361
375
  }
362
376
  }
363
- if act_item["name"] in actions_name:
364
- act_item["name"] = f"{svc_type}-{act_item['name']}"
365
- actions_name.append(act_item["name"])
366
377
  result["actions"].append(act_item)
367
378
 
368
- if cache_path is not None:
369
- cache_path = Path(cache_path)
370
- cache_path.mkdir(parents=True, exist_ok=True)
371
- cache_file = cache_path / f"{device_model}.json"
379
+ _deduplicate_names(result["properties"], "piid")
380
+ _deduplicate_names(result["actions"], "aiid")
381
+
382
+ if cache_file is not None:
383
+ cache_file.parent.mkdir(parents=True, exist_ok=True)
372
384
  logger.debug(f"缓存设备信息到: {cache_file}")
373
385
  with cache_file.open("w", encoding="utf-8") as f:
374
386
  json.dump(result, f, indent=2, ensure_ascii=False)
@@ -0,0 +1 @@
1
+ version = "4.2.0"
@@ -1,4 +1,4 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -1 +0,0 @@
1
- version = "4.1.3"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes