mijiaAPI 3.0.5__tar.gz → 3.1.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.
Files changed (28) hide show
  1. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/CHANGELOG.md +7 -0
  2. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/PKG-INFO +1 -7
  3. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/README.md +0 -6
  4. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/mijiaAPI/__main__.py +3 -5
  5. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/mijiaAPI/devices.py +65 -55
  6. mijiaapi-3.1.0/mijiaAPI/version.py +1 -0
  7. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/mijiaAPI.egg-info/PKG-INFO +1 -7
  8. mijiaapi-3.0.5/mijiaAPI/version.py +0 -1
  9. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  10. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/.gitignore +0 -0
  11. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/FAQ.md +0 -0
  12. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/LICENSE +0 -0
  13. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/demos/test_apis.py +0 -0
  14. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/demos/test_get_statistics.py +0 -0
  15. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/demos/test_login.py +0 -0
  16. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/mijiaAPI/__init__.py +0 -0
  17. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/mijiaAPI/apis.py +0 -0
  18. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/mijiaAPI/errors.py +0 -0
  19. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/mijiaAPI/logger.py +0 -0
  20. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/mijiaAPI/miutils.py +0 -0
  21. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/mijiaAPI.egg-info/SOURCES.txt +0 -0
  22. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/mijiaAPI.egg-info/dependency_links.txt +0 -0
  23. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/mijiaAPI.egg-info/entry_points.txt +0 -0
  24. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/mijiaAPI.egg-info/requires.txt +0 -0
  25. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/mijiaAPI.egg-info/top_level.txt +0 -0
  26. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/pyproject.toml +0 -0
  27. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/setup.cfg +0 -0
  28. {mijiaapi-3.0.5 → mijiaapi-3.1.0}/uv.lock +0 -0
@@ -2,6 +2,13 @@
2
2
 
3
3
  本文档记录了项目的v1.3.7以来的重要变更。
4
4
 
5
+ ## [3.1.0](https://github.com/Do1e/mijia-api/compare/v3.0.5...v3.1.0) - 2026-05-27
6
+ ### new feature
7
+ * 删除设备属性的单位`unit`属性,因为 home.miot-spec.com 上已废弃
8
+ ### bugfix
9
+ * 适配 home.miot-spec.com 新的规格页格式
10
+ * 修复 execute-text-directive 中 quiet 参数的类型转换
11
+
5
12
  ## [3.0.5](https://github.com/Do1e/mijia-api/compare/v3.0.4...v3.0.5) - 2026-01-24
6
13
  ### bugfix
7
14
  * 蓝牙设备控制返回 code 为 1 时表示网关已经接收指令,视为成功。
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mijiaAPI
3
- Version: 3.0.5
3
+ Version: 3.1.0
4
4
  Summary: A Python API for Xiaomi Mijia
5
5
  Author-email: Do1e <i@do1e.cn>
6
6
  License-Expression: GPL-3.0-or-later
