pyezvizapi 1.0.0.7__tar.gz → 1.0.0.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 (25) hide show
  1. {pyezvizapi-1.0.0.7/pyezvizapi.egg-info → pyezvizapi-1.0.0.9}/PKG-INFO +1 -1
  2. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi/__init__.py +18 -15
  3. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi/api_endpoints.py +5 -0
  4. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi/camera.py +1 -0
  5. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi/client.py +176 -4
  6. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi/constants.py +21 -6
  7. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi/light_bulb.py +46 -21
  8. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9/pyezvizapi.egg-info}/PKG-INFO +1 -1
  9. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/setup.py +1 -1
  10. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/LICENSE +0 -0
  11. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/LICENSE.md +0 -0
  12. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/MANIFEST.in +0 -0
  13. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/README.md +0 -0
  14. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi/__main__.py +0 -0
  15. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi/cas.py +0 -0
  16. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi/exceptions.py +0 -0
  17. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi/mqtt.py +0 -0
  18. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi/test_cam_rtsp.py +0 -0
  19. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi/utils.py +0 -0
  20. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi.egg-info/SOURCES.txt +0 -0
  21. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi.egg-info/dependency_links.txt +0 -0
  22. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi.egg-info/entry_points.txt +0 -0
  23. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi.egg-info/requires.txt +0 -0
  24. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/pyezvizapi.egg-info/top_level.txt +0 -0
  25. {pyezvizapi-1.0.0.7 → pyezvizapi-1.0.0.9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pyezvizapi
3
- Version: 1.0.0.7
3
+ Version: 1.0.0.9
4
4
  Summary: Pilot your Ezviz cameras
5
5
  Home-page: https://github.com/RenierM26/pyEzvizApi/
6
6
  Author: Renier Moorcroft
@@ -1,14 +1,16 @@
1
1
  """init pyezvizapi."""
2
+
2
3
  from .camera import EzvizCamera
3
4
  from .cas import EzvizCAS
4
5
  from .client import EzvizClient
5
6
  from .constants import (
7
+ AlarmDetectHumanCar,
6
8
  BatteryCameraWorkMode,
7
9
  DefenseModeType,
8
10
  DeviceCatagories,
9
11
  DeviceSwitchType,
10
12
  DisplayMode,
11
- IntelligentDetectionMode,
13
+ IntelligentDetectionSmartApp,
12
14
  MessageFilterType,
13
15
  NightVisionMode,
14
16
  SoundMode,
@@ -28,27 +30,28 @@ from .mqtt import MQTTClient
28
30
  from .test_cam_rtsp import TestRTSPAuth
29
31
 
30
32
  __all__ = [
31
- "EzvizCamera",
32
- "EzvizClient",
33
- "PyEzvizError",
34
- "InvalidURL",
35
- "HTTPError",
36
- "InvalidHost",
33
+ "AlarmDetectHumanCar",
37
34
  "AuthTestResultFailed",
35
+ "BatteryCameraWorkMode",
36
+ "DefenseModeType",
37
+ "DeviceCatagories",
38
+ "DeviceSwitchType",
39
+ "DisplayMode",
38
40
  "EzvizAuthTokenExpired",
39
41
  "EzvizAuthVerificationCode",
40
42
  "EzvizCAS",
43
+ "EzvizCamera",
44
+ "EzvizClient",
41
45
  "EzvizLightBulb",
46
+ "HTTPError",
47
+ "IntelligentDetectionSmartApp",
48
+ "InvalidHost",
49
+ "InvalidURL",
42
50
  "MQTTClient",
43
- "DefenseModeType",
44
- "IntelligentDetectionMode",
45
- "BatteryCameraWorkMode",
46
- "DisplayMode",
47
- "NightVisionMode",
48
51
  "MessageFilterType",
49
- "DeviceCatagories",
50
- "DeviceSwitchType",
51
- "SupportExt",
52
+ "NightVisionMode",
53
+ "PyEzvizError",
52
54
  "SoundMode",
55
+ "SupportExt",
53
56
  "TestRTSPAuth",
54
57
  ]
@@ -12,6 +12,7 @@ API_ENDPOINT_USER_ID = "/v3/userdevices/v1/token"
12
12
  API_ENDPOINT_GROUP_DEFENCE_MODE = "/v3/userdevices/v1/group/defenceMode"
13
13
  API_ENDPOINT_PAGELIST = "/v3/userdevices/v1/resources/pagelist"
14
14
  API_ENDPOINT_SWITCH_DEFENCE_MODE = "/v3/userdevices/v1/group/switchDefenceMode"
15
+ API_ENDPOINT_OSD = "/v3/userdevices/v1/devices/"
15
16
 
16
17
  API_ENDPOINT_PANORAMIC_DEVICES_OPERATION = "/v3/panoramicDevices/operation"
17
18
  API_ENDPOINT_UPGRADE_DEVICE = "/v3/upgrades/v1/devices/"
@@ -27,6 +28,10 @@ API_ENDPOINT_SET_LUMINANCE = "/v3/alarms/device/alarmLight/"
27
28
  API_ENDPOINT_DEVCONFIG_BY_KEY = "/v3/devconfig/v1/keyValue/"
28
29
  API_ENDPOINT_CAM_AUTH_CODE = "/v3/devconfig/authcode/query/"
29
30
 
31
+ API_ENDPOINT_INTELLIGENT_APP = "/v3/intelligent-app/load/"
32
+
33
+ API_ENDPOINT_DEVICE_BASICS = "/v3/basics/v1/devices/"
34
+
30
35
  API_ENDPOINT_DETECTION_SENSIBILITY = "/api/device/configAlgorithm"
31
36
  API_ENDPOINT_DETECTION_SENSIBILITY_GET = "/api/device/queryAlgorithmConfig"
32
37
  API_ENDPOINT_SET_DEFENCE_SCHEDULE = "/api/device/defence/plan2"
@@ -164,6 +164,7 @@ class EzvizCamera:
164
164
  "Alarm_AdvancedDetect": self.fetch_key(
165
165
  ["STATUS", "optionals", "Alarm_AdvancedDetect", "type"]
166
166
  ),
167
+ "resouceid": self.fetch_key(["resourceInfos", 0, "resourceId"]),
167
168
  "wifiInfos": self._device["WIFI"],
168
169
  "switches": self._switch,
169
170
  "optionals": self.fetch_key(["STATUS", "optionals"]),
@@ -24,15 +24,18 @@ from .api_endpoints import (
24
24
  API_ENDPOINT_DETECTION_SENSIBILITY,
25
25
  API_ENDPOINT_DETECTION_SENSIBILITY_GET,
26
26
  API_ENDPOINT_DEVCONFIG_BY_KEY,
27
+ API_ENDPOINT_DEVICE_BASICS,
27
28
  API_ENDPOINT_DEVICE_STORAGE_STATUS,
28
29
  API_ENDPOINT_DEVICE_SYS_OPERATION,
29
30
  API_ENDPOINT_DEVICES,
30
31
  API_ENDPOINT_DO_NOT_DISTURB,
31
32
  API_ENDPOINT_GROUP_DEFENCE_MODE,
33
+ API_ENDPOINT_INTELLIGENT_APP,
32
34
  API_ENDPOINT_IOT_FEATURE,
33
35
  API_ENDPOINT_LOGIN,
34
36
  API_ENDPOINT_LOGOUT,
35
37
  API_ENDPOINT_OFFLINE_NOTIFY,
38
+ API_ENDPOINT_OSD,
36
39
  API_ENDPOINT_PAGELIST,
37
40
  API_ENDPOINT_PANORAMIC_DEVICES_OPERATION,
38
41
  API_ENDPOINT_PTZCONTROL,
@@ -660,7 +663,7 @@ class EzvizClient:
660
663
  params, safe="}{:"
661
664
  ) # not encode curly braces and colon
662
665
 
663
- full_url = f'https://{self._token["api_url"]}{API_ENDPOINT_DEVCONFIG_BY_KEY}{serial}/1/op'
666
+ full_url = f"https://{self._token['api_url']}{API_ENDPOINT_DEVCONFIG_BY_KEY}{serial}/1/op"
664
667
 
665
668
  # EZVIZ api request needs {}: in the url, but requests lib doesn't allow it
666
669
  # so we need to manually prepare it
@@ -721,7 +724,7 @@ class EzvizClient:
721
724
 
722
725
  payload = json.dumps({"itemKey": key, "productId": product_id, "value": value})
723
726
 
724
- full_url = f'https://{self._token["api_url"]}{API_ENDPOINT_IOT_FEATURE}{serial.upper()}/0'
727
+ full_url = f"https://{self._token['api_url']}{API_ENDPOINT_IOT_FEATURE}{serial.upper()}/0"
725
728
 
726
729
  headers = self._session.headers
727
730
  headers.update({"Content-Type": "application/json"})
@@ -1010,7 +1013,7 @@ class EzvizClient:
1010
1013
 
1011
1014
  try:
1012
1015
  req = self._session.post(
1013
- url=f'https://{self._token["api_url"]}{API_ENDPOINT_DEVICE_SYS_OPERATION}{serial}',
1016
+ url=f"https://{self._token['api_url']}{API_ENDPOINT_DEVICE_SYS_OPERATION}{serial}",
1014
1017
  data={
1015
1018
  "oper": operation,
1016
1019
  "deviceSerial": serial,
@@ -1071,7 +1074,7 @@ class EzvizClient:
1071
1074
 
1072
1075
  try:
1073
1076
  req = self._session.post(
1074
- url=f'https://{self._token["api_url"]}{API_ENDPOINT_OFFLINE_NOTIFY}',
1077
+ url=f"https://{self._token['api_url']}{API_ENDPOINT_OFFLINE_NOTIFY}",
1075
1078
  data={
1076
1079
  "reqType": req_type,
1077
1080
  "serial": serial,
@@ -1884,6 +1887,175 @@ class EzvizClient:
1884
1887
 
1885
1888
  return True
1886
1889
 
1890
+ def manage_intelligent_app(
1891
+ self,
1892
+ serial: str,
1893
+ resource_id: str,
1894
+ app_name: str,
1895
+ action: str = "add",
1896
+ max_retries: int = 0,
1897
+ ) -> bool:
1898
+ """Manage the intelligent app on the camera by adding (add) or removing (remove) it.
1899
+
1900
+ Args:
1901
+ serial (str): The camera serial.
1902
+ resource_id (str): The resource identifier of the camera.
1903
+ app_name (str): The intelligent app name.
1904
+ "app_video_change" = Image change detection,
1905
+ "app_human_detect" = Human shape detection,
1906
+ "app_car_detect" = Vehicle detection,
1907
+ "app_wave_recognize" = Gesture recognition
1908
+ action (str, optional): Add or remove app ("add" or "remove"). Defaults to "add".
1909
+ max_retries (int, optional): Number of retries attempted. Defaults to 0.
1910
+
1911
+ Raises:
1912
+ PyEzvizError: If max retries are exceeded or if the response indicates failure.
1913
+ HTTPError: If an HTTP error occurs (other than a 401, which triggers re-login).
1914
+
1915
+ Returns:
1916
+ bool: True if the operation was successful.
1917
+
1918
+ """
1919
+ if max_retries > MAX_RETRIES:
1920
+ raise PyEzvizError("Can't gather proper data. Max retries exceeded.")
1921
+
1922
+ url = (
1923
+ f"https://{self._token['api_url']}"
1924
+ f"{API_ENDPOINT_INTELLIGENT_APP}{serial}/{resource_id}/{app_name}"
1925
+ )
1926
+
1927
+ try:
1928
+ # Determine which method to call based on the parameter.
1929
+ action = action.lower()
1930
+ if action == "add":
1931
+ req = self._session.put(url=url, timeout=self._timeout)
1932
+ elif action == "remove":
1933
+ req = self._session.delete(url=url, timeout=self._timeout)
1934
+ else:
1935
+ raise PyEzvizError(f"Invalid action '{action}'. Use 'add' or 'remove'.")
1936
+
1937
+ req.raise_for_status()
1938
+
1939
+ except requests.HTTPError as err:
1940
+ if err.response.status_code == 401:
1941
+ # Session might be invalid; attempt to re-login and retry.
1942
+ self.login()
1943
+ return self.manage_intelligent_app(
1944
+ serial, resource_id, app_name, action, max_retries + 1
1945
+ )
1946
+ raise HTTPError from err
1947
+
1948
+ try:
1949
+ json_output = req.json()
1950
+ except ValueError as err:
1951
+ raise PyEzvizError("Could not decode response: " + str(err)) from err
1952
+
1953
+ if json_output.get("meta", {}).get("code") != 200:
1954
+ raise PyEzvizError(f"Could not {action} intelligent app: Got {json_output}")
1955
+
1956
+ return True
1957
+
1958
+ def flip_image(
1959
+ self,
1960
+ serial: str,
1961
+ channel: int = 1,
1962
+ max_retries: int = 0,
1963
+ ) -> bool:
1964
+ """Flips the camera image when called.
1965
+
1966
+ Args:
1967
+ serial (str): The camera serial.
1968
+ channel (int, optional): The camera channel number to flip. Defaults to 1.
1969
+ max_retries (int, optional): Number of retries attempted. Defaults to 0.
1970
+
1971
+ Raises:
1972
+ PyEzvizError: If max retries are exceeded or if the response indicates failure.
1973
+ HTTPError: If an HTTP error occurs (other than a 401, which triggers re-login).
1974
+
1975
+ Returns:
1976
+ bool: True if the operation was successful.
1977
+
1978
+ """
1979
+ if max_retries > MAX_RETRIES:
1980
+ raise PyEzvizError("Can't gather proper data. Max retries exceeded.")
1981
+
1982
+ try:
1983
+ req = self._session.put(
1984
+ url=f"https://{self._token['api_url']}{API_ENDPOINT_DEVICE_BASICS}{serial}/{channel}/CENTER/mirror",
1985
+ timeout=self._timeout,
1986
+ )
1987
+ req.raise_for_status()
1988
+
1989
+ except requests.HTTPError as err:
1990
+ if err.response.status_code == 401:
1991
+ # Session might be invalid; attempt to re-login and retry.
1992
+ self.login()
1993
+ return self.flip_image(serial, channel, max_retries + 1)
1994
+ raise HTTPError from err
1995
+
1996
+ try:
1997
+ json_output = req.json()
1998
+
1999
+ except ValueError as err:
2000
+ raise PyEzvizError("Could not decode response: " + str(err)) from err
2001
+
2002
+ if json_output.get("meta", {}).get("code") != 200:
2003
+ raise PyEzvizError(f"Could not flip image on camera: Got {json_output}")
2004
+
2005
+ return True
2006
+
2007
+ def set_camera_osd(
2008
+ self,
2009
+ serial: str,
2010
+ text: str = "",
2011
+ channel: int = 1,
2012
+ max_retries: int = 0,
2013
+ ) -> bool:
2014
+ """Set OSD (on screen display) text.
2015
+
2016
+ Args:
2017
+ serial (str): The camera serial.
2018
+ text (str, optional): The osd text to set. The default of "" will clear.
2019
+ channel (int, optional): The cammera channel to set this on. Defaults to 1.
2020
+ max_retries (int, optional): Number of retries attempted. Defaults to 0.
2021
+
2022
+ Raises:
2023
+ PyEzvizError: If max retries are exceeded or if the response indicates failure.
2024
+ HTTPError: If an HTTP error occurs (other than a 401, which triggers re-login).
2025
+
2026
+ Returns:
2027
+ bool: True if the operation was successful.
2028
+
2029
+ """
2030
+ if max_retries > MAX_RETRIES:
2031
+ raise PyEzvizError("Can't gather proper data. Max retries exceeded.")
2032
+
2033
+ try:
2034
+ req = self._session.put(
2035
+ url=f"https://{self._token['api_url']}{API_ENDPOINT_OSD}{serial}/{channel}/osd",
2036
+ data={"osd": text},
2037
+ timeout=self._timeout,
2038
+ )
2039
+ req.raise_for_status()
2040
+
2041
+ except requests.HTTPError as err:
2042
+ if err.response.status_code == 401:
2043
+ # Session might be invalid; attempt to re-login and retry.
2044
+ self.login()
2045
+ return self.set_camera_osd(serial, text, channel, max_retries + 1)
2046
+ raise HTTPError from err
2047
+
2048
+ try:
2049
+ json_output = req.json()
2050
+
2051
+ except ValueError as err:
2052
+ raise PyEzvizError("Could not decode response: " + str(err)) from err
2053
+
2054
+ if json_output.get("meta", {}).get("code") != 200:
2055
+ raise PyEzvizError(f"Could set osd message on camera: Got {json_output}")
2056
+
2057
+ return True
2058
+
1887
2059
  def set_floodlight_brightness(
1888
2060
  self,
1889
2061
  serial: str,
@@ -1,4 +1,5 @@
1
1
  """Device switch types relationship."""
2
+
2
3
  from enum import Enum, unique
3
4
 
4
5
  FEATURE_CODE = "1fc28fa018178a1cd1c091b13b2f9f02"
@@ -305,6 +306,10 @@ class SupportExt(Enum):
305
306
  SupportWifiLock = 541
306
307
  SupportWifiManager = 239
307
308
  SupportWifiPortal = 43
309
+ SupportWorkModeList = 502
310
+ SupportSensitiveUnderDefenceType = 444
311
+ SupportDefenceTypeFull = 534
312
+ SupportDetectAreaUnderDefencetype = 504
308
313
 
309
314
 
310
315
  @unique
@@ -330,12 +335,22 @@ class DefenseModeType(Enum):
330
335
 
331
336
 
332
337
  @unique
333
- class IntelligentDetectionMode(Enum):
334
- """Intelligent detection modes."""
338
+ class AlarmDetectHumanCar(Enum):
339
+ """Detection modes for cameras that support AlarmDetectHumanCar."""
340
+
341
+ DETECTION_MODE_HUMAN_SHAPE = 1
342
+ DETECTION_MODE_PIR = 5
343
+ DETECTION_MODE_IMAGE_CHANGE = 3
344
+
345
+
346
+ @unique
347
+ class IntelligentDetectionSmartApp(Enum):
348
+ """Intelligent detection modes for cameras using smart apps."""
335
349
 
336
- INTELLI_MODE_HUMAN_SHAPE = 1
337
- INTELLI_MODE_PIR = 5
338
- INTELLI_MODE_IMAGE_CHANGE = 3
350
+ app_human_detect = 1
351
+ app_video_change = 4
352
+ app_car_detect = 2
353
+ app_wave_recognize = 64
339
354
 
340
355
 
341
356
  @unique
@@ -365,7 +380,7 @@ class BatteryCameraWorkMode(Enum):
365
380
  POWER_SAVE = 0
366
381
  SUPER_POWER_SAVE = 3
367
382
  CUSTOM = 4
368
- HYBERNATE = 5 #not sure
383
+ HYBERNATE = 5 # not sure
369
384
  UNKNOWN = -1
370
385
 
371
386
 
@@ -1,4 +1,5 @@
1
- """pyezviz camera api."""
1
+ """Ezviz camera api."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import json
@@ -16,7 +17,7 @@ class EzvizLightBulb:
16
17
  """Initialize Ezviz Light Bulb object."""
17
18
 
18
19
  def __init__(
19
- self, client: EzvizClient, serial: str, device_obj: dict | None = None
20
+ self, client: EzvizClient, serial: str, device_obj: dict | None = None
20
21
  ) -> None:
21
22
  """Initialize the light bulb object."""
22
23
  self._client = client
@@ -30,7 +31,9 @@ class EzvizLightBulb:
30
31
  }
31
32
  if DeviceSwitchType.ALARM_LIGHT.value not in self._switch:
32
33
  # trying to have same interface as the camera's light
33
- self._switch[DeviceSwitchType.ALARM_LIGHT.value] = self.get_feature_item("light_switch")["dataValue"]
34
+ self._switch[DeviceSwitchType.ALARM_LIGHT.value] = self.get_feature_item(
35
+ "light_switch"
36
+ )["dataValue"]
34
37
 
35
38
  def fetch_key(self, keys: list, default_value: Any = None) -> Any:
36
39
  """Fetch dictionary key."""
@@ -39,15 +42,15 @@ class EzvizLightBulb:
39
42
  def _local_ip(self) -> Any:
40
43
  """Fix empty ip value for certain cameras."""
41
44
  if (
42
- self.fetch_key(["WIFI", "address"])
43
- and self._device["WIFI"]["address"] != "0.0.0.0"
45
+ self.fetch_key(["WIFI", "address"])
46
+ and self._device["WIFI"]["address"] != "0.0.0.0"
44
47
  ):
45
48
  return self._device["WIFI"]["address"]
46
49
 
47
50
  # Seems to return none or 0.0.0.0 on some.
48
51
  if (
49
- self.fetch_key(["CONNECTION", "localIp"])
50
- and self._device["CONNECTION"]["localIp"] != "0.0.0.0"
52
+ self.fetch_key(["CONNECTION", "localIp"])
53
+ and self._device["CONNECTION"]["localIp"] != "0.0.0.0"
51
54
  ):
52
55
  return self._device["CONNECTION"]["localIp"]
53
56
 
@@ -59,20 +62,19 @@ class EzvizLightBulb:
59
62
  json_output = json.loads(self._device["FEATURE"]["featureJson"])
60
63
 
61
64
  except ValueError as err:
62
- raise PyEzvizError(
63
- "Impossible to decode FEATURE: "
64
- + str(err)
65
- ) from err
65
+ raise PyEzvizError("Impossible to decode FEATURE: " + str(err)) from err
66
66
 
67
67
  return json_output
68
68
 
69
- def get_feature_item(self, key: str, default_value: Any = { "dataValue" : "" }) -> Any:
70
- """Get items fron FEATURE."""
69
+ def get_feature_item(self, key: str, default_value: Any = None) -> Any:
70
+ """Get items from FEATURE."""
71
71
  items = self._feature_json["featureItemDtos"]
72
+
72
73
  for item in items:
73
74
  if item["itemKey"] == key:
74
75
  return item
75
- return default_value
76
+
77
+ return default_value if default_value else {"dataValue": ""}
76
78
 
77
79
  def get_product_id(self) -> Any:
78
80
  """Get product id."""
@@ -104,23 +106,46 @@ class EzvizLightBulb:
104
106
  "optionals": self.fetch_key(["STATUS", "optionals"]),
105
107
  "supportExt": self._device["deviceInfos"]["supportExt"],
106
108
  "ezDeviceCapability": self.fetch_key(["deviceInfos", "ezDeviceCapability"]),
107
-
108
109
  "featureItems": self._feature_json["featureItemDtos"],
109
110
  "productId": self._feature_json["productId"],
110
- "color_temperature": self.get_feature_item("color_temperature")["dataValue"],
111
-
111
+ "color_temperature": self.get_feature_item("color_temperature")[
112
+ "dataValue"
113
+ ],
112
114
  "is_on": self.get_feature_item("light_switch")["dataValue"],
113
115
  "brightness": self.get_feature_item("brightness")["dataValue"],
114
116
  # same as brightness... added in order to keep "same interface" between camera and light bulb objects
115
117
  "alarm_light_luminance": self.get_feature_item("brightness")["dataValue"],
116
118
  }
117
119
 
118
- def toggle_switch(self) -> bool:
119
- """Toggle on/off light bulb."""
120
+ def _write_state(self, state: bool | None = None) -> bool:
121
+ """Set the light bulb state."""
120
122
  item = self.get_feature_item("light_switch")
123
+
121
124
  return self._client.set_device_feature_by_key(
122
125
  self._serial,
123
126
  self.get_product_id(),
124
- not bool(item["dataValue"]),
125
- item["itemKey"]
127
+ state if state else not bool(item["dataValue"]),
128
+ item["itemKey"],
129
+ )
130
+
131
+ def set_brightness(self, value: int) -> bool:
132
+ """Set the light bulb brightness.
133
+
134
+ The value must be in range 1-100.
135
+
136
+ """
137
+ return self._client.set_device_feature_by_key(
138
+ self._serial, self.get_product_id(), value, "brightness"
126
139
  )
140
+
141
+ def toggle_switch(self) -> bool:
142
+ """Toggle on/off light bulb."""
143
+ return self._write_state()
144
+
145
+ def power_on(self) -> bool:
146
+ """Power the light bulb on."""
147
+ return self._write_state(True)
148
+
149
+ def power_off(self) -> bool:
150
+ """Power the light bulb off."""
151
+ return self._write_state(False)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pyezvizapi
3
- Version: 1.0.0.7
3
+ Version: 1.0.0.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.0.7",
8
+ version="1.0.0.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