python-aidot-cameras 0.7.8__tar.gz → 0.7.10__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 (48) hide show
  1. python_aidot_cameras-0.7.10/MANIFEST.in +1 -0
  2. python_aidot_cameras-0.7.10/PKG-INFO +138 -0
  3. python_aidot_cameras-0.7.10/README.md +111 -0
  4. python_aidot_cameras-0.7.10/pyproject.toml +77 -0
  5. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/aes_utils.py +2 -2
  6. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/camera/__init__.py +1 -1
  7. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/camera/client.py +249 -179
  8. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/camera/lan_control.py +5 -5
  9. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/client.py +15 -3
  10. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/const.py +1 -1
  11. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/credentials.py +9 -1
  12. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/device_client.py +50 -21
  13. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/discover.py +56 -27
  14. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/models/device_client_model.py +2 -2
  15. python_aidot_cameras-0.7.10/src/aidot/py.typed +0 -0
  16. python_aidot_cameras-0.7.10/src/python_aidot_cameras.egg-info/PKG-INFO +138 -0
  17. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/python_aidot_cameras.egg-info/SOURCES.txt +2 -0
  18. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_post_merge_hardening.py +1 -2
  19. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_stream_cap.py +1 -1
  20. python_aidot_cameras-0.7.8/PKG-INFO +0 -70
  21. python_aidot_cameras-0.7.8/README.md +0 -43
  22. python_aidot_cameras-0.7.8/pyproject.toml +0 -41
  23. python_aidot_cameras-0.7.8/src/python_aidot_cameras.egg-info/PKG-INFO +0 -70
  24. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/LICENSE +0 -0
  25. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/setup.cfg +0 -0
  26. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/__init__.py +5 -5
  27. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/exceptions.py +0 -0
  28. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/g711.py +0 -0
  29. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/login_const.py +0 -0
  30. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/models/__init__.py +6 -6
  31. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/models/device_model.py +0 -0
  32. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/aidot/models/discover_model.py +0 -0
  33. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
  34. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/python_aidot_cameras.egg-info/requires.txt +0 -0
  35. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/src/python_aidot_cameras.egg-info/top_level.txt +0 -0
  36. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_alarm_event.py +0 -0
  37. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_highport_nomination.py +0 -0
  38. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_lan_control.py +0 -0
  39. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_motion_poll.py +0 -0
  40. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_no_undefined_names.py +0 -0
  41. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_sdes_idle_release.py +0 -0
  42. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_sdes_sprop.py +0 -0
  43. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_sdes_talk.py +0 -0
  44. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_sdes_watchdog.py +0 -0
  45. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_speak.py +0 -0
  46. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_talk.py +0 -0
  47. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_terminal_ack.py +0 -0
  48. {python_aidot_cameras-0.7.8 → python_aidot_cameras-0.7.10}/tests/test_token_refresh.py +0 -0
