pyimouapi 1.3.4__tar.gz → 1.4.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 (61) hide show
  1. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/PKG-INFO +5 -3
  2. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/README.md +4 -2
  3. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyimouapi/__init__.py +1 -1
  4. pyimouapi-1.4.0/pyimouapi/alarm_mode.py +22 -0
  5. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyimouapi/const.py +119 -37
  6. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyimouapi/device.py +805 -723
  7. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyimouapi/exceptions.py +2 -0
  8. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyimouapi/ha_device.py +712 -422
  9. pyimouapi-1.4.0/pyimouapi/openapi.py +290 -0
  10. pyimouapi-1.4.0/pyimouapi/pic_decode.py +220 -0
  11. pyimouapi-1.4.0/pyimouapi/push.py +187 -0
  12. pyimouapi-1.4.0/pyimouapi/py.typed +0 -0
  13. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyimouapi/select_option.py +1 -11
  14. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyimouapi.egg-info/PKG-INFO +5 -3
  15. pyimouapi-1.4.0/pyimouapi.egg-info/SOURCES.txt +57 -0
  16. pyimouapi-1.4.0/pyimouapi.egg-info/not-zip-safe +1 -0
  17. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyproject.toml +16 -1
  18. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/setup.py +3 -1
  19. pyimouapi-1.4.0/tests/test_accessory_device_id.py +73 -0
  20. pyimouapi-1.4.0/tests/test_alarm_control_panel.py +65 -0
  21. pyimouapi-1.4.0/tests/test_alarm_mode.py +33 -0
  22. pyimouapi-1.4.0/tests/test_auth_failure_propagates.py +142 -0
  23. pyimouapi-1.4.0/tests/test_bind_device.py +37 -0
  24. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/tests/test_channel_id_and_api_guards.py +1 -1
  25. pyimouapi-1.4.0/tests/test_connection_pool.py +94 -0
  26. pyimouapi-1.4.0/tests/test_device_image.py +61 -0
  27. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/tests/test_device_summaries.py +29 -0
  28. pyimouapi-1.4.0/tests/test_entity_tables_golden.py +36 -0
  29. pyimouapi-1.4.0/tests/test_feature_switches.py +88 -0
  30. pyimouapi-1.4.0/tests/test_get_devices.py +198 -0
  31. pyimouapi-1.4.0/tests/test_motion_detect_excepts.py +89 -0
  32. pyimouapi-1.4.0/tests/test_openapi_http.py +490 -0
  33. pyimouapi-1.4.0/tests/test_packaging.py +37 -0
  34. pyimouapi-1.4.0/tests/test_pic_decode.py +177 -0
  35. pyimouapi-1.4.0/tests/test_product_id_guard.py +45 -0
  36. pyimouapi-1.4.0/tests/test_push.py +205 -0
  37. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/tests/test_select_option.py +2 -26
  38. pyimouapi-1.4.0/tests/test_services_entities_concurrency.py +123 -0
  39. pyimouapi-1.4.0/tests/test_set_text_value.py +85 -0
  40. pyimouapi-1.4.0/tests/test_shared_status_reads.py +219 -0
  41. pyimouapi-1.4.0/tests/test_status_read_concurrency.py +156 -0
  42. pyimouapi-1.4.0/tests/test_switch_status_aggregation.py +110 -0
  43. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/tests/test_update_from_detail.py +84 -0
  44. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/tests/test_write_optimistic_state.py +6 -10
  45. pyimouapi-1.3.4/pyimouapi/openapi.py +0 -165
  46. pyimouapi-1.3.4/pyimouapi.egg-info/SOURCES.txt +0 -31
  47. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/LICENSE +0 -0
  48. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyimouapi/collection_point.py +0 -0
  49. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyimouapi/sensor.py +0 -0
  50. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyimouapi/siren.py +0 -0
  51. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyimouapi.egg-info/dependency_links.txt +0 -0
  52. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyimouapi.egg-info/requires.txt +0 -0
  53. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/pyimouapi.egg-info/top_level.txt +0 -0
  54. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/setup.cfg +0 -0
  55. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/tests/test_collect_property_entities.py +0 -0
  56. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/tests/test_collection_point.py +0 -0
  57. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/tests/test_event_identifier_map.py +0 -0
  58. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/tests/test_lookup_property.py +0 -0
  59. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/tests/test_message_callback.py +0 -0
  60. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/tests/test_sensor_normalize.py +0 -0
  61. {pyimouapi-1.3.4 → pyimouapi-1.4.0}/tests/test_siren.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyimouapi
