pyezvizapi 1.0.2.7__tar.gz → 1.0.2.9__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.

Potentially problematic release.


This version of pyezvizapi might be problematic. Click here for more details.

Files changed (27) hide show
  1. {pyezvizapi-1.0.2.7/pyezvizapi.egg-info → pyezvizapi-1.0.2.9}/PKG-INFO +1 -1
  2. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/api_endpoints.py +2 -0
  3. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/client.py +164 -30
  4. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9/pyezvizapi.egg-info}/PKG-INFO +1 -1
  5. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/setup.py +1 -1
  6. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/LICENSE +0 -0
  7. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/LICENSE.md +0 -0
  8. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/MANIFEST.in +0 -0
  9. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/README.md +0 -0
  10. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/__init__.py +0 -0
  11. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/__main__.py +0 -0
  12. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/camera.py +0 -0
  13. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/cas.py +0 -0
  14. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/constants.py +0 -0
  15. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/exceptions.py +0 -0
  16. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/light_bulb.py +0 -0
  17. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/models.py +0 -0
  18. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/mqtt.py +0 -0
  19. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/test_cam_rtsp.py +0 -0
  20. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/test_mqtt.py +0 -0
  21. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi/utils.py +0 -0
  22. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi.egg-info/SOURCES.txt +0 -0
  23. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi.egg-info/dependency_links.txt +0 -0
  24. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi.egg-info/entry_points.txt +0 -0
  25. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi.egg-info/requires.txt +0 -0
  26. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/pyezvizapi.egg-info/top_level.txt +0 -0
  27. {pyezvizapi-1.0.2.7 → pyezvizapi-1.0.2.9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyezvizapi
3
- Version: 1.0.2.7
3
+ Version: 1.0.2.9
4
4
  Summary: Pilot your Ezviz cameras
5
5
  Home-page: https://github.com/RenierM26/pyEzvizApi/
6
6
  Author: Renier Moorcroft
@@ -37,7 +37,9 @@ API_ENDPOINT_DEVICE_BASICS = "/v3/basics/v1/devices/"
37
37
 
38
38
  API_ENDPOINT_DETECTION_SENSIBILITY = "/api/device/configAlgorithm"
39
39
  API_ENDPOINT_DETECTION_SENSIBILITY_GET = "/api/device/queryAlgorithmConfig"
40
+ API_ENDPOINT_SENSITIVITY = "/v3/devconfig/v1/sensitivity/"
40
41
  API_ENDPOINT_SET_DEFENCE_SCHEDULE = "/api/device/defence/plan2"
42
+ API_ENDPOINT_DEVICE_SWITCH_STATUS_LEGACY = "/api/device/switchStatus"
41
43
  API_ENDPOINT_CAM_ENCRYPTKEY = "/api/device/query/encryptkey"
42
44
  API_ENDPOINT_OFFLINE_NOTIFY = "/api/device/notify/switch"
43
45
  API_ENDPOINT_CANCEL_ALARM = "/api/device/cancelAlarm"
@@ -2,13 +2,12 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from collections.abc import Callable
5
+ from collections.abc import Callable, Mapping
6
6
  from datetime import datetime
7
7
  import hashlib
8
8
  import json
9
9
  import logging
10
10
  from typing import Any, ClassVar, TypedDict, cast
11
- import urllib.parse
12
11
  from uuid import uuid4
13
12
 
14
13
  import requests
@@ -28,6 +27,7 @@ from .api_endpoints import (
28
27
  API_ENDPOINT_DEVCONFIG_BY_KEY,
29
28
  API_ENDPOINT_DEVICE_BASICS,
30
29
  API_ENDPOINT_DEVICE_STORAGE_STATUS,
30
+ API_ENDPOINT_DEVICE_SWITCH_STATUS_LEGACY,
31
31
  API_ENDPOINT_DEVICE_SYS_OPERATION,
32
32
  API_ENDPOINT_DEVICES,
33
33
  API_ENDPOINT_DO_NOT_DISTURB,
@@ -46,6 +46,7 @@ from .api_endpoints import (
46
46
  API_ENDPOINT_REMOTE_UNLOCK,
47
47
  API_ENDPOINT_RETURN_PANORAMIC,
48
48
  API_ENDPOINT_SEND_CODE,
49
+ API_ENDPOINT_SENSITIVITY,
49
50
  API_ENDPOINT_SERVER_INFO,
50
51
  API_ENDPOINT_SET_DEFENCE_SCHEDULE,
51
52
  API_ENDPOINT_SET_LUMINANCE,
@@ -647,26 +648,103 @@ class EzvizClient:
647
648
  self._ensure_ok(json_output, "Could not get unified message list")
648
649
  return json_output
649
650
 
651
+ def set_switch_v3(
652
+ self,
653
+ serial: str,
654
+ switch_type: int,
655
+ enable: bool | int,
656
+ channel: int = 0,
657
+ max_retries: int = 0,
658
+ ) -> dict:
659
+ """Update a device switch via the v3 endpoint."""
660
+
661
+ if max_retries > MAX_RETRIES:
662
+ raise PyEzvizError("Can't gather proper data. Max retries exceeded.")
663
+
664
+ enable_flag = 1 if bool(enable) else 0
665
+ path = (
666
+ f"{API_ENDPOINT_DEVICES}{serial}/{channel}/{enable_flag}/"
667
+ f"{switch_type}{API_ENDPOINT_SWITCH_STATUS}"
668
+ )
669
+ payload = self._request_json(
670
+ "PUT",
671
+ path,
672
+ retry_401=True,
673
+ max_retries=max_retries,
674
+ )
675
+ self._ensure_ok(payload, "Could not set the switch")
676
+ return payload
677
+
678
+ def set_switch_legacy(
679
+ self,
680
+ serial: str,
681
+ switch_type: int,
682
+ enable: bool | int,
683
+ channel: int = 0,
684
+ max_retries: int = 0,
685
+ ) -> dict:
686
+ """Fallback legacy switch endpoint used by older firmware."""
687
+
688
+ if max_retries > MAX_RETRIES:
689
+ raise PyEzvizError("Can't gather proper data. Max retries exceeded.")
690
+
691
+ payload = self._request_json(
692
+ "POST",
693
+ API_ENDPOINT_DEVICE_SWITCH_STATUS_LEGACY,
694
+ data={
695
+ "serial": serial,
696
+ "enable": "1" if bool(enable) else "0",
697
+ "type": str(switch_type),
698
+ "channel": str(channel),
699
+ },
700
+ retry_401=True,
701
+ max_retries=max_retries,
702
+ )
703
+ self._ensure_ok(payload, "Could not set the switch (legacy)")
704
+ return payload
705
+
706
+ def set_switch(
707
+ self,
708
+ serial: str,
709
+ switch_type: int,
710
+ enable: bool | int,
711
+ channel: int = 0,
712
+ max_retries: int = 0,
713
+ ) -> dict:
714
+ """Try the v3 switch endpoint, falling back to the legacy API if needed."""
715
+
716
+ try:
717
+ return self.set_switch_v3(
718
+ serial, switch_type, enable, channel, max_retries=max_retries
719
+ )
720
+ except PyEzvizError as first_error:
721
+ try:
722
+ return self.set_switch_legacy(
723
+ serial, switch_type, enable, channel, max_retries=max_retries
724
+ )
725
+ except PyEzvizError:
726
+ raise first_error from None
727
+
650
728
  def switch_status(
651
729
  self,
652
730
  serial: str,
653
731
  status_type: int,
654
- enable: int,
732
+ enable: bool | int,
655
733
  channel_no: int = 0,
656
734
  max_retries: int = 0,
657
735
  ) -> bool:
658
736
  """Camera features are represented as switches. Switch them on or off."""
659
- if max_retries > MAX_RETRIES:
660
- raise PyEzvizError("Can't gather proper data. Max retries exceeded.")
661
- json_output = self._request_json(
662
- "PUT",
663
- f"{API_ENDPOINT_DEVICES}{serial}/{channel_no}/{enable}/{status_type}{API_ENDPOINT_SWITCH_STATUS}",
664
- retry_401=True,
737
+
738
+ target_state = bool(enable)
739
+ self.set_switch(
740
+ serial,
741
+ status_type,
742
+ target_state,
743
+ channel=channel_no,
665
744
  max_retries=max_retries,
666
745
  )
667
- self._ensure_ok(json_output, "Could not set the switch")
668
746
  if self._cameras.get(serial):
669
- self._cameras[serial]["switches"][status_type] = bool(enable)
747
+ self._cameras[serial]["switches"][status_type] = target_state
670
748
  return True
671
749
 
672
750
  def switch_status_other(
@@ -792,36 +870,61 @@ class EzvizClient:
792
870
  serial, value=f'{{"mode":{mode}}}', key="display_mode"
793
871
  )
794
872
 
795
- def set_device_config_by_key(
873
+ def set_dev_config_kv(
796
874
  self,
797
875
  serial: str,
798
- value: Any,
876
+ channel: int,
799
877
  key: str,
878
+ value: Mapping[str, Any] | str | bytes | float | bool,
800
879
  max_retries: int = 0,
801
- ) -> bool:
802
- """Change value on device by setting key."""
880
+ ) -> dict:
881
+ """Update a device configuration key/value pair via devconfig."""
882
+
803
883
  if max_retries > MAX_RETRIES:
804
884
  raise PyEzvizError("Can't gather proper data. Max retries exceeded.")
805
885
 
806
- params = {"key": key, "value": value}
807
- params_str = urllib.parse.urlencode(
808
- params, safe="}{:"
809
- ) # not encode curly braces and colon
886
+ if isinstance(value, Mapping):
887
+ value_payload = json.dumps(value, separators=(",", ":"))
888
+ elif isinstance(value, bytes):
889
+ value_payload = value.decode()
890
+ elif isinstance(value, bool):
891
+ value_payload = "1" if value else "0"
892
+ elif isinstance(value, (int, float)):
893
+ value_payload = str(value)
894
+ else:
895
+ value_payload = str(value)
810
896
 
811
- full_url = f"https://{self._token['api_url']}{API_ENDPOINT_DEVCONFIG_BY_KEY}{serial}/1/op"
897
+ data = {
898
+ "key": key,
899
+ "value": value_payload,
900
+ }
812
901
 
813
- # EZVIZ api request needs {}: in the url, but requests lib doesn't allow it
814
- # so we need to manually prepare it
815
- req_prep = requests.Request(
816
- method="PUT", url=full_url, headers=self._session.headers
817
- ).prepare()
818
- req_prep.url = full_url + "?" + params_str
902
+ payload = self._request_json(
903
+ "PUT",
904
+ f"{API_ENDPOINT_DEVCONFIG_BY_KEY}{serial}/{channel}/op",
905
+ data=data,
906
+ retry_401=True,
907
+ max_retries=max_retries,
908
+ )
909
+ self._ensure_ok(payload, "Could not set devconfig key")
910
+ return payload
819
911
 
820
- req = self._send_prepared(req_prep, retry_401=True, max_retries=max_retries)
821
- json_output = self._parse_json(req)
822
- if not self._meta_ok(json_output):
823
- raise PyEzvizError(f"Could not set config key '${key}': Got {json_output})")
912
+ def set_device_config_by_key(
913
+ self,
914
+ serial: str,
915
+ value: Any,
916
+ key: str,
917
+ max_retries: int = 0,
918
+ ) -> bool:
919
+ """Change value on device by setting key."""
824
920
 
921
+ self.set_dev_config_kv(
922
+ serial,
923
+ 1,
924
+ key,
925
+ value,
926
+ max_retries=max_retries,
927
+ )
825
928
  return True
826
929
 
827
930
  def set_device_feature_by_key(
@@ -1997,6 +2100,37 @@ class EzvizClient:
1997
2100
 
1998
2101
  return True
1999
2102
 
2103
+ def set_detection_sensitivity(
2104
+ self,
2105
+ serial: str,
2106
+ channel: int,
2107
+ sensitivity_type: int,
2108
+ value: int,
2109
+ max_retries: int = 0,
2110
+ ) -> bool:
2111
+ """Set detection sensitivity via v3 devconfig endpoint."""
2112
+
2113
+ if max_retries > MAX_RETRIES:
2114
+ raise PyEzvizError("Can't gather proper data. Max retries exceeded.")
2115
+
2116
+ if sensitivity_type == 0 and not 1 <= value <= 6:
2117
+ raise PyEzvizError("Detection sensitivity must be within 1..6")
2118
+ if sensitivity_type != 0 and not 1 <= value <= 100:
2119
+ raise PyEzvizError("Detection sensitivity must be within 1..100")
2120
+
2121
+ url_path = (
2122
+ f"{API_ENDPOINT_SENSITIVITY}{serial}/{channel}/{sensitivity_type}/{value}"
2123
+ )
2124
+ json_output = self._request_json(
2125
+ "PUT",
2126
+ url_path,
2127
+ retry_401=True,
2128
+ max_retries=max_retries,
2129
+ )
2130
+ self._ensure_ok(json_output, "Could not set detection sensitivity")
2131
+
2132
+ return True
2133
+
2000
2134
  def get_detection_sensibility(
2001
2135
  self, serial: str, type_value: str = "0", max_retries: int = 0
2002
2136
  ) -> Any:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyezvizapi
3
- Version: 1.0.2.7
3
+ Version: 1.0.2.9
4
4
  Summary: Pilot your Ezviz cameras
5
5
  Home-page: https://github.com/RenierM26/pyEzvizApi/
6
6
  Author: Renier Moorcroft
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name='pyezvizapi',
8
- version="1.0.2.7",
8
+ version="1.0.2.9",
9
9
  license='Apache Software License 2.0',
10
10
  author='Renier Moorcroft',
11
11
  author_email='RenierM26@users.github.com',
File without changes
File without changes
File without changes
File without changes
File without changes