python-aidot-cameras 0.5.17__tar.gz → 0.6.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.5.17/src/python_aidot_cameras.egg-info → python_aidot_cameras-0.6.0}/PKG-INFO +2 -1
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/pyproject.toml +2 -1
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/src/aidot/aes_utils.py +30 -6
- python_aidot_cameras-0.6.0/src/aidot/camera/__init__.py +5 -0
- python_aidot_cameras-0.5.17/src/aidot/device_client.py → python_aidot_cameras-0.6.0/src/aidot/camera/client.py +168 -477
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/src/aidot/client.py +84 -20
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/src/aidot/const.py +4 -0
- python_aidot_cameras-0.6.0/src/aidot/device_client.py +448 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/src/aidot/discover.py +45 -30
- python_aidot_cameras-0.6.0/src/aidot/login_const.py +16 -0
- python_aidot_cameras-0.6.0/src/aidot/models/__init__.py +37 -0
- python_aidot_cameras-0.6.0/src/aidot/models/device_client_model.py +210 -0
- python_aidot_cameras-0.6.0/src/aidot/models/device_model.py +83 -0
- python_aidot_cameras-0.6.0/src/aidot/models/discover_model.py +102 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0/src/python_aidot_cameras.egg-info}/PKG-INFO +2 -1
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/src/python_aidot_cameras.egg-info/SOURCES.txt +7 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/src/python_aidot_cameras.egg-info/requires.txt +1 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/tests/test_sdes_sprop.py +2 -1
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/tests/test_stream_cap.py +2 -1
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/LICENSE +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/README.md +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/setup.cfg +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/src/aidot/__init__.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/src/aidot/credentials.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/src/aidot/exceptions.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/src/aidot/g711.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/src/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/src/python_aidot_cameras.egg-info/top_level.txt +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/tests/test_alarm_event.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/tests/test_highport_nomination.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/tests/test_motion_poll.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/tests/test_no_undefined_names.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/tests/test_sdes_idle_release.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/tests/test_sdes_talk.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/tests/test_sdes_watchdog.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/tests/test_speak.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/tests/test_talk.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/tests/test_terminal_ack.py +0 -0
- {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.0}/tests/test_token_refresh.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aidot-cameras
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.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
|
|
@@ -15,6 +15,7 @@ Requires-Dist: aiohttp
|
|
|
15
15
|
Requires-Dist: paho-mqtt>=2.0
|
|
16
16
|
Requires-Dist: cryptography
|
|
17
17
|
Requires-Dist: pycryptodome
|
|
18
|
+
Requires-Dist: dacite
|
|
18
19
|
Provides-Extra: webrtc
|
|
19
20
|
Requires-Dist: aiortc>=1.9.0; extra == "webrtc"
|
|
20
21
|
Requires-Dist: av; extra == "webrtc"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-aidot-cameras"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.6.0"
|
|
8
8
|
description = "Control AiDot/Leedarson WiFi lights and cameras (WebRTC streaming, two-way audio, PTZ, controls)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -20,6 +20,7 @@ dependencies = [
|
|
|
20
20
|
"paho-mqtt>=2.0",
|
|
21
21
|
"cryptography",
|
|
22
22
|
"pycryptodome",
|
|
23
|
+
"dacite",
|
|
23
24
|
]
|
|
24
25
|
|
|
25
26
|
[project.optional-dependencies]
|
|
@@ -1,25 +1,49 @@
|
|
|
1
1
|
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
|
2
2
|
from cryptography.hazmat.backends import default_backend
|
|
3
3
|
from cryptography.hazmat.primitives import padding
|
|
4
|
+
import json
|
|
5
|
+
from typing import Any, Optional
|
|
4
6
|
|
|
5
7
|
|
|
6
|
-
def aes_encrypt(plaintext
|
|
7
|
-
"""AES-ECB encrypt with raw key bytes (used for LAN discovery / TCP:10000)."""
|
|
8
|
+
def aes_encrypt(plaintext, key):
|
|
8
9
|
padder = padding.PKCS7(algorithms.AES.block_size).padder()
|
|
9
10
|
padded_data = padder.update(plaintext) + padder.finalize()
|
|
11
|
+
|
|
10
12
|
cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())
|
|
11
13
|
encryptor = cipher.encryptor()
|
|
12
|
-
return encryptor.update(padded_data) + encryptor.finalize()
|
|
13
14
|
|
|
15
|
+
ciphertext = encryptor.update(padded_data) + encryptor.finalize()
|
|
16
|
+
|
|
17
|
+
return ciphertext
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
|
|
20
|
+
def aes_decrypt(ciphertext, key):
|
|
17
21
|
cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())
|
|
18
22
|
decryptor = cipher.decryptor()
|
|
23
|
+
|
|
19
24
|
decrypted_data = decryptor.update(ciphertext) + decryptor.finalize()
|
|
25
|
+
|
|
20
26
|
unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
|
|
21
27
|
plaintext = unpadder.update(decrypted_data) + unpadder.finalize()
|
|
22
|
-
|
|
28
|
+
|
|
29
|
+
return plaintext.decode()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def aes_decrypt_to_json(ciphertext: bytes, key: Optional[bytes] = None) -> dict[str, Any]:
|
|
33
|
+
"""Decrypt AES encrypted data and parse to JSON.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
ciphertext: AES encrypted data
|
|
37
|
+
key: AES key (optional, if None, assumes data is already decrypted)
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Parsed JSON dict
|
|
41
|
+
"""
|
|
42
|
+
if key:
|
|
43
|
+
decrypted_data = aes_decrypt(ciphertext, key)
|
|
44
|
+
else:
|
|
45
|
+
decrypted_data = ciphertext.decode() if isinstance(ciphertext, bytes) else ciphertext
|
|
46
|
+
return json.loads(decrypted_data)
|
|
23
47
|
|
|
24
48
|
|
|
25
49
|
def _str_key_32(key_str: str) -> bytes:
|