python-aidot-cameras 0.11.14__tar.gz → 0.12.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 (150) hide show
  1. {python_aidot_cameras-0.11.14/python_aidot_cameras.egg-info → python_aidot_cameras-0.12.0}/PKG-INFO +14 -7
  2. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/README.md +12 -6
  3. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/__init__.py +30 -17
  4. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/client.py +1 -1
  5. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/lan_control.py +1 -1
  6. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/playback.py +1 -1
  7. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/protocol.py +1 -1
  8. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/webrtc_open.py +7 -7
  9. python_aidot_cameras-0.12.0/aidot_cameras/client.py +701 -0
  10. python_aidot_cameras-0.12.0/aidot_cameras/const.py +59 -0
  11. python_aidot_cameras-0.12.0/aidot_cameras/crypto.py +43 -0
  12. python_aidot_cameras-0.12.0/aidot_cameras/device_client.py +255 -0
  13. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/discover.py +143 -63
  14. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/exceptions.py +17 -37
  15. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/pyproject.toml +12 -8
  16. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0/python_aidot_cameras.egg-info}/PKG-INFO +14 -7
  17. python_aidot_cameras-0.12.0/python_aidot_cameras.egg-info/SOURCES.txt +132 -0
  18. python_aidot_cameras-0.12.0/python_aidot_cameras.egg-info/entry_points.txt +2 -0
  19. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/python_aidot_cameras.egg-info/requires.txt +1 -0
  20. python_aidot_cameras-0.12.0/python_aidot_cameras.egg-info/top_level.txt +1 -0
  21. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_aioice_compat.py +1 -1
  22. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_alarm_event.py +1 -1
  23. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_backoff.py +1 -1
  24. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_deferred_hardening.py +4 -4
  25. python_aidot_cameras-0.12.0/tests/test_device_login_guard.py +81 -0
  26. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_device_user_info_cache.py +1 -1
  27. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_dtls_not_ready_burst.py +4 -4
  28. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_dtls_pinning.py +1 -1
  29. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_dtls_serve_decode_skip.py +2 -2
  30. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_dtls_serve_open_timeout.py +3 -3
  31. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_dtls_skip_signaling_wait.py +1 -1
  32. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_dtls_slow_probe.py +3 -3
  33. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_egress_guard.py +4 -4
  34. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_go2rtc.py +1 -1
  35. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_go2rtc_cli.py +2 -2
  36. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_h264_decode_rate_limit.py +5 -5
  37. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_highport_nomination.py +1 -1
  38. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_ice_config_cache.py +1 -1
  39. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_keepalive_renew.py +4 -4
  40. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_keyframe_prompter.py +1 -1
  41. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_lan_control.py +2 -2
  42. python_aidot_cameras-0.12.0/tests/test_light_active_color_mode.py +180 -0
  43. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_live_stream_param.py +1 -1
  44. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_logging_caps.py +9 -9
  45. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_motion_poll.py +2 -2
  46. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_mqtt_session_reconnect.py +1 -1
  47. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_narrow_pc_ice.py +1 -1
  48. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_no_undefined_names.py +4 -1
  49. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_offline_keepalive_pause.py +3 -3
  50. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_open_fail_logger.py +1 -1
  51. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_open_gate_delay.py +1 -1
  52. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_persistent_mqtt.py +2 -2
  53. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_persistent_mqtt_robustness.py +3 -3
  54. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_playback_tls.py +3 -3
  55. python_aidot_cameras-0.12.0/tests/test_post_merge_hardening.py +216 -0
  56. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_retry_policy.py +1 -1
  57. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_adaptive.py +1 -1
  58. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_bridge_break_gate.py +2 -2
  59. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_echo_wait_timeout.py +1 -1
  60. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_fast_liveplay.py +1 -1
  61. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_ffmpeg_stderr_log.py +5 -5
  62. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_idle_release.py +1 -1
  63. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_open_cleanup.py +1 -1
  64. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_serve_audio.py +1 -1
  65. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_serve_cmd.py +1 -1
  66. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_sprop.py +3 -3
  67. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_talk.py +1 -1
  68. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_teardown_exit_log.py +3 -3
  69. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_watchdog.py +1 -1
  70. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_security_hardening.py +3 -3
  71. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_serializable_login_info.py +2 -2
  72. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_serve_relay.py +1 -1
  73. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_session_stats.py +1 -1
  74. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_speak.py +3 -3
  75. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_stream_cap.py +1 -1
  76. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_stream_drain_ownership.py +1 -1
  77. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_stream_idle.py +1 -1
  78. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_stream_teardown.py +1 -1
  79. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_talk.py +1 -1
  80. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_terminal_ack.py +2 -2
  81. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_token_file_robustness.py +1 -1
  82. python_aidot_cameras-0.12.0/tests/test_token_refresh.py +145 -0
  83. python_aidot_cameras-0.12.0/tests/test_upstream_compat.py +248 -0
  84. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_wait_or_event.py +1 -1
  85. python_aidot_cameras-0.11.14/aidot/aes_utils.py +0 -70
  86. python_aidot_cameras-0.11.14/aidot/client.py +0 -609
  87. python_aidot_cameras-0.11.14/aidot/const.py +0 -260
  88. python_aidot_cameras-0.11.14/aidot/device_client.py +0 -550
  89. python_aidot_cameras-0.11.14/aidot/login_const.py +0 -16
  90. python_aidot_cameras-0.11.14/aidot/models/__init__.py +0 -37
  91. python_aidot_cameras-0.11.14/aidot/models/device_client_model.py +0 -210
  92. python_aidot_cameras-0.11.14/aidot/models/device_model.py +0 -83
  93. python_aidot_cameras-0.11.14/aidot/models/discover_model.py +0 -102
  94. python_aidot_cameras-0.11.14/python_aidot_cameras.egg-info/SOURCES.txt +0 -136
  95. python_aidot_cameras-0.11.14/python_aidot_cameras.egg-info/entry_points.txt +0 -2
  96. python_aidot_cameras-0.11.14/python_aidot_cameras.egg-info/top_level.txt +0 -1
  97. python_aidot_cameras-0.11.14/tests/test_device_login_guard.py +0 -95
  98. python_aidot_cameras-0.11.14/tests/test_light_active_color_mode.py +0 -58
  99. python_aidot_cameras-0.11.14/tests/test_post_merge_hardening.py +0 -189
  100. python_aidot_cameras-0.11.14/tests/test_token_refresh.py +0 -79
  101. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/LICENSE +0 -0
  102. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/MANIFEST.in +0 -0
  103. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/__main__.py +0 -0
  104. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/__init__.py +0 -0
  105. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/__init__.py +0 -0
  106. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/clock.py +0 -0
  107. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/__init__.py +0 -0
  108. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/base.py +0 -0
  109. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/g711.py +0 -0
  110. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/g722.py +0 -0
  111. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/h264.py +0 -0
  112. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/opus.py +0 -0
  113. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/vpx.py +0 -0
  114. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/contrib/__init__.py +0 -0
  115. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/contrib/media.py +0 -0
  116. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/contrib/signaling.py +0 -0
  117. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/events.py +0 -0
  118. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/exceptions.py +0 -0
  119. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/jitterbuffer.py +0 -0
  120. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/mediastreams.py +0 -0
  121. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rate.py +0 -0
  122. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcconfiguration.py +0 -0
  123. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcdatachannel.py +0 -0
  124. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcdtlstransport.py +0 -0
  125. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcicetransport.py +0 -0
  126. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcpeerconnection.py +0 -0
  127. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcrtpparameters.py +0 -0
  128. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcrtpreceiver.py +0 -0
  129. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcrtpsender.py +0 -0
  130. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcrtptransceiver.py +0 -0
  131. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcsctptransport.py +0 -0
  132. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcsessiondescription.py +0 -0
  133. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtp.py +0 -0
  134. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/sdp.py +0 -0
  135. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/stats.py +0 -0
  136. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/utils.py +0 -0
  137. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/__init__.py +0 -0
  138. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/constants.py +0 -0
  139. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/controls.py +0 -0
  140. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/go2rtc.py +0 -0
  141. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/models.py +0 -0
  142. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/sdes.py +0 -0
  143. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/sdes_open.py +0 -0
  144. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/tutk.py +0 -0
  145. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/webrtc.py +0 -0
  146. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/credentials.py +0 -0
  147. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/g711.py +0 -0
  148. {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/py.typed +0 -0
  149. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
  150. {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-aidot-cameras
3
- Version: 0.11.14
3
+ Version: 0.12.0
4
4
  Summary: Control AiDot/Leedarson WiFi lights and cameras (WebRTC streaming, two-way audio, PTZ, controls)
5
5
  Author-email: cbrightly <chris.brightly@gmail.com>
6
6
  License-Expression: MIT
@@ -11,6 +11,7 @@ Classifier: Operating System :: OS Independent
11
11
  Requires-Python: >=3.11
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
+ Requires-Dist: python-aidot==0.3.55
14
15
  Requires-Dist: aiohttp>=3.9
15
16
  Requires-Dist: paho-mqtt>=1.6.1
16
17
  Requires-Dist: cryptography>=42.0
@@ -36,10 +37,16 @@ Dynamic: license-file
36
37
 
37
38
  Control AIDOT WiFi lights **and cameras** from Python.
38
39
 
39
- This is a camera-capable fork of the upstream lights-only
40
- [`python-aidot`](https://github.com/AiDot-Development-Team/python-AiDot). It adds
41
- live WebRTC video streaming (DTLS and SDES-SRTP paths), snapshots, PTZ, camera
42
- controls, cloud recordings/thumbnails, and two-way (push-to-talk) audio.
40
+ This **extends** the upstream lights-only
41
+ [`python-aidot`](https://github.com/AiDot-Development-Team/python-AiDot), which it
42
+ installs as a dependency rather than forking. It adds live WebRTC video streaming
43
+ (DTLS and SDES-SRTP paths), snapshots, PTZ, camera controls, cloud
44
+ recordings/thumbnails, and two-way (push-to-talk) audio.
45
+
46
+ Upstream owns the `aidot` import name and handles non-camera devices (lights,
47
+ plugs, switches) with none of this package's code in the path; everything here
48
+ lives under `aidot_cameras`. Taking a new upstream release is a dependency bump
49
+ plus a test run - see [`docs/UPSTREAM.md`](docs/UPSTREAM.md).
43
50
 
44
51
  This repository is the **library** (distribution name `python-aidot-cameras`).
45
52
  The Home Assistant custom component (`custom_components/aidot/`) lives in the
@@ -142,7 +149,7 @@ The library reads the following environment variables.
142
149
  ### Credentials
143
150
 
144
151
  Used by the credential helper (`aidot.credentials`); they take priority over any
145
- stored credentials file. See [`aidot/credentials.py`](aidot/credentials.py).
152
+ stored credentials file. See [`aidot_cameras/credentials.py`](aidot_cameras/credentials.py).
146
153
 
147
154
  | Variable | Purpose | Default |
148
155
  | --- | --- | --- |
@@ -152,7 +159,7 @@ stored credentials file. See [`aidot/credentials.py`](aidot/credentials.py).
152
159
 
153
160
  ### Camera streaming / tuning
154
161
 
155
- The most useful knobs read by the camera client (`aidot.camera.client`). Defaults
162
+ The most useful knobs read by the camera client (`aidot_cameras.camera.client`). Defaults
156
163
  are chosen to work out of the box; override only when tuning. Finer-grained
157
164
  internal knobs (audio normalization, keyframe/PLI cadence, retry timing, SDES
158
165
  audio, idle release, the sprop cache path) are documented in
@@ -6,10 +6,16 @@
6
6
 
7
7
  Control AIDOT WiFi lights **and cameras** from Python.
8
8
 
9
- This is a camera-capable fork of the upstream lights-only
10
- [`python-aidot`](https://github.com/AiDot-Development-Team/python-AiDot). It adds
11
- live WebRTC video streaming (DTLS and SDES-SRTP paths), snapshots, PTZ, camera
12
- controls, cloud recordings/thumbnails, and two-way (push-to-talk) audio.
9
+ This **extends** the upstream lights-only
10
+ [`python-aidot`](https://github.com/AiDot-Development-Team/python-AiDot), which it
11
+ installs as a dependency rather than forking. It adds live WebRTC video streaming
12
+ (DTLS and SDES-SRTP paths), snapshots, PTZ, camera controls, cloud
13
+ recordings/thumbnails, and two-way (push-to-talk) audio.
14
+
15
+ Upstream owns the `aidot` import name and handles non-camera devices (lights,
16
+ plugs, switches) with none of this package's code in the path; everything here
17
+ lives under `aidot_cameras`. Taking a new upstream release is a dependency bump
18
+ plus a test run - see [`docs/UPSTREAM.md`](docs/UPSTREAM.md).
13
19
 
14
20
  This repository is the **library** (distribution name `python-aidot-cameras`).
15
21
  The Home Assistant custom component (`custom_components/aidot/`) lives in the
@@ -112,7 +118,7 @@ The library reads the following environment variables.
112
118
  ### Credentials
113
119
 
114
120
  Used by the credential helper (`aidot.credentials`); they take priority over any
115
- stored credentials file. See [`aidot/credentials.py`](aidot/credentials.py).
121
+ stored credentials file. See [`aidot_cameras/credentials.py`](aidot_cameras/credentials.py).
116
122
 
117
123
  | Variable | Purpose | Default |
118
124
  | --- | --- | --- |
@@ -122,7 +128,7 @@ stored credentials file. See [`aidot/credentials.py`](aidot/credentials.py).
122
128
 
123
129
  ### Camera streaming / tuning
124
130
 
125
- The most useful knobs read by the camera client (`aidot.camera.client`). Defaults
131
+ The most useful knobs read by the camera client (`aidot_cameras.camera.client`). Defaults
126
132
  are chosen to work out of the box; override only when tuning. Finer-grained
127
133
  internal knobs (audio normalization, keyframe/PLI cadence, retry timing, SDES
128
134
  audio, idle release, the sprop cache path) are documented in
@@ -1,15 +1,23 @@
1
- """AiDot camera and device library."""
1
+ """AiDot camera library.
2
+
3
+ This package extends the upstream ``python-aidot`` library rather than forking
4
+ it: upstream owns the ``aidot`` import name and handles non-camera devices by
5
+ itself, while everything here adds the camera surface (streaming, snapshots,
6
+ recordings, motion) on top of it. See docs/UPSTREAM.md for how to take a new
7
+ upstream release.
8
+ """
2
9
 
3
10
  import logging as _logging
4
11
  import time as _time
5
12
 
6
- from .client import AidotClient
7
- from .device_client import DeviceClient
8
- from .discover import Discover
13
+ from .client import AidotClient, CameraClient
14
+ from .device_client import CameraDeviceClient, DeviceInformation, DeviceStatusData
15
+ from .discover import CameraDiscover, Discover
9
16
  from .exceptions import (
10
17
  AidotAuthFailed,
11
18
  AidotAuthTokenExpired,
12
19
  AidotCameraBusy,
20
+ AidotCameraNotReady,
13
21
  AidotError,
14
22
  AidotNotLogin,
15
23
  AidotOSError,
@@ -20,8 +28,8 @@ from .exceptions import (
20
28
  )
21
29
 
22
30
  # Cap the noisy external/vendored loggers so enabling DEBUG on the parent
23
- # ``aidot`` logger to diagnose the integration does not unleash a flood that,
24
- # on a microSD Home Assistant host, can starve the recorder with log I/O.
31
+ # ``aidot_cameras`` logger to diagnose the integration does not unleash a flood
32
+ # that, on a microSD Home Assistant host, can starve the recorder with log I/O.
25
33
  #
26
34
  # The vendored aiortc RTP receiver/sender log every media packet at DEBUG, so
27
35
  # capping them at INFO removes that flood while leaving the diagnostically
@@ -29,15 +37,15 @@ from .exceptions import (
29
37
  #
30
38
  # The external ``aioice`` package's flood is different: it logs ICE
31
39
  # connectivity-check state transitions at INFO, not DEBUG (aioice is a real
32
- # dependency, not vendored, so it is not under ``aidot._vendor``). An INFO cap
33
- # cannot suppress an INFO-level flood, so ``aioice.ice`` and ``aioice.turn``
34
- # are capped at WARNING instead; aioice emits nothing at WARNING or above, so
35
- # no real warning is lost. A user who wants the aioice ICE INFO logging back
36
- # (e.g. to debug connectivity issues) can set that logger's level explicitly -
37
- # the NOTSET guard below respects it.
40
+ # dependency, not vendored, so it is not under ``aidot_cameras._vendor``). An
41
+ # INFO cap cannot suppress an INFO-level flood, so ``aioice.ice`` and
42
+ # ``aioice.turn`` are capped at WARNING instead; aioice emits nothing at
43
+ # WARNING or above, so no real warning is lost. A user who wants the aioice ICE
44
+ # INFO logging back (e.g. to debug connectivity issues) can set that logger's
45
+ # level explicitly - the NOTSET guard below respects it.
38
46
  _EXTERNAL_LOGGER_CAPS = {
39
- "aidot._vendor.aiortc.rtcrtpreceiver": _logging.INFO,
40
- "aidot._vendor.aiortc.rtcrtpsender": _logging.INFO,
47
+ "aidot_cameras._vendor.aiortc.rtcrtpreceiver": _logging.INFO,
48
+ "aidot_cameras._vendor.aiortc.rtcrtpsender": _logging.INFO,
41
49
  "aioice.ice": _logging.WARNING,
42
50
  "aioice.turn": _logging.WARNING,
43
51
  }
@@ -58,7 +66,7 @@ def _cap_external_loggers() -> None:
58
66
  _cap_external_loggers()
59
67
 
60
68
  # The vendored H.264 decoder logs a WARNING per corrupt/undecodable frame
61
- # (aidot/_vendor/aiortc/codecs/h264.py:118). A degrading link can therefore
69
+ # (aidot_cameras/_vendor/aiortc/codecs/h264.py). A degrading link can therefore
62
70
  # log hundreds of identical lines in a few minutes; a live evaluation saw 172
63
71
  # in 11 minutes. A level cap cannot help here since the message is already at
64
72
  # WARNING, and the message is a corruption canary for a degrading link, so it
@@ -67,7 +75,7 @@ _cap_external_loggers()
67
75
  # WARNINGs within a window, and lets the first WARNING after the window
68
76
  # elapses through carrying the suppressed count, so the canary stays visible
69
77
  # at a low rate instead of flooding.
70
- _H264_DECODE_LOGGER_NAME = "aidot._vendor.aiortc.codecs.h264"
78
+ _H264_DECODE_LOGGER_NAME = "aidot_cameras._vendor.aiortc.codecs.h264"
71
79
  _H264_DECODE_RATE_LIMIT_WINDOW_SECONDS = 30.0
72
80
 
73
81
 
@@ -124,12 +132,17 @@ __all__ = [
124
132
  "AidotAuthFailed",
125
133
  "AidotAuthTokenExpired",
126
134
  "AidotCameraBusy",
135
+ "AidotCameraNotReady",
127
136
  "AidotClient",
128
137
  "AidotError",
129
138
  "AidotNotLogin",
130
139
  "AidotOSError",
131
140
  "AidotUserOrPassIncorrect",
132
- "DeviceClient",
141
+ "CameraClient",
142
+ "CameraDeviceClient",
143
+ "CameraDiscover",
144
+ "DeviceInformation",
145
+ "DeviceStatusData",
133
146
  "Discover",
134
147
  "HTTPError",
135
148
  "InvalidHost",
@@ -9,7 +9,7 @@ import asyncio
9
9
  from typing import Any, Callable, List, Optional
10
10
 
11
11
  from ..exceptions import AidotCameraBusy, AidotCameraNotReady
12
- from ..login_const import APP_ID as _AIDOT_APP_ID
12
+ from ..const import APP_ID as _AIDOT_APP_ID
13
13
  from ..const import (
14
14
  LOGIN_INFO_PERSISTENT_MQTT_KEY,
15
15
  LOGIN_INFO_PERSISTENT_MQTT_LOCK_KEY,
@@ -32,7 +32,7 @@ import time
32
32
  from datetime import datetime
33
33
  from typing import Any, Optional
34
34
 
35
- from ..aes_utils import aes_encrypt, aes_decrypt
35
+ from ..crypto import aes_encrypt, aes_decrypt
36
36
 
37
37
  _LOGGER = logging.getLogger(__name__)
38
38
 
@@ -16,7 +16,7 @@ import struct
16
16
  import time
17
17
  from typing import Callable, List, Optional
18
18
 
19
- from ..aes_utils import aes_ecb_decrypt_str_key, aes_ecb_encrypt_str_key
19
+ from ..crypto import aes_ecb_decrypt_str_key, aes_ecb_encrypt_str_key
20
20
  from .constants import (
21
21
  _CMD_HB_REQ, _CMD_HB_RES, _CMD_LOGIN_REQ, _CMD_LOGIN_RES,
22
22
  _CMD_PARAM, _CMD_STREAM_REQ, _CMD_STREAM_RES, _CMD_SUBCMD,
@@ -352,7 +352,7 @@ def _make_talk_audio_track(pcm_provider: Callable[[], "Optional[bytes]"]):
352
352
  try:
353
353
  import fractions
354
354
  import av
355
- from aidot._vendor.aiortc.mediastreams import MediaStreamTrack
355
+ from aidot_cameras._vendor.aiortc.mediastreams import MediaStreamTrack
356
356
  except ImportError:
357
357
  return None
358
358
 
@@ -301,8 +301,8 @@ class _WebRTCOpenMixin:
301
301
 
302
302
  if not use_sdes:
303
303
  try:
304
- from aidot._vendor.aiortc import RTCPeerConnection, RTCSessionDescription
305
- from aidot._vendor.aiortc.sdp import candidate_from_sdp
304
+ from aidot_cameras._vendor.aiortc import RTCPeerConnection, RTCSessionDescription
305
+ from aidot_cameras._vendor.aiortc.sdp import candidate_from_sdp
306
306
  except ImportError:
307
307
  raise ImportError(
308
308
  "aiortc is required for WebRTC streaming. "
@@ -327,7 +327,7 @@ class _WebRTCOpenMixin:
327
327
  # that negotiate DTLS 1.2 still get DTLS 1.2; this only widens
328
328
  # the floor.
329
329
  try:
330
- from aidot._vendor.aiortc.rtcdtlstransport import RTCCertificate as _AidotRTCCert
330
+ from aidot_cameras._vendor.aiortc.rtcdtlstransport import RTCCertificate as _AidotRTCCert
331
331
  if not getattr(_AidotRTCCert, "_aidot_dtls10_patched", False):
332
332
  _orig_create_ctx = _AidotRTCCert._create_ssl_context
333
333
  _DTLS1_VERSION = 0xFEFF # not exposed in pyOpenSSL; raw OpenSSL constant
@@ -1289,7 +1289,7 @@ class _WebRTCOpenMixin:
1289
1289
  # aioice.turn at INFO anyway, so forcing DEBUG was both self-defeating and
1290
1290
  # noisy. To debug ICE, set the aioice logger level explicitly (that
1291
1291
  # overrides the NOTSET-guarded cap).
1292
- from aidot._vendor.aiortc import RTCConfiguration, RTCIceServer
1292
+ from aidot_cameras._vendor.aiortc import RTCConfiguration, RTCIceServer
1293
1293
 
1294
1294
  def _sanitize_ice_uris(uris):
1295
1295
  """Remove ?transport= from stun: URIs - invalid per RFC 7064."""
@@ -1888,7 +1888,7 @@ class _WebRTCOpenMixin:
1888
1888
  recorder = None
1889
1889
  if output_path:
1890
1890
  try:
1891
- from aidot._vendor.aiortc.contrib.media import MediaRecorder
1891
+ from aidot_cameras._vendor.aiortc.contrib.media import MediaRecorder
1892
1892
  recorder = MediaRecorder(output_path)
1893
1893
 
1894
1894
  _video_recorded = [False]
@@ -2392,7 +2392,7 @@ class _WebRTCOpenMixin:
2392
2392
  # ICE connects), but does NOT require setRemoteDescription first.
2393
2393
  import types as _types
2394
2394
  try:
2395
- from aidot._vendor.aiortc.rtcdtlstransport import (
2395
+ from aidot_cameras._vendor.aiortc.rtcdtlstransport import (
2396
2396
  RTCDtlsFingerprint as _RRFp,
2397
2397
  certificate_digest as _rr_cert_fp,
2398
2398
  )
@@ -2918,7 +2918,7 @@ class _WebRTCOpenMixin:
2918
2918
  if _fp_subs or _np_pinned_fp:
2919
2919
  import types as _np_types
2920
2920
  try:
2921
- from aidot._vendor.aiortc.rtcdtlstransport import (
2921
+ from aidot_cameras._vendor.aiortc.rtcdtlstransport import (
2922
2922
  RTCDtlsFingerprint as _NPFp,
2923
2923
  certificate_digest as _np_cert_fp,
2924
2924
  )