pyezvizapi 1.0.0.0__py3-none-any.whl

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.

pyezvizapi/__init__.py ADDED
@@ -0,0 +1,54 @@
1
+ """init pyezvizapi."""
2
+ from .camera import EzvizCamera
3
+ from .cas import EzvizCAS
4
+ from .client import EzvizClient
5
+ from .constants import (
6
+ BatteryCameraWorkMode,
7
+ DefenseModeType,
8
+ DeviceCatagories,
9
+ DeviceSwitchType,
10
+ DisplayMode,
11
+ IntelligentDetectionMode,
12
+ MessageFilterType,
13
+ NightVisionMode,
14
+ SoundMode,
15
+ SupportExt,
16
+ )
17
+ from .exceptions import (
18
+ AuthTestResultFailed,
19
+ EzvizAuthTokenExpired,
20
+ EzvizAuthVerificationCode,
21
+ HTTPError,
22
+ InvalidHost,
23
+ InvalidURL,
24
+ PyEzvizError,
25
+ )
26
+ from .light_bulb import EzvizLightBulb
27
+ from .mqtt import MQTTClient
28
+ from .test_cam_rtsp import TestRTSPAuth
29
+
30
+ __all__ = [
31
+ "EzvizCamera",
32
+ "EzvizClient",
33
+ "PyEzvizError",
34
+ "InvalidURL",
35
+ "HTTPError",
36
+ "InvalidHost",
37
+ "AuthTestResultFailed",
38
+ "EzvizAuthTokenExpired",
39
+ "EzvizAuthVerificationCode",
40
+ "EzvizCAS",
41
+ "EzvizLightBulb",
42
+ "MQTTClient",
43
+ "DefenseModeType",
44
+ "IntelligentDetectionMode",
45
+ "BatteryCameraWorkMode",
46
+ "DisplayMode",
47
+ "NightVisionMode",
48
+ "MessageFilterType",
49
+ "DeviceCatagories",
50
+ "DeviceSwitchType",
51
+ "SupportExt",
52
+ "SoundMode",
53
+ "TestRTSPAuth",
54
+ ]
pyezvizapi/__main__.py ADDED
@@ -0,0 +1,459 @@
1
+ """pyezvizapi command line."""
2
+ import argparse
3
+ import json
4
+ import logging
5
+ import sys
6
+ from typing import Any
7
+
8
+ import pandas as pd
9
+
10
+ from .camera import EzvizCamera
11
+ from .client import EzvizClient
12
+ from .constants import BatteryCameraWorkMode, DefenseModeType
13
+ from .exceptions import EzvizAuthVerificationCode
14
+ from .light_bulb import EzvizLightBulb
15
+ from .mqtt import MQTTClient
16
+
17
+
18
+ def main() -> Any:
19
+ """Initiate arg parser."""
20
+ parser = argparse.ArgumentParser(prog="pyezvizapi")
21
+ parser.add_argument("-u", "--username", required=True, help="Ezviz username")
22
+ parser.add_argument("-p", "--password", required=True, help="Ezviz Password")
23
+ parser.add_argument(
24
+ "-r",
25
+ "--region",
26
+ required=False,
27
+ default="apiieu.ezvizlife.com",
28
+ help="Ezviz API region",
29
+ )
30
+ parser.add_argument(
31
+ "--debug", "-d", action="store_true", help="Print debug messages to stderr"
32
+ )
33
+
34
+ subparsers = parser.add_subparsers(dest="action")
35
+
36
+ parser_device = subparsers.add_parser(
37
+ "devices", help="Play with all devices at once"
38
+ )
39
+ parser_device.add_argument(
40
+ "device_action",
41
+ type=str,
42
+ default="status",
43
+ help="Device action to perform",
44
+ choices=["device", "status", "switch", "connection"],
45
+ )
46
+
47
+ parser_device_lights = subparsers.add_parser(
48
+ "devices_light", help="Get all the light bulbs"
49
+ )
50
+ parser_device_lights.add_argument(
51
+ "devices_light_action",
52
+ type=str,
53
+ default="status",
54
+ help="Light bulbs action to perform",
55
+ choices=["status"]
56
+ )
57
+
58
+ parser_light = subparsers.add_parser("light", help="Light actions")
59
+ parser_light.add_argument("--serial", required=True, help="light bulb SERIAL")
60
+
61
+ subparsers_light = parser_light.add_subparsers(dest="light_action")
62
+ subparsers_light.add_parser("toggle", help="Toggle the light bulb")
63
+ subparsers_light.add_parser("status", help="Get information about the light bulb")
64
+
65
+ parser_home_defence_mode = subparsers.add_parser(
66
+ "home_defence_mode", help="Set home defence mode"
67
+ )
68
+
69
+ subparsers.add_parser("mqtt", help="Connect to mqtt push notifications")
70
+
71
+ parser_home_defence_mode.add_argument(
72
+ "--mode", required=False, help="Choose mode", choices=["HOME_MODE", "AWAY_MODE"]
73
+ )
74
+
75
+ parser_camera = subparsers.add_parser("camera", help="Camera actions")
76
+ parser_camera.add_argument("--serial", required=True, help="camera SERIAL")
77
+
78
+ subparsers_camera = parser_camera.add_subparsers(dest="camera_action")
79
+
80
+ subparsers_camera.add_parser("status", help="Get the status of the camera")
81
+ parser_camera_move = subparsers_camera.add_parser("move", help="Move the camera")
82
+ parser_camera_move.add_argument(
83
+ "--direction",
84
+ required=True,
85
+ help="Direction to move the camera to",
86
+ choices=["up", "down", "right", "left"],
87
+ )
88
+ parser_camera_move.add_argument(
89
+ "--speed",
90
+ required=False,
91
+ help="Speed of the movement",
92
+ default=5,
93
+ type=int,
94
+ choices=range(1, 10),
95
+ )
96
+
97
+ parser_camera_move_coords = subparsers_camera.add_parser(
98
+ "move_coords", help="Move the camera to the X,Y coordinates"
99
+ )
100
+ parser_camera_move_coords.add_argument(
101
+ "--x",
102
+ required=True,
103
+ help="The X coordinate to move the camera to",
104
+ type=float,
105
+ )
106
+ parser_camera_move_coords.add_argument(
107
+ "--y",
108
+ required=True,
109
+ help="The Y coordinate to move the camera to",
110
+ type=float,
111
+ )
112
+
113
+ parser_camera_switch = subparsers_camera.add_parser(
114
+ "switch", help="Change the status of a switch"
115
+ )
116
+ parser_camera_switch.add_argument(
117
+ "--switch",
118
+ required=True,
119
+ help="Switch to switch",
120
+ choices=[
121
+ "audio",
122
+ "ir",
123
+ "state",
124
+ "privacy",
125
+ "sleep",
126
+ "follow_move",
127
+ "sound_alarm",
128
+ ],
129
+ )
130
+ parser_camera_switch.add_argument(
131
+ "--enable",
132
+ required=False,
133
+ help="Enable (or not)",
134
+ default=1,
135
+ type=int,
136
+ choices=[0, 1],
137
+ )
138
+
139
+ parser_camera_alarm = subparsers_camera.add_parser(
140
+ "alarm", help="Configure the camera alarm"
141
+ )
142
+ parser_camera_alarm.add_argument(
143
+ "--notify", required=False, help="Enable (or not)", type=int, choices=[0, 1]
144
+ )
145
+ parser_camera_alarm.add_argument(
146
+ "--sound",
147
+ required=False,
148
+ help="Sound level (2 is silent, 1 intensive, 0 soft)",
149
+ type=int,
150
+ choices=[0, 1, 2],
151
+ )
152
+ parser_camera_alarm.add_argument(
153
+ "--sensibility",
154
+ required=False,
155
+ help="Sensibility level (Non-Cameras = from 1 to 6) or (Cameras = 1 to 100)",
156
+ type=int,
157
+ choices=range(100),
158
+ )
159
+ parser_camera_alarm.add_argument(
160
+ "--do_not_disturb",
161
+ required=False,
162
+ help="\
163
+ If alarm notifications are enabled in the EZViz app then movement normally causes a notification to be sent. \
164
+ Enabling this feature stops these notifications, i.e. you are not to be disturbed even if movement occurs. \
165
+ Care must be taken because do-not-disturb can not be reset using the mobile app. \
166
+ No new notifications will be sent until do-not-disturb is disabled. \
167
+ Movement is still recorded even if do-not-disturb is enabled.",
168
+ default=None,
169
+ type=int,
170
+ choices=[0, 1],
171
+ )
172
+ parser_camera_alarm.add_argument(
173
+ "--schedule", required=False, help="Schedule in json format *test*", type=str
174
+ )
175
+
176
+ parser_camera_select = subparsers_camera.add_parser(
177
+ "select", help="Change the value of a multi-value option (for on/off value, see 'switch' command)"
178
+ )
179
+
180
+ parser_camera_select.add_argument(
181
+ "--battery_work_mode",
182
+ required=False,
183
+ help="Change the work mode for battery powered camera",
184
+ choices=[mode.name for mode in BatteryCameraWorkMode if mode is not BatteryCameraWorkMode.UNKNOWN],
185
+ )
186
+
187
+ args = parser.parse_args()
188
+
189
+ # print("--------------args")
190
+ # print("--------------args: %s",args)
191
+ # print("--------------args")
192
+
193
+ client = EzvizClient(args.username, args.password, args.region)
194
+ try:
195
+ client.login()
196
+
197
+ except EzvizAuthVerificationCode:
198
+ mfa_code = input("MFA code required, please input MFA code.\n")
199
+ client.login(sms_code=mfa_code)
200
+
201
+ except Exception as exp: # pylint: disable=broad-except
202
+ print(exp)
203
+
204
+ if args.debug:
205
+ # You must initialize logging, otherwise you'll not see debug output.
206
+ logging.basicConfig()
207
+ logging.getLogger().setLevel(logging.DEBUG)
208
+ requests_log = logging.getLogger("requests.packages.urllib3")
209
+ requests_log.setLevel(logging.DEBUG)
210
+ requests_log.propagate = True
211
+
212
+ if args.action == "devices":
213
+
214
+ if args.device_action == "device":
215
+ try:
216
+ print(json.dumps(client.get_device(), indent=2))
217
+ except Exception as exp: # pylint: disable=broad-except
218
+ print(exp)
219
+ finally:
220
+ client.close_session()
221
+
222
+ elif args.device_action == "status":
223
+ try:
224
+ print(
225
+ pd.DataFrame.from_dict(
226
+ data=client.load_cameras(),
227
+ orient="index",
228
+ columns=[
229
+ "name",
230
+ # version,
231
+ # upgrade_available,
232
+ "status",
233
+ "device_category",
234
+ "device_sub_category",
235
+ "sleep",
236
+ "privacy",
237
+ "audio",
238
+ "ir_led",
239
+ "state_led",
240
+ # follow_move,
241
+ # alarm_notify,
242
+ # alarm_schedules_enabled,
243
+ # alarm_sound_mod,
244
+ # encrypted,
245
+ "local_ip",
246
+ "local_rtsp_port",
247
+ "detection_sensibility",
248
+ "battery_level",
249
+ "alarm_schedules_enabled",
250
+ "alarm_notify",
251
+ "Motion_Trigger",
252
+ # last_alarm_time,
253
+ # last_alarm_pic
254
+ ],
255
+ )
256
+ )
257
+ except Exception as exp: # pylint: disable=broad-except
258
+ print(exp)
259
+ finally:
260
+ client.close_session()
261
+
262
+ elif args.device_action == "switch":
263
+ try:
264
+ print(json.dumps(client.get_switch(), indent=2))
265
+ except Exception as exp: # pylint: disable=broad-except
266
+ print(exp)
267
+ finally:
268
+ client.close_session()
269
+
270
+ elif args.device_action == "connection":
271
+ try:
272
+ print(json.dumps(client.get_connection(), indent=2))
273
+ except Exception as exp: # pylint: disable=broad-except
274
+ print(exp)
275
+ finally:
276
+ client.close_session()
277
+
278
+ else:
279
+ print("Action not implemented: %s", args.device_action)
280
+
281
+ elif args.action == "devices_light":
282
+ if args.devices_light_action == "status":
283
+ try:
284
+ print(
285
+ pd.DataFrame.from_dict(
286
+ data=client.load_light_bulbs(),
287
+ orient="index",
288
+ columns=[
289
+ "name",
290
+ # "version",
291
+ # "upgrade_available",
292
+ "status",
293
+ "device_category",
294
+ "device_sub_category",
295
+ "local_ip",
296
+ "productId",
297
+ "is_on",
298
+ "brightness",
299
+ "color_temperature",
300
+ ],
301
+ )
302
+ )
303
+ except Exception as exp: # pylint: disable=broad-except
304
+ print(exp)
305
+ finally:
306
+ client.close_session()
307
+
308
+ elif args.action == "light":
309
+ # load light bulb object
310
+ try:
311
+ light_bulb = EzvizLightBulb(client, args.serial)
312
+ logging.debug("Light bulb loaded")
313
+ except Exception as exp: # pylint: disable=broad-except
314
+ print(exp)
315
+ client.close_session()
316
+
317
+ if args.light_action == "toggle":
318
+ try:
319
+ light_bulb.toggle_switch()
320
+ except Exception as exp: # pylint: disable=broad-except
321
+ print(exp)
322
+ finally:
323
+ client.close_session()
324
+
325
+ elif args.light_action == "status":
326
+ try:
327
+ print(json.dumps(light_bulb.status(), indent=2))
328
+
329
+ except Exception as exp: # pylint: disable=broad-except
330
+ print(exp)
331
+ finally:
332
+ client.close_session()
333
+
334
+ elif args.action == "home_defence_mode":
335
+
336
+ if args.mode:
337
+ try:
338
+ print(
339
+ json.dumps(
340
+ client.api_set_defence_mode(
341
+ getattr(DefenseModeType, args.mode).value
342
+ ),
343
+ indent=2,
344
+ )
345
+ )
346
+ except Exception as exp: # pylint: disable=broad-except
347
+ print(exp)
348
+ finally:
349
+ client.close_session()
350
+
351
+ elif args.action == "mqtt":
352
+
353
+ logging.basicConfig()
354
+ logging.getLogger().setLevel(logging.DEBUG)
355
+
356
+ try:
357
+ token = client.login()
358
+ mqtt = MQTTClient(token)
359
+ mqtt.start()
360
+
361
+ except Exception as exp: # pylint: disable=broad-except
362
+ print(exp)
363
+ finally:
364
+ client.close_session()
365
+
366
+ elif args.action == "camera":
367
+
368
+ # load camera object
369
+ try:
370
+ camera = EzvizCamera(client, args.serial)
371
+ logging.debug("Camera loaded")
372
+ except Exception as exp: # pylint: disable=broad-except
373
+ print(exp)
374
+ client.close_session()
375
+
376
+ if args.camera_action == "move":
377
+ try:
378
+ camera.move(args.direction, args.speed)
379
+ except Exception as exp: # pylint: disable=broad-except
380
+ print(exp)
381
+ finally:
382
+ client.close_session()
383
+
384
+ elif args.camera_action == "move_coords":
385
+ try:
386
+ camera.move_coordinates(args.x, args.y)
387
+ except Exception as exp: # pylint: disable=broad-except
388
+ print(exp)
389
+ finally:
390
+ client.close_session()
391
+
392
+ elif args.camera_action == "status":
393
+ try:
394
+ print(json.dumps(camera.status(), indent=2))
395
+
396
+ except Exception as exp: # pylint: disable=broad-except
397
+ print(exp)
398
+ finally:
399
+ client.close_session()
400
+
401
+ elif args.camera_action == "switch":
402
+ try:
403
+ if args.switch == "ir":
404
+ camera.switch_device_ir_led(args.enable)
405
+ elif args.switch == "state":
406
+ print(args.enable)
407
+ camera.switch_device_state_led(args.enable)
408
+ elif args.switch == "audio":
409
+ camera.switch_device_audio(args.enable)
410
+ elif args.switch == "privacy":
411
+ camera.switch_privacy_mode(args.enable)
412
+ elif args.switch == "sleep":
413
+ camera.switch_sleep_mode(args.enable)
414
+ elif args.switch == "follow_move":
415
+ camera.switch_follow_move(args.enable)
416
+ elif args.switch == "sound_alarm":
417
+ # Map 0|1 enable flog to operation type: 1 for off and 2 for on.
418
+ camera.switch_sound_alarm(args.enable + 1)
419
+ except Exception as exp: # pylint: disable=broad-except
420
+ print(exp)
421
+ finally:
422
+ client.close_session()
423
+
424
+ elif args.camera_action == "alarm":
425
+ try:
426
+ if args.sound is not None:
427
+ camera.alarm_sound(args.sound)
428
+ if args.notify is not None:
429
+ camera.alarm_notify(args.notify)
430
+ if args.sensibility is not None:
431
+ camera.alarm_detection_sensibility(args.sensibility)
432
+ if args.do_not_disturb is not None:
433
+ camera.do_not_disturb(args.do_not_disturb)
434
+ if args.schedule is not None:
435
+ camera.change_defence_schedule(args.schedule)
436
+ except Exception as exp: # pylint: disable=broad-except
437
+ print(exp)
438
+ finally:
439
+ client.close_session()
440
+
441
+ elif args.camera_action == "select":
442
+ try:
443
+ if args.battery_work_mode is not None:
444
+ camera.set_battery_camera_work_mode(getattr(BatteryCameraWorkMode, args.battery_work_mode))
445
+
446
+ except Exception as exp: # pylint: disable=broad-except
447
+ print(exp)
448
+ finally:
449
+ client.close_session()
450
+
451
+ else:
452
+ print("Action not implemented, try running with -h switch for help")
453
+
454
+ else:
455
+ print("Action not implemented: %s", args.action)
456
+
457
+
458
+ if __name__ == "__main__":
459
+ sys.exit(main())
@@ -0,0 +1,52 @@
1
+ """API endpoints."""
2
+
3
+ # API Endpoints
4
+ API_ENDPOINT_CLOUDDEVICES = "/api/cloud/v2/cloudDevices/getAll"
5
+
6
+ API_ENDPOINT_LOGIN = "/v3/users/login/v5"
7
+ API_ENDPOINT_LOGOUT = "/v3/users/logout/v2"
8
+ API_ENDPOINT_REFRESH_SESSION_ID = "/v3/apigateway/login"
9
+ API_ENDPOINT_SERVER_INFO = "/v3/configurations/system/info"
10
+ API_ENDPOINT_USER_ID = "/v3/userdevices/v1/token"
11
+ API_ENDPOINT_GROUP_DEFENCE_MODE = "/v3/userdevices/v1/group/defenceMode"
12
+
13
+ API_ENDPOINT_PANORAMIC_DEVICES_OPERATION = "/v3/panoramicDevices/operation"
14
+ API_ENDPOINT_UPGRADE_DEVICE = "/v3/upgrades/v1/devices/"
15
+ API_ENDPOINT_SEND_CODE = "/v3/sms/nologin/checkcode"
16
+
17
+ API_ENDPOINT_ALARMINFO_GET = "/v3/alarms/v2/advanced"
18
+ API_ENDPOINT_UNIFIEDMSG_LIST_GET = "/v3/unifiedmsg/list"
19
+ API_ENDPOINT_V3_ALARMS = "/v3/alarms/"
20
+ API_ENDPOINT_SET_LUMINANCE = "/v3/alarms/device/alarmLight"
21
+
22
+ API_ENDPOINT_PAGELIST = "/v3/userdevices/v1/resources/pagelist"
23
+ API_ENDPOINT_SWITCH_DEFENCE_MODE = "/v3/userdevices/v1/group/switchDefenceMode"
24
+
25
+ API_ENDPOINT_DETECTION_SENSIBILITY = "/api/device/configAlgorithm"
26
+ API_ENDPOINT_DETECTION_SENSIBILITY_GET = "/api/device/queryAlgorithmConfig"
27
+ API_ENDPOINT_SET_DEFENCE_SCHEDULE = "/api/device/defence/plan2"
28
+ API_ENDPOINT_CAM_ENCRYPTKEY = "/api/device/query/encryptkey"
29
+ API_ENDPOINT_CANCEL_ALARM = "/api/device/cancelAlarm"
30
+ API_ENDPOINT_DEVICE_SYS_OPERATION = "/api/device/v2/sysOper/"
31
+ API_ENDPOINT_DEVICE_STORAGE_STATUS = "/api/device/queryStorageStatus"
32
+ API_ENDPOINT_DEVCONFIG_BY_KEY = "/v3/devconfig/v1/keyValue/"
33
+ API_ENDPOINT_IOT_FEATURE = "/v3/iot-feature/feature/"
34
+
35
+ # Videogo DeviceApi
36
+ API_ENDPOINT_DEVICES = "/v3/devices/"
37
+ API_ENDPOINT_SWITCH_STATUS = "/switchStatus"
38
+ API_ENDPOINT_SWITCH_OTHER = "/switch"
39
+ API_ENDPOINT_PTZCONTROL = "/ptzControl"
40
+ API_ENDPOINT_ALARM_SOUND = "/alarm/sound"
41
+ API_ENDPOINT_SWITCH_SOUND_ALARM = "/sendAlarm"
42
+ API_ENDPOINT_DO_NOT_DISTURB = "/nodisturb"
43
+ API_ENDPOINT_VIDEO_ENCRYPT = "encryptedInfo/risk"
44
+ API_ENDPOINT_CHANGE_DEFENCE_STATUS = "changeDefenceStatusReq"
45
+
46
+ API_ENDPOINT_CREATE_PANORAMIC = "/api/panoramic/devices/pics/collect"
47
+ API_ENDPOINT_RETURN_PANORAMIC = "/api/panoramic/devices/pics"
48
+
49
+ # MQTT
50
+ API_ENDPOINT_REGISTER_MQTT = "/v1/getClientId"
51
+ API_ENDPOINT_START_MQTT = "/api/push/start"
52
+ API_ENDPOINT_STOP_MQTT = "/api/push/stop"