python-aidot-cameras 0.5.17__tar.gz → 0.6.1__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 (40) hide show
  1. {python_aidot_cameras-0.5.17/src/python_aidot_cameras.egg-info → python_aidot_cameras-0.6.1}/PKG-INFO +2 -1
  2. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/pyproject.toml +2 -1
  3. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/src/aidot/aes_utils.py +30 -6
  4. python_aidot_cameras-0.6.1/src/aidot/camera/__init__.py +5 -0
  5. python_aidot_cameras-0.5.17/src/aidot/device_client.py → python_aidot_cameras-0.6.1/src/aidot/camera/client.py +198 -489
  6. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/src/aidot/client.py +99 -22
  7. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/src/aidot/const.py +7 -2
  8. python_aidot_cameras-0.6.1/src/aidot/device_client.py +470 -0
  9. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/src/aidot/discover.py +52 -43
  10. python_aidot_cameras-0.6.1/src/aidot/login_const.py +16 -0
  11. python_aidot_cameras-0.6.1/src/aidot/models/__init__.py +37 -0
  12. python_aidot_cameras-0.6.1/src/aidot/models/device_client_model.py +210 -0
  13. python_aidot_cameras-0.6.1/src/aidot/models/device_model.py +83 -0
  14. python_aidot_cameras-0.6.1/src/aidot/models/discover_model.py +102 -0
  15. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1/src/python_aidot_cameras.egg-info}/PKG-INFO +2 -1
  16. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/src/python_aidot_cameras.egg-info/SOURCES.txt +8 -0
  17. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/src/python_aidot_cameras.egg-info/requires.txt +1 -0
  18. python_aidot_cameras-0.6.1/tests/test_post_merge_hardening.py +178 -0
  19. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/tests/test_sdes_sprop.py +2 -1
  20. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/tests/test_stream_cap.py +2 -1
  21. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/LICENSE +0 -0
  22. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/README.md +0 -0
  23. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/setup.cfg +0 -0
  24. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/src/aidot/__init__.py +0 -0
  25. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/src/aidot/credentials.py +0 -0
  26. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/src/aidot/exceptions.py +0 -0
  27. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/src/aidot/g711.py +0 -0
  28. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/src/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
  29. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/src/python_aidot_cameras.egg-info/top_level.txt +0 -0
  30. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/tests/test_alarm_event.py +0 -0
  31. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/tests/test_highport_nomination.py +0 -0
  32. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/tests/test_motion_poll.py +0 -0
  33. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/tests/test_no_undefined_names.py +0 -0
  34. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/tests/test_sdes_idle_release.py +0 -0
  35. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/tests/test_sdes_talk.py +0 -0
  36. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/tests/test_sdes_watchdog.py +0 -0
  37. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/tests/test_speak.py +0 -0
  38. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/tests/test_talk.py +0 -0
  39. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/tests/test_terminal_ack.py +0 -0
  40. {python_aidot_cameras-0.5.17 → python_aidot_cameras-0.6.1}/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.5.17
3
+ Version: 0.6.1
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.5.17"
7
+ version = "0.6.1"
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: bytes, key: bytes) -> bytes:
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
- def aes_decrypt(ciphertext: bytes, key: bytes) -> str:
16
- """AES-ECB decrypt with raw key bytes; returns UTF-8 string."""
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
- return plaintext.decode("utf-8")
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:
@@ -0,0 +1,5 @@
1
+ """Camera extensions for the aidot library."""
2
+
3
+ from .client import CameraMixin, WebRTCSession, SdesSession
4
+
5
+ __all__ = ["CameraMixin", "WebRTCSession", "SdesSession"]