@@ -26,12 +26,6 @@ Dynamic: license-file
26
26
  [![PyPI](https://img.shields.io/badge/PyPI-mijiaAPI-blue)](https://pypi.org/project/mijiaAPI/)
27
27
  [![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-green.svg)](https://opensource.org/licenses/GPL-3.0)
28
28
 
29
- ## ⚠️ 重要提醒
30
-
31
- **v1.5.0 和 v3.0.0包含多项破坏性变更!**
32
-
33
- 如果您正在从旧版本升级,请务必查看 [CHANGELOG.md](CHANGELOG.md) 以了解详细的变更内容和迁移指南。
34
-
35
29
  常见问题见 [FAQ.md](FAQ.md)。
36
30
 
37
31
  ## 安装
@@ -6,12 +6,6 @@
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 和 v3.0.0包含多项破坏性变更!**
12
-
13
- 如果您正在从旧版本升级,请务必查看 [CHANGELOG.md](CHANGELOG.md) 以了解详细的变更内容和迁移指南。
14
-
15
9
  常见问题见 [FAQ.md](FAQ.md)。
16
10
 
17
11
  ## 安装
@@ -265,8 +265,7 @@ def get(args):
265
265
  api = init_api(args.auth_path)
266
266
  device = mijiaDevice(api, did=args.did, dev_name=args.dev_name)
267
267
  value = device.get(args.prop_name)
268
- unit = device.prop_list[args.prop_name].unit
269
- print(f"{device.name} ({device.did}) 的 {args.prop_name} 值为 {value} {unit if unit else ''}")
268
+ print(f"{device.name} ({device.did}) 的 {args.prop_name} 值为 {value}")
270
269
 
271
270
  def set(args):
272
271
  api = init_api(args.auth_path)
@@ -276,8 +275,7 @@ def set(args):
276
275
  except Exception as e:
277
276
  print(f"设置 {args.dev_name} 的 {args.prop_name} 值为 {args.value} 失败: {e}")
278
277
  return
279
- unit = device.prop_list[args.prop_name].unit
280
- print(f"{device.name} ({device.did}) 的 {args.prop_name} 值已设置为 {args.value} {unit if unit else ''}")
278
+ print(f"{device.name} ({device.did}) 的 {args.prop_name} 值已设置为 {args.value}")
281
279
 
282
280
  def main(args):
283
281
  args = parse_args(args)
@@ -323,7 +321,7 @@ def main(args):
323
321
  raise ValueError("未找到小爱音箱设备")
324
322
  else:
325
323
  wifispeaker = mijiaDevice(api, dev_name=args.wifispeaker_name)
326
- wifispeaker.run_action('execute-text-directive', _in=[args.run, args.quiet])
324
+ wifispeaker.run_action('execute-text-directive', _in=[args.run, 1 if args.quiet else 0])
327
325
  if hasattr(args, 'func') and args.func is not None:
328
326
  if args.func == 'get':
329
327
  get(args)
@@ -30,7 +30,6 @@ class DevProp():
30
30
  if self.type not in ["bool", "int", "uint", "float", "string"]:
31
31
  raise ValueError(f"不支持的类型: {self.type}, 可选类型: bool, int, uint, float, string")
32
32
  self.rw = prop_dict["rw"]
33
- self.unit = prop_dict["unit"]
34
33
  self.range = prop_dict["range"]
35
34
  self.value_list = prop_dict.get("value-list", None)
36
35
  self.method = prop_dict["method"]
@@ -38,7 +37,7 @@ class DevProp():
38
37
  def __str__(self):
39
38
  lines = [
40
39
  f" {self.name}: {self.desc}",
41
- f" valuetype: {self.type}, rw: {self.rw}, unit: {self.unit}, range: {self.range}"
40
+ f" valuetype: {self.type}, rw: {self.rw}, range: {self.range}"
42
41
  ]
43
42
 
44
43
  if self.value_list:
@@ -260,7 +259,6 @@ def get_device_info(device_model: str, cache_path: Optional[Union[str, Path]] =
260
259
  - description (str): 属性描述
261
260
  - type (str): 属性数据类型(int、uint、float、bool、string)
262
261
  - rw (str): 读写权限('r' 可读,'w' 可写,'rw' 可读写)
263
- - unit (str): 属性单位
264
262
  - range (list): 属性值范围 [min, max, step]
265
263
  - value-list (list): 枚举值列表
266
264
  - method (dict): API 调用方法参数
@@ -288,72 +286,84 @@ def get_device_info(device_model: str, cache_path: Optional[Union[str, Path]] =
288
286
  })
289
287
  if response.status_code != 200:
290
288
  raise GetDeviceInfoError(device_model)
291
- content = re.search(r"data-page=\"(.*?)\">", response.text)
289
+ content = re.search(r"<script data-page=\"app\" type=\"application/json\">(.*?)</script>", response.text)
292
290
  if content is None:
293
291
  raise GetDeviceInfoError(device_model)
294
292
  content = content.group(1)
295
- content = json.loads(content.replace("&quot;", "\""))
296
-
297
- if content["props"]["product"]:
298
- name = content["props"]["product"]["name"]
299
- model = content["props"]["product"]["model"]
300
- else:
301
- name = content["props"]["spec"]["name"]
302
- model = device_model
293
+ content = json.loads(content)
294
+
295
+ product = content["props"]["product"]
296
+ name = product["name"]
297
+ model = product["model"]
298
+ i18n_zh = content["props"]["i18n"]["zh_cn"]
303
299
  result = {
304
300
  "name": name,
305
301
  "model": model,
306
302
  "properties": [],
307
303
  "actions": []
308
304
  }
309
- services = content["props"]["spec"]["services"]
305
+ services = content["props"]["tree"]["services"]
310
306
 
311
307
  properties_name = []
312
308
  actions_name = []
313
- for siid in services:
314
- if "properties" in services[siid]:
315
- for piid in services[siid]["properties"]:
316
- prop = services[siid]["properties"][piid]
317
- if prop["format"].startswith("int"):
318
- prop_type = "int"
319
- elif prop["format"].startswith("uint"):
320
- prop_type = "uint"
321
- else:
322
- prop_type = prop["format"]
323
- item = {
324
- "name": prop["name"],
325
- "description": f"{prop.get('description', '')} / {prop.get('desc_zh_cn', '')}",
326
- "type": prop_type,
327
- "rw": "".join([
328
- "r" if "read" in prop["access"] else "",
329
- "w" if "write" in prop["access"] else ""
330
- ]),
331
- "unit": prop.get("unit", None),
332
- "range": prop.get("value-range", None),
333
- "value-list": prop.get("value-list", None),
334
- "method": {
335
- "siid": int(siid),
336
- "piid": int(piid)
337
- }
309
+ for svc in services:
310
+ siid = svc["iid"]
311
+ svc_type = svc["type"]
312
+ for prop in svc.get("properties", []):
313
+ piid = prop["iid"]
314
+ if prop["format"].startswith("int"):
315
+ prop_type = "int"
316
+ elif prop["format"].startswith("uint"):
317
+ prop_type = "uint"
318
+ else:
319
+ prop_type = prop["format"]
320
+ access_str = "".join([
321
+ "r" if "read" in prop["access"] else "",
322
+ "w" if "write" in prop["access"] else ""
323
+ ])
324
+ zh_cn = i18n_zh.get(f"service:{siid:03d}:property:{piid:03d}", "")
325
+ item = {
326
+ "name": prop["type"],
327
+ "description": f"{prop['description']} / {zh_cn}".rstrip(" / "),
328
+ "type": prop_type,
329
+ "rw": access_str,
330
+ "range": prop.get("valueRange", None),
331
+ "value-list": None,
332
+ "method": {
333
+ "siid": siid,
334
+ "piid": piid
338
335
  }
339
- if item["name"] in properties_name:
340
- item["name"] = f"{services[siid]['name']}-{item['name']}"
341
- properties_name.append(item["name"])
342
- result["properties"].append({k: None if v == "none" else v for k, v in item.items()})
343
- if "actions" in services[siid]:
344
- for aiid in services[siid]["actions"]:
345
- act = services[siid]["actions"][aiid]
346
- if act["name"] in actions_name:
347
- act["name"] = f"{services[siid]['name']}-{act['name']}"
348
- actions_name.append(act["name"])
349
- result["actions"].append({
350
- "name": act["name"],
351
- "description": f"{act.get('description', '')} / {act.get('desc_zh_cn', '')}",
352
- "method": {
353
- "siid": int(siid),
354
- "aiid": int(aiid)
336
+ }
337
+ if prop.get("valueList"):
338
+ item["value-list"] = []
339
+ for vl_item in prop["valueList"]:
340
+ vl_zh = i18n_zh.get(vl_item.get("i18nKey", ""), "")
341
+ vl_entry = {
342
+ "value": vl_item["value"],
343
+ "description": vl_item["description"]
355
344
  }
356
- })
345
+ if vl_zh:
346
+ vl_entry["desc_zh_cn"] = vl_zh
347
+ 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
+ result["properties"].append(item)
352
+ for act in svc.get("actions", []):
353
+ aiid = act["iid"]
354
+ zh_cn = i18n_zh.get(f"service:{siid:03d}:action:{aiid:03d}", "")
355
+ act_item = {
356
+ "name": act["type"],
357
+ "description": f"{act['description']} / {zh_cn}".rstrip(" / "),
358
+ "method": {
359
+ "siid": siid,
360
+ "aiid": aiid
361
+ }
362
+ }
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
+ result["actions"].append(act_item)
357
367
 
358
368
  if cache_path is not None:
359
369
  cache_path = Path(cache_path)
@@ -0,0 +1 @@
1
+ version = "3.1.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mijiaAPI
3
- Version: 3.0.5
3
+ Version: 3.1.0
4
4
  Summary: A Python API for Xiaomi Mijia
5
5
  Author-email: Do1e <i@do1e.cn>
6
6
  License-Expression: GPL-3.0-or-later
@@ -26,12 +26,6 @@ Dynamic: license-file
26
26
  [![PyPI](https://img.shields.io/badge/PyPI-mijiaAPI-blue)](https://pypi.org/project/mijiaAPI/)
27
27
  [![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-green.svg)](https://opensource.org/licenses/GPL-3.0)
28
28
 
29
- ## ⚠️ 重要提醒
30
-
31
- **v1.5.0 和 v3.0.0包含多项破坏性变更!**
32
-
33
- 如果您正在从旧版本升级,请务必查看 [CHANGELOG.md](CHANGELOG.md) 以了解详细的变更内容和迁移指南。
34
-
35
29
  常见问题见 [FAQ.md](FAQ.md)。
36
30
 
37
31
  ## 安装
@@ -1 +0,0 @@
1
- version = "3.0.5"
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
File without changes