@@ -0,0 +1 @@
1
+ include src/aidot/py.typed
@@ -0,0 +1,138 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-aidot-cameras
3
+ Version: 0.7.10
4
+ Summary: Control AiDot/Leedarson WiFi lights and cameras (WebRTC streaming, two-way audio, PTZ, controls)
5
+ Author-email: cbrightly <chris.brightly@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/cbrightly/python-aidot-cameras
8
+ Project-URL: Issue Tracker, https://github.com/cbrightly/python-aidot-cameras/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.11
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: aiohttp
15
+ Requires-Dist: paho-mqtt>=2.0
16
+ Requires-Dist: cryptography
17
+ Requires-Dist: pycryptodome
18
+ Requires-Dist: dacite
19
+ Provides-Extra: webrtc
20
+ Requires-Dist: aiortc>=1.9.0; extra == "webrtc"
21
+ Requires-Dist: av; extra == "webrtc"
22
+ Requires-Dist: pylibsrtp; extra == "webrtc"
23
+ Requires-Dist: pyopenssl; extra == "webrtc"
24
+ Requires-Dist: numpy; extra == "webrtc"
25
+ Requires-Dist: Pillow; extra == "webrtc"
26
+ Dynamic: license-file
27
+
28
+ # python-aidot-cameras
29
+
30
+ Control AIDOT WiFi lights **and cameras** from Python.
31
+
32
+ This is a camera-capable fork of the upstream lights-only
33
+ [`python-aidot`](https://github.com/Aidot-Development-Team/python-aidot). It adds
34
+ live WebRTC video streaming (DTLS and SDES-SRTP paths), snapshots, PTZ, camera
35
+ controls, cloud recordings/thumbnails, and two-way (push-to-talk) audio.
36
+
37
+ This repository is the **library** (distribution name `python-aidot-cameras`).
38
+ The Home Assistant custom component (`custom_components/aidot/`) lives in the
39
+ companion integration repo
40
+ [`cbrightly/hass-AiDot`](https://github.com/cbrightly/hass-AiDot), which depends
41
+ on this library.
42
+
43
+ ## Library install
44
+
45
+ Install from PyPI (the simplest, recommended method):
46
+
47
+ ```bash
48
+ # lights + camera cloud/control only:
49
+ pip install python-aidot-cameras
50
+ # add live WebRTC streaming, snapshots, and two-way audio:
51
+ pip install python-aidot-cameras[webrtc]
52
+ ```
53
+
54
+ `[webrtc]` pulls in the extra dependencies (aiortc, av, …) needed for live
55
+ streaming, snapshots, and two-way audio. Without it you still get lights plus
56
+ the camera cloud/control APIs, but not live media.
57
+
58
+ For the latest unreleased code, install straight from the GitHub repo instead:
59
+
60
+ ```bash
61
+ # lights + camera cloud/control only:
62
+ pip install "git+https://github.com/cbrightly/python-aidot-cameras"
63
+ # add live WebRTC streaming, snapshots, and two-way audio:
64
+ pip install "python-aidot-cameras[webrtc] @ git+https://github.com/cbrightly/python-aidot-cameras"
65
+ ```
66
+
67
+ ## Usage
68
+
69
+ Open a live WebRTC stream from a camera device client:
70
+
71
+ ```python
72
+ session = await device_client.async_open_webrtc_stream(on_frame=cb, timeout=30.0)
73
+ # ... session.stop() when done
74
+ ```
75
+
76
+ Two-way (push-to-talk) audio:
77
+
78
+ ```python
79
+ session = await device_client.async_open_webrtc_stream(..., talk=True)
80
+ await session.async_start_talk(pcm_provider) # provider() -> 320B s16le PCM (20ms @ 8kHz), or None
81
+ # ... speak ...
82
+ await session.async_stop_talk()
83
+ ```
84
+
85
+ See [`docs/CAMERAS.md`](docs/CAMERAS.md) for the full camera API (streaming,
86
+ snapshots, recordings, motion polling, two-way audio, and LAN-direct media).
87
+
88
+ ## Home Assistant component and CLI
89
+
90
+ The Home Assistant custom component (`custom_components/aidot/`) is **not** part
91
+ of this library repo - it lives in the companion integration repo
92
+ [`cbrightly/hass-AiDot`](https://github.com/cbrightly/hass-AiDot), which depends
93
+ on this library. See that repo for installing the component (via HACS or by
94
+ copying `custom_components/aidot/`).
95
+
96
+ The `test_camera.py` CLI harness and the scripts under `tools/` are local
97
+ developer/diagnostic tools (they carry hardcoded LAN IPs and are gitignored), so
98
+ they are not shipped with the published library.
99
+
100
+ ## Environment variables
101
+
102
+ The library reads the following environment variables.
103
+
104
+ ### Credentials
105
+
106
+ Used by the credential helper (`aidot.credentials`); they take priority over any
107
+ stored credentials file. See [`src/aidot/credentials.py`](src/aidot/credentials.py).
108
+
109
+ | Variable | Purpose | Default |
110
+ | --- | --- | --- |
111
+ | `AIDOT_USERNAME` | AiDot account username/email. Used with `AIDOT_PASSWORD`. | (none) |
112
+ | `AIDOT_PASSWORD` | AiDot account password. Used with `AIDOT_USERNAME`. | (none) |
113
+ | `AIDOT_COUNTRY` | Account region/country code. | `US` |
114
+
115
+ ### Camera streaming / tuning
116
+
117
+ Optional knobs read by the camera client (`aidot.camera.client`). Defaults are
118
+ chosen to work out of the box; override only when tuning.
119
+
120
+ | Variable | Purpose | Default |
121
+ | --- | --- | --- |
122
+ | `AIDOT_SPROP_DIR` | Directory where captured SPS/PPS (sprop) parameter sets are cached. Set this to a writable path (e.g. for Home Assistant) if the default location is read-only. | `<package dir>` |
123
+ | `AIDOT_DISABLE_HIGHPORT_FIX` | If set (any value), disables the DTLS high-port `USE-CANDIDATE` nomination fix and falls back to upstream aioice behavior (used to measure the baseline connect rate). | unset (fix enabled) |
124
+ | `AIDOT_FAST_CONNECT` | Enables LAN-direct "fast connect" mode (STUN-only, skips several cloud signaling waits) when set to a truthy value. | unset (off) |
125
+ | `AIDOT_MAX_CONCURRENT_OPENS` | Caps how many stream opens run concurrently. | `2` |
126
+ | `AIDOT_MAX_CONCURRENT_STREAMS` | Caps how many cameras stream at once. | `3` |
127
+ | `AIDOT_STREAM_IDLE_S` | Seconds of stream idle before an idle release. | `120` |
128
+ | `AIDOT_SDES_IDLE_RELEASE` | Set to `0` to disable idle release for SDES streams. | `1` (enabled) |
129
+ | `AIDOT_ICE_DISCONNECT_S` | ICE-disconnect debounce, in seconds, before tearing down. | `8` |
130
+ | `AIDOT_DTLS_RETRY_GATE_S` | Minimum spacing, in seconds, between DTLS open retries. | `15` |
131
+ | `AIDOT_BUSY_RETRY_S` | Delay, in seconds, before retrying when a camera reports busy. | `45` |
132
+ | `AIDOT_GOP_PLI_S` | Interval, in seconds, between PLI (keyframe) requests. | `2.0` |
133
+ | `AIDOT_AUDIO_TARGET_DBFS` | Target loudness (dBFS) for two-way audio normalization. | `-15` |
134
+ | `AIDOT_AUDIO_MAXGAIN_DB` | Maximum gain (dB) applied by the audio normalizer. | `30` |
135
+ | `AIDOT_AUDIO_MINGAIN_DB` | Minimum gain (dB) applied by the audio normalizer. | `-12` |
136
+ | `AIDOT_AUDIO_GATE_DBFS` | Noise-gate threshold (dBFS) for two-way audio. | `-45` |
137
+ | `AIDOT_SDES_SERVE_AUDIO` | Set to `1` to serve audio on SDES cameras (off by default). | `0` (off) |
138
+ | `AIDOT_SDES_AUDIO_GAIN_DB` | Gain (dB) applied when SDES audio is served. | `-8` |
@@ -0,0 +1,111 @@
1
+ # python-aidot-cameras
2
+
3
+ Control AIDOT WiFi lights **and cameras** from Python.
4
+
5
+ This is a camera-capable fork of the upstream lights-only
6
+ [`python-aidot`](https://github.com/Aidot-Development-Team/python-aidot). It adds
7
+ live WebRTC video streaming (DTLS and SDES-SRTP paths), snapshots, PTZ, camera
8
+ controls, cloud recordings/thumbnails, and two-way (push-to-talk) audio.
9
+
10
+ This repository is the **library** (distribution name `python-aidot-cameras`).
11
+ The Home Assistant custom component (`custom_components/aidot/`) lives in the
12
+ companion integration repo
13
+ [`cbrightly/hass-AiDot`](https://github.com/cbrightly/hass-AiDot), which depends
14
+ on this library.
15
+
16
+ ## Library install
17
+
18
+ Install from PyPI (the simplest, recommended method):
19
+
20
+ ```bash
21
+ # lights + camera cloud/control only:
22
+ pip install python-aidot-cameras
23
+ # add live WebRTC streaming, snapshots, and two-way audio:
24
+ pip install python-aidot-cameras[webrtc]
25
+ ```
26
+
27
+ `[webrtc]` pulls in the extra dependencies (aiortc, av, …) needed for live
28
+ streaming, snapshots, and two-way audio. Without it you still get lights plus
29
+ the camera cloud/control APIs, but not live media.
30
+
31
+ For the latest unreleased code, install straight from the GitHub repo instead:
32
+
33
+ ```bash
34
+ # lights + camera cloud/control only:
35
+ pip install "git+https://github.com/cbrightly/python-aidot-cameras"
36
+ # add live WebRTC streaming, snapshots, and two-way audio:
37
+ pip install "python-aidot-cameras[webrtc] @ git+https://github.com/cbrightly/python-aidot-cameras"
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ Open a live WebRTC stream from a camera device client:
43
+
44
+ ```python
45
+ session = await device_client.async_open_webrtc_stream(on_frame=cb, timeout=30.0)
46
+ # ... session.stop() when done
47
+ ```
48
+
49
+ Two-way (push-to-talk) audio:
50
+
51
+ ```python
52
+ session = await device_client.async_open_webrtc_stream(..., talk=True)
53
+ await session.async_start_talk(pcm_provider) # provider() -> 320B s16le PCM (20ms @ 8kHz), or None
54
+ # ... speak ...
55
+ await session.async_stop_talk()
56
+ ```
57
+
58
+ See [`docs/CAMERAS.md`](docs/CAMERAS.md) for the full camera API (streaming,
59
+ snapshots, recordings, motion polling, two-way audio, and LAN-direct media).
60
+
61
+ ## Home Assistant component and CLI
62
+
63
+ The Home Assistant custom component (`custom_components/aidot/`) is **not** part
64
+ of this library repo - it lives in the companion integration repo
65
+ [`cbrightly/hass-AiDot`](https://github.com/cbrightly/hass-AiDot), which depends
66
+ on this library. See that repo for installing the component (via HACS or by
67
+ copying `custom_components/aidot/`).
68
+
69
+ The `test_camera.py` CLI harness and the scripts under `tools/` are local
70
+ developer/diagnostic tools (they carry hardcoded LAN IPs and are gitignored), so
71
+ they are not shipped with the published library.
72
+
73
+ ## Environment variables
74
+
75
+ The library reads the following environment variables.
76
+
77
+ ### Credentials
78
+
79
+ Used by the credential helper (`aidot.credentials`); they take priority over any
80
+ stored credentials file. See [`src/aidot/credentials.py`](src/aidot/credentials.py).
81
+
82
+ | Variable | Purpose | Default |
83
+ | --- | --- | --- |
84
+ | `AIDOT_USERNAME` | AiDot account username/email. Used with `AIDOT_PASSWORD`. | (none) |
85
+ | `AIDOT_PASSWORD` | AiDot account password. Used with `AIDOT_USERNAME`. | (none) |
86
+ | `AIDOT_COUNTRY` | Account region/country code. | `US` |
87
+
88
+ ### Camera streaming / tuning
89
+
90
+ Optional knobs read by the camera client (`aidot.camera.client`). Defaults are
91
+ chosen to work out of the box; override only when tuning.
92
+
93
+ | Variable | Purpose | Default |
94
+ | --- | --- | --- |
95
+ | `AIDOT_SPROP_DIR` | Directory where captured SPS/PPS (sprop) parameter sets are cached. Set this to a writable path (e.g. for Home Assistant) if the default location is read-only. | `<package dir>` |
96
+ | `AIDOT_DISABLE_HIGHPORT_FIX` | If set (any value), disables the DTLS high-port `USE-CANDIDATE` nomination fix and falls back to upstream aioice behavior (used to measure the baseline connect rate). | unset (fix enabled) |
97
+ | `AIDOT_FAST_CONNECT` | Enables LAN-direct "fast connect" mode (STUN-only, skips several cloud signaling waits) when set to a truthy value. | unset (off) |
98
+ | `AIDOT_MAX_CONCURRENT_OPENS` | Caps how many stream opens run concurrently. | `2` |
99
+ | `AIDOT_MAX_CONCURRENT_STREAMS` | Caps how many cameras stream at once. | `3` |
100
+ | `AIDOT_STREAM_IDLE_S` | Seconds of stream idle before an idle release. | `120` |
101
+ | `AIDOT_SDES_IDLE_RELEASE` | Set to `0` to disable idle release for SDES streams. | `1` (enabled) |
102
+ | `AIDOT_ICE_DISCONNECT_S` | ICE-disconnect debounce, in seconds, before tearing down. | `8` |
103
+ | `AIDOT_DTLS_RETRY_GATE_S` | Minimum spacing, in seconds, between DTLS open retries. | `15` |
104
+ | `AIDOT_BUSY_RETRY_S` | Delay, in seconds, before retrying when a camera reports busy. | `45` |
105
+ | `AIDOT_GOP_PLI_S` | Interval, in seconds, between PLI (keyframe) requests. | `2.0` |
106
+ | `AIDOT_AUDIO_TARGET_DBFS` | Target loudness (dBFS) for two-way audio normalization. | `-15` |
107
+ | `AIDOT_AUDIO_MAXGAIN_DB` | Maximum gain (dB) applied by the audio normalizer. | `30` |
108
+ | `AIDOT_AUDIO_MINGAIN_DB` | Minimum gain (dB) applied by the audio normalizer. | `-12` |
109
+ | `AIDOT_AUDIO_GATE_DBFS` | Noise-gate threshold (dBFS) for two-way audio. | `-45` |
110
+ | `AIDOT_SDES_SERVE_AUDIO` | Set to `1` to serve audio on SDES cameras (off by default). | `0` (off) |
111
+ | `AIDOT_SDES_AUDIO_GAIN_DB` | Gain (dB) applied when SDES audio is served. | `-8` |
@@ -0,0 +1,77 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "python-aidot-cameras"
7
+ version = "0.7.10"
8
+ description = "Control AiDot/Leedarson WiFi lights and cameras (WebRTC streaming, two-way audio, PTZ, controls)"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ authors = [{ name = "cbrightly", email = "chris.brightly@gmail.com" }]
13
+ requires-python = ">=3.11"
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Operating System :: OS Independent",
17
+ ]
18
+ dependencies = [
19
+ "aiohttp",
20
+ "paho-mqtt>=2.0",
21
+ "cryptography",
22
+ "pycryptodome",
23
+ "dacite",
24
+ ]
25
+
26
+ [project.optional-dependencies]
27
+ webrtc = [
28
+ "aiortc>=1.9.0",
29
+ "av",
30
+ "pylibsrtp",
31
+ "pyopenssl",
32
+ "numpy",
33
+ "Pillow",
34
+ ]
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/cbrightly/python-aidot-cameras"
38
+ "Issue Tracker" = "https://github.com/cbrightly/python-aidot-cameras/issues"
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
42
+
43
+ [tool.setuptools.package-data]
44
+ aidot = ["py.typed"]
45
+
46
+ [tool.ruff]
47
+ target-version = "py311"
48
+ line-length = 88
49
+
50
+ [tool.ruff.lint]
51
+ # High-signal rules only; opinionated style (quotes, trailing commas, missing
52
+ # annotations/docstrings, magic values) is intentionally left to the formatter.
53
+ select = ["F", "E4", "E7", "E9", "W", "B", "ASYNC", "RUF", "UP", "SIM", "PIE", "RET", "PERF"]
54
+ ignore = [
55
+ "E501", # line length: formatter's job
56
+ "E701", "E741", # multiple-statements / ambiguous name: cosmetic
57
+ "UP035", "UP006", "UP007", "UP045", "UP037", "UP031", # typing/format style (keep broad compat)
58
+ "E702", # multiple-statements (semicolon): cosmetic
59
+ "SIM102", "SIM103", "SIM105", "SIM108", "SIM117", # collapsible/ternary/suppress/nested: stylistic
60
+ "ASYNC109", "ASYNC240", # timeout-param design; os.path.join is non-blocking
61
+ "RET504", "RET505", "RET506", # return-style: stylistic
62
+ "PERF203", "PERF401", # try/except in loop, manual comprehension: stylistic
63
+ "PIE810", # multiple startswith/endswith: stylistic
64
+ "RUF001", "RUF003", "RUF059", # ambiguous-unicode (intentional ×), unused-unpacked: cosmetic
65
+ "B904", # raise-without-from: traceback-chaining style (not enforced)
66
+ "B008",
67
+ ]
68
+
69
+ [tool.ruff.lint.per-file-ignores]
70
+ "tests/**" = ["B", "RUF", "SIM", "PERF", "ASYNC", "F811", "PIE", "E731", "E702"]
71
+ # Re-export modules: imports are intentional public re-exports / back-compat shims.
72
+ "__init__.py" = ["F401"]
73
+ # device_client.py re-exports from camera.client mid-file (avoids a circular import).
74
+ "**/device_client.py" = ["F401", "E402"]
75
+ # Inherited ffmpeg streaming engine is process-based (Popen / subprocess poll /
76
+ # SDP file write); a full non-blocking refactor needs on-device testing.
77
+ "src/aidot/camera/client.py" = ["ASYNC110", "ASYNC220", "ASYNC221", "ASYNC230"]
@@ -31,11 +31,11 @@ def aes_decrypt(ciphertext, key):
31
31
 
32
32
  def aes_decrypt_to_json(ciphertext: bytes, key: Optional[bytes] = None) -> dict[str, Any]:
33
33
  """Decrypt AES encrypted data and parse to JSON.
34
-
34
+
35
35
  Args:
36
36
  ciphertext: AES encrypted data
37
37
  key: AES key (optional, if None, assumes data is already decrypted)
38
-
38
+
39
39
  Returns:
40
40
  Parsed JSON dict
41
41
  """
@@ -2,4 +2,4 @@
2
2
 
3
3
  from .client import CameraMixin, WebRTCSession, SdesSession
4
4
 
5
- __all__ = ["CameraMixin", "WebRTCSession", "SdesSession"]
5
+ __all__ = ["CameraMixin", "SdesSession", "WebRTCSession"]