3
- Version: 1.3.4
3
+ Version: 1.4.0
4
4
  Summary: A package for imou open api
5
5
  Home-page: https://github.com/Imou-OpenPlatform/Py-Imou-Open-Api
6
6
  Author: Imou-OpenPlatform
@@ -31,8 +31,10 @@ Async Python client for the **Imou Open Platform** cloud APIs. Built on **aiohtt
31
31
  |--------|------|
32
32
  | `pyimouapi.openapi` | `ImouOpenApiClient` — auth, signing, token lifecycle, HTTP calls |
33
33
  | `pyimouapi.device` | `ImouDeviceManager`, `ImouDevice`, `ImouChannel` — listing, PTZ, alarms, storage, collection points (`getCollection` / `turnCollection`), and related endpoints |
34
- | `pyimouapi.collection_point` | Parsing helpers for PaaS / IoT collection point (preset) name lists |
35
- | `pyimouapi.ha_device` | `ImouHaDeviceManager`, `ImouHaDevice`, … — aggregated “device model” helpers for automation stacks (including `select.collection_point` when the device exposes `CollectionPoint` or IoT refs `21500`/`22000`) |
34
+ | `pyimouapi.collection_point` | Parsing helpers for PaaS / IoT collection point name lists |
35
+ | `pyimouapi.push` | Open Platform event-push helpers: normalize payload fields, alarm vs status `msgType`, IoT envelope check, event-ref lookup, picture URLs (`thumbUrl` first, then `picUrlArray` / `picUrlArr` / `picUrl`) |
36
+ | `pyimouapi.pic_decode` | `LCOpenPicDecoder` — decrypts alarm pictures **you have already downloaded**, through the official LCOpenSDK native libraries (linux x86-64). Also TCM detection and encrypt-key resolution. No Open Platform call, token, or CA bundle is involved |
37
+ | `pyimouapi.ha_device` | `ImouHaDeviceManager`, `ImouHaDevice`, … — aggregated “device model” helpers for automation stacks (including `alarm_control_panel` for IoT ref `15200`, feature switches, and `select.collection_point` when the device exposes `CollectionPoint` or IoT refs `21500`/`22000`) |
36
38
  | `pyimouapi.exceptions` | `ImouException` and typed errors (connect, request, invalid credentials, …) |
37
39
 
38
40
  The top-level `pyimouapi` package re-exports common symbols. Import submodules directly when needed, for example `from pyimouapi.ha_device import ImouHaDeviceManager`.
@@ -12,8 +12,10 @@ Async Python client for the **Imou Open Platform** cloud APIs. Built on **aiohtt
12
12
  |--------|------|
13
13
  | `pyimouapi.openapi` | `ImouOpenApiClient` — auth, signing, token lifecycle, HTTP calls |
14
14
  | `pyimouapi.device` | `ImouDeviceManager`, `ImouDevice`, `ImouChannel` — listing, PTZ, alarms, storage, collection points (`getCollection` / `turnCollection`), and related endpoints |
