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.
- {python_aidot_cameras-0.11.14/python_aidot_cameras.egg-info → python_aidot_cameras-0.12.0}/PKG-INFO +14 -7
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/README.md +12 -6
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/__init__.py +30 -17
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/client.py +1 -1
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/lan_control.py +1 -1
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/playback.py +1 -1
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/protocol.py +1 -1
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/webrtc_open.py +7 -7
- python_aidot_cameras-0.12.0/aidot_cameras/client.py +701 -0
- python_aidot_cameras-0.12.0/aidot_cameras/const.py +59 -0
- python_aidot_cameras-0.12.0/aidot_cameras/crypto.py +43 -0
- python_aidot_cameras-0.12.0/aidot_cameras/device_client.py +255 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/discover.py +143 -63
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/exceptions.py +17 -37
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/pyproject.toml +12 -8
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0/python_aidot_cameras.egg-info}/PKG-INFO +14 -7
- python_aidot_cameras-0.12.0/python_aidot_cameras.egg-info/SOURCES.txt +132 -0
- python_aidot_cameras-0.12.0/python_aidot_cameras.egg-info/entry_points.txt +2 -0
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/python_aidot_cameras.egg-info/requires.txt +1 -0
- python_aidot_cameras-0.12.0/python_aidot_cameras.egg-info/top_level.txt +1 -0
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_aioice_compat.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_alarm_event.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_backoff.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_deferred_hardening.py +4 -4
- python_aidot_cameras-0.12.0/tests/test_device_login_guard.py +81 -0
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_device_user_info_cache.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_dtls_not_ready_burst.py +4 -4
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_dtls_pinning.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_dtls_serve_decode_skip.py +2 -2
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_dtls_serve_open_timeout.py +3 -3
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_dtls_skip_signaling_wait.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_dtls_slow_probe.py +3 -3
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_egress_guard.py +4 -4
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_go2rtc.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_go2rtc_cli.py +2 -2
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_h264_decode_rate_limit.py +5 -5
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_highport_nomination.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_ice_config_cache.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_keepalive_renew.py +4 -4
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_keyframe_prompter.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_lan_control.py +2 -2
- python_aidot_cameras-0.12.0/tests/test_light_active_color_mode.py +180 -0
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_live_stream_param.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_logging_caps.py +9 -9
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_motion_poll.py +2 -2
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_mqtt_session_reconnect.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_narrow_pc_ice.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_no_undefined_names.py +4 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_offline_keepalive_pause.py +3 -3
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_open_fail_logger.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_open_gate_delay.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_persistent_mqtt.py +2 -2
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_persistent_mqtt_robustness.py +3 -3
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_playback_tls.py +3 -3
- python_aidot_cameras-0.12.0/tests/test_post_merge_hardening.py +216 -0
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_retry_policy.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_adaptive.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_bridge_break_gate.py +2 -2
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_echo_wait_timeout.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_fast_liveplay.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_ffmpeg_stderr_log.py +5 -5
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_idle_release.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_open_cleanup.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_serve_audio.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_serve_cmd.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_sprop.py +3 -3
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_talk.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_teardown_exit_log.py +3 -3
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_sdes_watchdog.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_security_hardening.py +3 -3
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_serializable_login_info.py +2 -2
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_serve_relay.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_session_stats.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_speak.py +3 -3
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_stream_cap.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_stream_drain_ownership.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_stream_idle.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_stream_teardown.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_talk.py +1 -1
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_terminal_ack.py +2 -2
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_token_file_robustness.py +1 -1
- python_aidot_cameras-0.12.0/tests/test_token_refresh.py +145 -0
- python_aidot_cameras-0.12.0/tests/test_upstream_compat.py +248 -0
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/tests/test_wait_or_event.py +1 -1
- python_aidot_cameras-0.11.14/aidot/aes_utils.py +0 -70
- python_aidot_cameras-0.11.14/aidot/client.py +0 -609
- python_aidot_cameras-0.11.14/aidot/const.py +0 -260
- python_aidot_cameras-0.11.14/aidot/device_client.py +0 -550
- python_aidot_cameras-0.11.14/aidot/login_const.py +0 -16
- python_aidot_cameras-0.11.14/aidot/models/__init__.py +0 -37
- python_aidot_cameras-0.11.14/aidot/models/device_client_model.py +0 -210
- python_aidot_cameras-0.11.14/aidot/models/device_model.py +0 -83
- python_aidot_cameras-0.11.14/aidot/models/discover_model.py +0 -102
- python_aidot_cameras-0.11.14/python_aidot_cameras.egg-info/SOURCES.txt +0 -136
- python_aidot_cameras-0.11.14/python_aidot_cameras.egg-info/entry_points.txt +0 -2
- python_aidot_cameras-0.11.14/python_aidot_cameras.egg-info/top_level.txt +0 -1
- python_aidot_cameras-0.11.14/tests/test_device_login_guard.py +0 -95
- python_aidot_cameras-0.11.14/tests/test_light_active_color_mode.py +0 -58
- python_aidot_cameras-0.11.14/tests/test_post_merge_hardening.py +0 -189
- python_aidot_cameras-0.11.14/tests/test_token_refresh.py +0 -79
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/LICENSE +0 -0
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/MANIFEST.in +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/__main__.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/__init__.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/__init__.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/clock.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/__init__.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/base.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/g711.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/g722.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/h264.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/opus.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/codecs/vpx.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/contrib/__init__.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/contrib/media.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/contrib/signaling.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/events.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/exceptions.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/jitterbuffer.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/mediastreams.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rate.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcconfiguration.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcdatachannel.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcdtlstransport.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcicetransport.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcpeerconnection.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcrtpparameters.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcrtpreceiver.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcrtpsender.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcrtptransceiver.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcsctptransport.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtcsessiondescription.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/rtp.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/sdp.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/stats.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/_vendor/aiortc/utils.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/__init__.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/constants.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/controls.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/go2rtc.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/models.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/sdes.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/sdes_open.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/tutk.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/webrtc.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/credentials.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/g711.py +0 -0
- {python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/py.typed +0 -0
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
- {python_aidot_cameras-0.11.14 → python_aidot_cameras-0.12.0}/setup.cfg +0 -0
{python_aidot_cameras-0.11.14/python_aidot_cameras.egg-info → python_aidot_cameras-0.12.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aidot-cameras
|
|
3
|
-
Version: 0.
|
|
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
|
|
40
|
-
[`python-aidot`](https://github.com/AiDot-Development-Team/python-AiDot)
|
|
41
|
-
|
|
42
|
-
|
|
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 [`
|
|
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 (`
|
|
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
|
|
10
|
-
[`python-aidot`](https://github.com/AiDot-Development-Team/python-AiDot)
|
|
11
|
-
|
|
12
|
-
|
|
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 [`
|
|
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 (`
|
|
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
|
{python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/__init__.py
RENAMED
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
"""AiDot camera
|
|
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
|
|
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
|
-
# ``
|
|
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 ``
|
|
33
|
-
# cannot suppress an INFO-level flood, so ``aioice.ice`` and
|
|
34
|
-
# are capped at WARNING instead; aioice emits nothing at
|
|
35
|
-
# no real warning is lost. A user who wants the aioice ICE
|
|
36
|
-
# (e.g. to debug connectivity issues) can set that logger's
|
|
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
|
-
"
|
|
40
|
-
"
|
|
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
|
-
# (
|
|
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 = "
|
|
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
|
-
"
|
|
141
|
+
"CameraClient",
|
|
142
|
+
"CameraDeviceClient",
|
|
143
|
+
"CameraDiscover",
|
|
144
|
+
"DeviceInformation",
|
|
145
|
+
"DeviceStatusData",
|
|
133
146
|
"Discover",
|
|
134
147
|
"HTTPError",
|
|
135
148
|
"InvalidHost",
|
{python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/client.py
RENAMED
|
@@ -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 ..
|
|
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,
|
{python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/playback.py
RENAMED
|
@@ -16,7 +16,7 @@ import struct
|
|
|
16
16
|
import time
|
|
17
17
|
from typing import Callable, List, Optional
|
|
18
18
|
|
|
19
|
-
from ..
|
|
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,
|
{python_aidot_cameras-0.11.14/aidot → python_aidot_cameras-0.12.0/aidot_cameras}/camera/protocol.py
RENAMED
|
@@ -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
|
|
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
|
|
305
|
-
from
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2921
|
+
from aidot_cameras._vendor.aiortc.rtcdtlstransport import (
|
|
2922
2922
|
RTCDtlsFingerprint as _NPFp,
|
|
2923
2923
|
certificate_digest as _np_cert_fp,
|
|
2924
2924
|
)
|