15
- | `pyimouapi.collection_point` | Parsing helpers for PaaS / IoT collection point (preset) name lists |
16
- | `pyimouapi.ha_device` | `ImouHaDeviceManager`, `ImouHaDevice`, … — aggregated “device model” helpers for automation stacks (including `select.collection_point` when the device exposes `CollectionPoint` or IoT refs `21500`/`22000`) |
15
+ | `pyimouapi.collection_point` | Parsing helpers for PaaS / IoT collection point name lists |
16
+ | `pyimouapi.push` | Open Platform event-push helpers: normalize payload fields, alarm vs status `msgType`, IoT envelope check, event-ref lookup, picture URLs (`thumbUrl` first, then `picUrlArray` / `picUrlArr` / `picUrl`) |
17
+ | `pyimouapi.pic_decode` | `LCOpenPicDecoder` — decrypts alarm pictures **you have already downloaded**, through the official LCOpenSDK native libraries (linux x86-64). Also TCM detection and encrypt-key resolution. No Open Platform call, token, or CA bundle is involved |
18
+ | `pyimouapi.ha_device` | `ImouHaDeviceManager`, `ImouHaDevice`, … — aggregated “device model” helpers for automation stacks (including `alarm_control_panel` for IoT ref `15200`, feature switches, and `select.collection_point` when the device exposes `CollectionPoint` or IoT refs `21500`/`22000`) |
17
19
  | `pyimouapi.exceptions` | `ImouException` and typed errors (connect, request, invalid credentials, …) |
18
20
 
19
21
  The top-level `pyimouapi` package re-exports common symbols. Import submodules directly when needed, for example `from pyimouapi.ha_device import ImouHaDeviceManager`.
@@ -1,4 +1,4 @@
1
- __version__ = "1.3.4"
1
+ __version__ = "1.4.0"
2
2
 
3
3
  from .device import ImouChannel, ImouDevice, ImouDeviceManager
4
4
  from .exceptions import (
@@ -0,0 +1,22 @@
1
+ """Friendly keys for IoT alarm mode (ref 15200)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ ALARM_MODES: tuple[str, ...] = ("home", "away", "disarm")
6
+
7
+ _RAW_TO_FRIENDLY = {"0": "home", "1": "away", "2": "disarm"}
8
+ _FRIENDLY_TO_RAW = {v: k for k, v in _RAW_TO_FRIENDLY.items()}
9
+
10
+
11
+ def to_friendly(raw: object) -> str:
12
+ """Map vendor raw (int or str) to home / away / disarm."""
13
+ key = "" if raw is None else str(raw).strip()
14
+ return _RAW_TO_FRIENDLY.get(key, key)
15
+
16
+
17
+ def to_raw(mode: str) -> str:
18
+ """Map home / away / disarm to the IoT integer string."""
19
+ key = mode.strip().lower()
20
+ if key not in _FRIENDLY_TO_RAW:
21
+ raise ValueError(f"unknown alarm mode: {mode!r}")
22
+ return _FRIENDLY_TO_RAW[key]
@@ -1,3 +1,5 @@
1
+ from typing import Any
2
+
1
3
  # API Endpoints
2
4
  API_ENDPOINT_ACCESS_TOKEN = "/openapi/accessToken"
3
5
  API_ENDPOINT_LIST_DEVICE_DETAILS = "/openapi/listDeviceDetailsByPage"
@@ -10,6 +12,7 @@ API_ENDPOINT_GET_DEVICE_NIGHT_VISION_MODE = "/openapi/getNightVisionMode"
10
12
  API_ENDPOINT_SET_DEVICE_NIGHT_VISION_MODE = "/openapi/setNightVisionMode"
11
13
  API_ENDPOINT_DEVICE_STORAGE = "/openapi/deviceStorage"
12
14
  API_ENDPOINT_RESTART_DEVICE = "/openapi/restartDevice"
15
+ API_ENDPOINT_BIND_DEVICE = "/openapi/bindDevice"
13
16
  API_ENDPOINT_BIND_DEVICE_LIVE = "/openapi/bindDeviceLive"
14
17
  API_ENDPOINT_GET_DEVICE_ONLINE = "/openapi/deviceOnline"
15
18
  API_ENDPOINT_GET_DEVICE_LIVE_INFO = "/openapi/getLiveStreamInfo"
@@ -88,6 +91,7 @@ PARAM_STATUS = "status"
88
91
  PARAM_CURRENT_OPTION = "current_option"
89
92
  PARAM_MODES = "modes"
90
93
  PARAM_OPTIONS = "options"
94
+ PARAM_SUPPORTED = "supported"
91
95
  PARAM_CHANNELS = "channels"
92
96
  PARAM_USED_BYTES = "usedBytes"
93
97
  PARAM_TOTAL_BYTES = "totalBytes"
@@ -155,7 +159,7 @@ PARAM_ABILITY = "ability"
155
159
  PARAM_FUNCTION_TYPE = "function_type"
156
160
 
157
161
  # Required capacity for various switch types
158
- SWITCH_TYPE_ABILITY = {
162
+ SWITCH_TYPE_ABILITY: dict[str, list[dict[str, Any]]] = {
159
163
  "motion_detect": [
160
164
  {
161
165
  "ability": "MobileDetect",
@@ -224,17 +228,63 @@ SWITCH_TYPE_ABILITY = {
224
228
  "function_type": "smdHuman",
225
229
  },
226
230
  ],
231
+ "frame_reverse": [
232
+ {
233
+ "ability": "FrameReverse",
234
+ "default": False,
235
+ "function_type": "frameReverse",
236
+ }
237
+ ],
238
+ "wide_dynamic": [
239
+ {
240
+ "ability": "WideDynamic",
241
+ "default": False,
242
+ "function_type": "wideDynamic",
243
+ }
244
+ ],
245
+ "smart_track": [
246
+ {
247
+ "ability": "SmartTrack",
248
+ "default": False,
249
+ "function_type": "smartTrack",
250
+ }
251
+ ],
252
+ "play_sound": [
253
+ {
254
+ "ability": "PlaySound",
255
+ "default": False,
256
+ "function_type": "playSound",
257
+ }
258
+ ],
259
+ "linkage_siren": [
260
+ {
261
+ "ability": "LinkageSiren",
262
+ "default": False,
263
+ "function_type": "linkageSiren",
264
+ }
265
+ ],
266
+ "linkage_white_light": [
267
+ {
268
+ "ability": "WhiteLight",
269
+ "default": False,
270
+ "function_type": "linkageWhiteLight",
271
+ },
272
+ {
273
+ "ability": "ChnWhiteLight",
274
+ "default": False,
275
+ "function_type": "linkageWhiteLight",
276
+ },
277
+ ],
227
278
  }
228
279
 
229
- SWITCH_TYPE_REF = {
280
+ SWITCH_TYPE_REF: dict[str, list[dict[str, Any]]] = {
230
281
  "motion_detect": [
231
282
  {
232
283
  "ref": "14800",
233
284
  "default": False,
234
- },
235
- {
236
- "ref": "305000",
237
- "default": False,
285
+ "excepts": [
286
+ "FKX9UYL4",
287
+ ],
238
288
  },
239
289
  {
240
290
  "ref": "108800",
@@ -257,25 +307,13 @@ SWITCH_TYPE_REF = {
257
307
  {
258
308
  "ref": "14200",
259
309
  "default": False,
260
- },
261
- {
262
- "ref": "115300",
263
- "default": False,
264
- },
310
+ }
265
311
  ],
266
312
  "audio_encode_control": [
267
313
  {
268
314
  "ref": "13900",
269
315
  "default": False,
270
- },
271
- {
272
- "ref": "104000",
273
- "default": False,
274
- },
275
- {
276
- "ref": "103800",
277
- "default": False,
278
- },
316
+ }
279
317
  ],
280
318
  "header_detect": [
281
319
  {
@@ -311,9 +349,51 @@ SWITCH_TYPE_REF = {
311
349
  "default": False,
312
350
  }
313
351
  ],
352
+ "pet_detect": [
353
+ {
354
+ "ref": "18300",
355
+ "default": False,
356
+ }
357
+ ],
358
+ "frame_reverse": [
359
+ {
360
+ "ref": "13500",
361
+ "default": False,
362
+ }
363
+ ],
364
+ "wide_dynamic": [
365
+ {
366
+ "ref": "19400",
367
+ "default": False,
368
+ }
369
+ ],
370
+ "smart_track": [
371
+ {
372
+ "ref": "13300",
373
+ "default": False,
374
+ }
375
+ ],
376
+ "play_sound": [
377
+ {
378
+ "ref": "14000",
379
+ "default": False,
380
+ }
381
+ ],
382
+ "linkage_siren": [
383
+ {
384
+ "ref": "102000",
385
+ "default": False,
386
+ }
387
+ ],
388
+ "linkage_white_light": [
389
+ {
390
+ "ref": "17300",
391
+ "default": False,
392
+ }
393
+ ],
314
394
  }
315
395
  # Required capacity for various button types
316
- BUTTON_TYPE_ABILITY = {
396
+ BUTTON_TYPE_ABILITY: dict[str, list[str]] = {
317
397
  "restart_device": ["Reboot"],
318
398
  "siren_start": ["Siren"],
319
399
  "siren_stop": ["Siren"],
@@ -322,7 +402,7 @@ BUTTON_TYPE_ABILITY = {
322
402
  "ptz_left": ["PT", "PTZ"],
323
403
  "ptz_right": ["PT", "PTZ"],
324
404
  }
325
- BUTTON_TYPE_REF = {
405
+ BUTTON_TYPE_REF: dict[str, list[dict[str, Any]]] = {
326
406
  "restart_device": [
327
407
  {"ref": "2300"},
328
408
  {"ref": "21200"},
@@ -401,11 +481,11 @@ BUTTON_TYPE_REF = {
401
481
  ],
402
482
  }
403
483
  # Required capacity for various select types
404
- SELECT_TYPE_ABILITY = {
484
+ SELECT_TYPE_ABILITY: dict[str, list[str]] = {
405
485
  "night_vision_mode": ["NVM"],
406
486
  "collection_point": ["CollectionPoint"],
407
487
  }
408
- SELECT_TYPE_REF = {
488
+ SELECT_TYPE_REF: dict[str, list[dict[str, Any]]] = {
409
489
  "night_vision_mode": [
410
490
  {
411
491
  "ref": "17400",
@@ -432,14 +512,6 @@ SELECT_TYPE_REF = {
432
512
  "value_type": "int",
433
513
  },
434
514
  ],
435
- "mode": [
436
- {
437
- "ref": "15200",
438
- "default": "home",
439
- "options": ["home", "away", "disarm"],
440
- "value_type": "int",
441
- }
442
- ],
443
515
  "device_volume": [
444
516
  {
445
517
  "ref": "15400",
@@ -459,12 +531,20 @@ SELECT_TYPE_REF = {
459
531
  }
460
532
  ],
461
533
  }
534
+ ALARM_CONTROL_PANEL_REF: list[dict[str, Any]] = [
535
+ {
536
+ "ref": "15200",
537
+ "default": "home",
538
+ "supported": ["home", "away", "disarm"],
539
+ "value_type": "int",
540
+ }
541
+ ]
462
542
  # Required capacity for various sensor types
463
- SENSOR_TYPE_ABILITY = {
543
+ SENSOR_TYPE_ABILITY: dict[str, list[str]] = {
464
544
  "storage_used": ["LocalStorage", "LocalStorageEnable"],
465
545
  "battery": ["Electric"],
466
546
  }
467
- SENSOR_TYPE_REF = {
547
+ SENSOR_TYPE_REF: dict[str, list[dict[str, Any]]] = {
468
548
  "storage_used": [
469
549
  {
470
550
  "ref": "14600",
@@ -536,10 +616,12 @@ SENSOR_TYPE_REF = {
536
616
  ],
537
617
  }
538
618
 
539
- BINARY_SENSOR_TYPE_ABILITY = {}
540
- BINARY_SENSOR_TYPE_REF = {"door_contact_status": [{"ref": "16300", "default": False}]}
619
+ BINARY_SENSOR_TYPE_ABILITY: dict[str, list[str]] = {}
620
+ BINARY_SENSOR_TYPE_REF: dict[str, list[dict[str, Any]]] = {
621
+ "door_contact_status": [{"ref": "16300", "default": False}]
622
+ }
541
623
 
542
- TEXT_TYPE_REF = {
624
+ TEXT_TYPE_REF: dict[str, list[dict[str, Any]]] = {
543
625
  "count_down_switch": [
544
626
  {
545
627
  "ref": "28800",