wyzeapy 0.5.28__py3-none-any.whl → 0.5.30__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.
@@ -12,49 +12,163 @@ from typing import List, Tuple, Any, Dict, Optional
12
12
  import aiohttp
13
13
 
14
14
  from .update_manager import DeviceUpdater, UpdateManager
15
- from ..const import PHONE_SYSTEM_TYPE, APP_VERSION, APP_VER, PHONE_ID, APP_NAME, OLIVE_APP_ID, APP_INFO, SC, SV, APP_PLATFORM, SOURCE
15
+ from ..const import (
16
+ PHONE_SYSTEM_TYPE,
17
+ APP_VERSION,
18
+ APP_VER,
19
+ PHONE_ID,
20
+ APP_NAME,
21
+ OLIVE_APP_ID,
22
+ APP_INFO,
23
+ SC,
24
+ SV,
25
+ APP_PLATFORM,
26
+ SOURCE,
27
+ )
16
28
  from ..crypto import olive_create_signature
17
- from ..payload_factory import olive_create_hms_patch_payload, olive_create_hms_payload, \
18
- olive_create_hms_get_payload, ford_create_payload, olive_create_get_payload, olive_create_post_payload, \
19
- olive_create_user_info_payload, devicemgmt_create_capabilities_payload, devicemgmt_get_iot_props_list
29
+ from ..payload_factory import (
30
+ olive_create_hms_patch_payload,
31
+ olive_create_hms_payload,
32
+ olive_create_hms_get_payload,
33
+ ford_create_payload,
34
+ olive_create_get_payload,
35
+ olive_create_post_payload,
36
+ olive_create_user_info_payload,
37
+ devicemgmt_create_capabilities_payload,
38
+ devicemgmt_get_iot_props_list,
39
+ olive_create_get_payload_irrigation,
40
+ olive_create_post_payload_irrigation_stop,
41
+ olive_create_post_payload_irrigation_quickrun,
42
+ )
20
43
  from ..types import PropertyIDs, Device, DeviceMgmtToggleType
21
- from ..utils import check_for_errors_standard, check_for_errors_hms, check_for_errors_lock, \
22
- check_for_errors_iot, wyze_encrypt, check_for_errors_devicemgmt
44
+ from ..utils import (
45
+ check_for_errors_standard,
46
+ check_for_errors_hms,
47
+ check_for_errors_lock,
48
+ check_for_errors_iot,
49
+ wyze_encrypt,
50
+ check_for_errors_devicemgmt,
51
+ )
23
52
  from ..wyze_auth_lib import WyzeAuthLib
24
53
 
54
+ """
55
+ BaseService provides shared functionality for Wyze device services,
56
+ including authentication, device discovery, and automatic updates.
57
+ """
58
+
25
59
  _LOGGER = logging.getLogger(__name__)
26
60
 
27
61
 
28
62
  class BaseService:
63
+ """Base service class providing common functionality for all Wyze device services.
64
+
65
+ This abstract base class provides shared infrastructure for interacting with Wyze devices
66
+ including authentication, API communication, device discovery, and automatic updates.
67
+ All device-specific service classes (BulbService, SwitchService, etc.) inherit from this class.
68
+
69
+ **Key Features:**
70
+ * Device discovery and caching via `get_object_list()`
71
+ * Automatic device updates with configurable intervals
72
+ * Authentication token management and refresh
73
+ * Common API endpoint wrappers for device properties and actions
74
+ * Error handling and validation for API responses
75
+ * Support for both cloud and local device communication
76
+
77
+ **Common Usage Patterns:**
78
+ ```python
79
+ # Device services inherit from BaseService
80
+ bulb_service = await wyze.bulb_service
81
+
82
+ # Get all devices (cached after first call)
83
+ devices = await bulb_service.get_object_list()
84
+
85
+ # Register for automatic updates
86
+ bulb_service.register_updater(device, interval=30)
87
+ ```
88
+
89
+ **Note:** This class is not meant to be instantiated directly - use device-specific services instead.
90
+ """
91
+
29
92
  _devices: Optional[List[Device]] = None
30
- _last_updated_time: time = 0 # preload a value of 0 so that comparison will succeed on the first run
93
+ _last_updated_time: time = (
94
+ 0 # preload a value of 0 so that comparison will succeed on the first run
95
+ )
31
96
  _min_update_time = 1200 # lets let the device_params update every 20 minutes for now. This could probably reduced signicficantly.
32
- _update_lock: asyncio.Lock = asyncio.Lock() # fmt: skip
97
+ _update_lock: asyncio.Lock = asyncio.Lock() # fmt: skip
33
98
  _update_manager: UpdateManager = UpdateManager()
34
99
  _update_loop = None
35
100
  _updater: DeviceUpdater = None
36
101
  _updater_dict = {}
37
102
 
38
103
  def __init__(self, auth_lib: WyzeAuthLib):
104
+ """Initialize the base service with authentication.
105
+
106
+ **Args:**
107
+ * `auth_lib` (WyzeAuthLib): The authentication library for API access
108
+ """
39
109
  self._auth_lib = auth_lib
40
110
 
41
111
  @staticmethod
42
112
  async def start_update_manager():
113
+ """Start the global update manager for automatic device state updates.
114
+
115
+ This initializes the background update system that handles periodic
116
+ device state refreshes for all registered devices.
117
+
118
+ **Example:**
119
+ ```python
120
+ await BaseService.start_update_manager()
121
+ ```
122
+ """
43
123
  if BaseService._update_loop is None:
44
124
  BaseService._update_loop = asyncio.get_event_loop()
45
- BaseService._update_loop.create_task(BaseService._update_manager.update_next())
125
+ BaseService._update_loop.create_task(
126
+ BaseService._update_manager.update_next()
127
+ )
46
128
 
47
129
  def register_updater(self, device: Device, interval):
130
+ """Register a device for automatic status updates at a specified interval.
131
+
132
+ This enables automatic background updates for a device, periodically refreshing
133
+ its state from the Wyze servers. Useful for keeping device status current.
134
+
135
+ **Args:**
136
+ * `device` (Device): The device to register for automatic updates
137
+ * `interval` (int): Update interval in seconds
138
+
139
+ **Example:**
140
+ ```python
141
+ # Update device state every 30 seconds
142
+ service.register_updater(device, 30)
143
+ ```
144
+ """
48
145
  self._updater = DeviceUpdater(self, device, interval)
49
146
  BaseService._update_manager.add_updater(self._updater)
50
147
  self._updater_dict[self._updater.device] = self._updater
51
148
 
52
149
  def unregister_updater(self, device: Device):
150
+ """Stop automatic updates for a device.
151
+
152
+ This removes a device from the automatic update system to stop
153
+ background status refreshes.
154
+
155
+ **Args:**
156
+ * `device` (Device): The device to stop updating automatically
157
+
158
+ **Example:**
159
+ ```python
160
+ service.unregister_updater(device)
161
+ ```
162
+ """
53
163
  if self._updater:
54
164
  BaseService._update_manager.del_updater(self._updater_dict[device])
55
165
  del self._updater_dict[device]
56
166
 
57
- async def set_push_info(self, on: bool) -> None:
167
+ async def set_push_info(self, on: bool):
168
+ """Set push info for the user.
169
+
170
+ :param on: Whether to enable or disable push notifications.
171
+ """
58
172
  await self._auth_lib.refresh_if_should()
59
173
 
60
174
  url = "https://api.wyzecam.com/app/user/set_push_info"
@@ -68,7 +182,7 @@ class BaseService:
68
182
  "sv": SV,
69
183
  "access_token": self._auth_lib.token.access_token,
70
184
  "phone_id": PHONE_ID,
71
- "app_name": APP_NAME
185
+ "app_name": APP_NAME,
72
186
  }
73
187
 
74
188
  response_json = await self._auth_lib.post(url, json=payload)
@@ -76,31 +190,49 @@ class BaseService:
76
190
  check_for_errors_standard(self, response_json)
77
191
 
78
192
  async def get_user_profile(self) -> Dict[Any, Any]:
193
+ """Get user profile.
194
+
195
+ :return: User profile.
196
+ """
79
197
  await self._auth_lib.refresh_if_should()
80
198
 
81
199
  payload = olive_create_user_info_payload()
82
200
  signature = olive_create_signature(payload, self._auth_lib.token.access_token)
83
201
  headers = {
84
- 'Accept-Encoding': 'gzip',
85
- 'User-Agent': 'myapp',
86
- 'appid': OLIVE_APP_ID,
87
- 'appinfo': APP_INFO,
88
- 'phoneid': PHONE_ID,
89
- 'access_token': self._auth_lib.token.access_token,
90
- 'signature2': signature
202
+ "Accept-Encoding": "gzip",
203
+ "User-Agent": "myapp",
204
+ "appid": OLIVE_APP_ID,
205
+ "appinfo": APP_INFO,
206
+ "phoneid": PHONE_ID,
207
+ "access_token": self._auth_lib.token.access_token,
208
+ "signature2": signature,
91
209
  }
92
210
 
93
- url = 'https://wyze-platform-service.wyzecam.com/app/v2/platform/get_user_profile'
211
+ url = (
212
+ "https://wyze-platform-service.wyzecam.com/app/v2/platform/get_user_profile"
213
+ )
94
214
 
95
215
  response_json = await self._auth_lib.get(url, headers=headers, params=payload)
96
216
 
97
217
  return response_json
98
218
 
99
219
  async def get_object_list(self) -> List[Device]:
100
- """
101
- Wraps the api.wyzecam.com/app/v2/home_page/get_object_list endpoint
220
+ """Discover and retrieve all devices associated with the Wyze account.
221
+
222
+ This method fetches all devices from the Wyze API and caches them for
223
+ efficient subsequent access. Results are shared across all service instances.
224
+
225
+ **Returns:**
226
+ * `List[Device]`: List of all discovered Wyze devices
227
+
228
+ **Example:**
229
+ ```python
230
+ devices = await service.get_object_list()
231
+ for device in devices:
232
+ print(f"Device: {device.nickname} ({device.product_model})")
233
+ ```
102
234
 
103
- :return: List of devices
235
+ **Note:** Results are cached and shared across all BaseService instances
104
236
  """
105
237
  await self._auth_lib.refresh_if_should()
106
238
 
@@ -113,19 +245,29 @@ class BaseService:
113
245
  "sv": "9d74946e652647e9b6c9d59326aef104",
114
246
  "access_token": self._auth_lib.token.access_token,
115
247
  "phone_id": PHONE_ID,
116
- "app_name": APP_NAME
248
+ "app_name": APP_NAME,
117
249
  }
118
250
 
119
- response_json = await self._auth_lib.post("https://api.wyzecam.com/app/v2/home_page/get_object_list",
120
- json=payload)
251
+ response_json = await self._auth_lib.post(
252
+ "https://api.wyzecam.com/app/v2/home_page/get_object_list", json=payload
253
+ )
121
254
 
122
255
  check_for_errors_standard(self, response_json)
123
256
  # Cache the devices so that update calls can pull more recent device_params
124
- BaseService._devices = [Device(device) for device in response_json['data']['device_list']]
257
+ BaseService._devices = [
258
+ Device(device) for device in response_json["data"]["device_list"]
259
+ ]
125
260
 
126
261
  return BaseService._devices
127
262
 
128
- async def get_updated_params(self, device_mac: str = None) -> Dict[str, Optional[Any]]:
263
+ async def get_updated_params(
264
+ self, device_mac: str = None
265
+ ) -> Dict[str, Optional[Any]]:
266
+ """Get updated params for a device.
267
+
268
+ :param device_mac: The device mac to get updated params for.
269
+ :return: Updated params for the device.
270
+ """
129
271
  if time.time() - BaseService._last_updated_time >= BaseService._min_update_time:
130
272
  await self.get_object_list()
131
273
  BaseService._last_updated_time = time.time()
@@ -136,8 +278,7 @@ class BaseService:
136
278
  return ret_params
137
279
 
138
280
  async def _get_property_list(self, device: Device) -> List[Tuple[PropertyIDs, Any]]:
139
- """
140
- Wraps the api.wyzecam.com/app/v2/device/get_property_list endpoint
281
+ """Wraps the api.wyzecam.com/app/v2/device/get_property_list endpoint
141
282
 
142
283
  :param device: Device to get properties for
143
284
  :return: List of PropertyIDs and values
@@ -157,34 +298,30 @@ class BaseService:
157
298
  "app_name": APP_NAME,
158
299
  "device_model": device.product_model,
159
300
  "device_mac": device.mac,
160
- "target_pid_list": []
301
+ "target_pid_list": [],
161
302
  }
162
303
 
163
- response_json = await self._auth_lib.post("https://api.wyzecam.com/app/v2/device/get_property_list",
164
- json=payload)
304
+ response_json = await self._auth_lib.post(
305
+ "https://api.wyzecam.com/app/v2/device/get_property_list", json=payload
306
+ )
165
307
 
166
308
  check_for_errors_standard(self, response_json)
167
- properties = response_json['data']['property_list']
309
+ properties = response_json["data"]["property_list"]
168
310
  property_list = []
169
311
  for prop in properties:
170
312
  try:
171
- property_id = PropertyIDs(prop['pid'])
172
- property_list.append((
173
- property_id,
174
- prop['value']
175
- ))
313
+ property_id = PropertyIDs(prop["pid"])
314
+ property_list.append((property_id, prop["value"]))
176
315
  except ValueError:
177
316
  pass
178
317
 
179
318
  return property_list
180
319
 
181
- async def _set_property_list(self, device: Device, plist: List[Dict[str, str]]) -> None:
182
- """
183
- Wraps the api.wyzecam.com/app/v2/device/set_property_list endpoint
320
+ async def _set_property_list(self, device: Device, plist: List[Dict[str, str]]):
321
+ """Wraps the api.wyzecam.com/app/v2/device/set_property_list endpoint
184
322
 
185
323
  :param device: The device for which to set the property(ies)
186
324
  :param plist: A list of properties [{"pid": pid, "pvalue": pvalue},...]
187
- :return:
188
325
  """
189
326
 
190
327
  await self._auth_lib.refresh_if_should()
@@ -201,17 +338,17 @@ class BaseService:
201
338
  "app_name": APP_NAME,
202
339
  "property_list": plist,
203
340
  "device_model": device.product_model,
204
- "device_mac": device.mac
341
+ "device_mac": device.mac,
205
342
  }
206
343
 
207
- response_json = await self._auth_lib.post("https://api.wyzecam.com/app/v2/device/set_property_list",
208
- json=payload)
344
+ response_json = await self._auth_lib.post(
345
+ "https://api.wyzecam.com/app/v2/device/set_property_list", json=payload
346
+ )
209
347
 
210
348
  check_for_errors_standard(self, response_json)
211
349
 
212
- async def _run_action_list(self, device: Device, plist: List[Dict[Any, Any]]) -> None:
213
- """
214
- Wraps the api.wyzecam.com/app/v2/auto/run_action_list endpoint
350
+ async def _run_action_list(self, device: Device, plist: List[Dict[Any, Any]]):
351
+ """Wraps the api.wyzecam.com/app/v2/auto/run_action_list endpoint
215
352
 
216
353
  :param device: The device for which to run the action list
217
354
  :param plist: A list of properties [{"pid": pid, "pvalue": pvalue},...]
@@ -231,31 +368,24 @@ class BaseService:
231
368
  "action_list": [
232
369
  {
233
370
  "instance_id": device.mac,
234
- "action_params": {
235
- "list": [
236
- {
237
- "mac": device.mac,
238
- "plist": plist
239
- }
240
- ]
241
- },
371
+ "action_params": {"list": [{"mac": device.mac, "plist": plist}]},
242
372
  "provider_key": device.product_model,
243
- "action_key": "set_mesh_property"
373
+ "action_key": "set_mesh_property",
244
374
  }
245
- ]
375
+ ],
246
376
  }
247
377
 
248
- response_json = await self._auth_lib.post("https://api.wyzecam.com/app/v2/auto/run_action_list",
249
- json=payload)
378
+ response_json = await self._auth_lib.post(
379
+ "https://api.wyzecam.com/app/v2/auto/run_action_list", json=payload
380
+ )
250
381
 
251
382
  check_for_errors_standard(self, response_json)
252
383
 
253
384
  async def _get_event_list(self, count: int) -> Dict[Any, Any]:
254
- """
255
- Wraps the api.wyzecam.com/app/v2/device/get_event_list endpoint
385
+ """Wraps the api.wyzecam.com/app/v2/device/get_event_list endpoint
256
386
 
257
387
  :param count: Number of events to gather
258
- :return: Response from the server
388
+ :return: Response from the server after being validated
259
389
  """
260
390
 
261
391
  await self._auth_lib.refresh_if_should()
@@ -268,12 +398,7 @@ class BaseService:
268
398
  "count": count,
269
399
  "app_version": APP_VERSION,
270
400
  "order_by": 2,
271
- "event_value_list": [
272
- "1",
273
- "13",
274
- "10",
275
- "12"
276
- ],
401
+ "event_value_list": ["1", "13", "10", "12"],
277
402
  "sc": "9f275790cab94a72bd206c8876429f3c",
278
403
  "device_mac_list": [],
279
404
  "event_tag_list": [],
@@ -283,22 +408,21 @@ class BaseService:
283
408
  "app_ver": APP_VER,
284
409
  "ts": 1623612037763,
285
410
  "device_mac": "",
286
- "access_token": self._auth_lib.token.access_token
411
+ "access_token": self._auth_lib.token.access_token,
287
412
  }
288
413
 
289
- response_json = await self._auth_lib.post("https://api.wyzecam.com/app/v2/device/get_event_list",
290
- json=payload)
414
+ response_json = await self._auth_lib.post(
415
+ "https://api.wyzecam.com/app/v2/device/get_event_list", json=payload
416
+ )
291
417
 
292
418
  check_for_errors_standard(self, response_json)
293
419
  return response_json
294
420
 
295
- async def _run_action(self, device: Device, action: str) -> None:
296
- """
297
- Wraps the api.wyzecam.com/app/v2/auto/run_action endpoint
421
+ async def _run_action(self, device: Device, action: str):
422
+ """Wraps the api.wyzecam.com/app/v2/auto/run_action endpoint
298
423
 
299
424
  :param device: The device for which to run the action
300
425
  :param action: The action to run
301
- :return:
302
426
  """
303
427
 
304
428
  await self._auth_lib.refresh_if_should()
@@ -320,18 +444,18 @@ class BaseService:
320
444
  "custom_string": "",
321
445
  }
322
446
 
323
- response_json = await self._auth_lib.post("https://api.wyzecam.com/app/v2/auto/run_action",
324
- json=payload)
447
+ response_json = await self._auth_lib.post(
448
+ "https://api.wyzecam.com/app/v2/auto/run_action", json=payload
449
+ )
325
450
 
326
451
  check_for_errors_standard(self, response_json)
327
-
328
- async def _run_action_devicemgmt(self, device: Device, type: str, value: str) -> None:
329
- """
330
- Wraps the devicemgmt-service-beta.wyze.com/device-management/api/action/run_action endpoint
452
+
453
+ async def _run_action_devicemgmt(self, device: Device, type: str, value: str):
454
+ """Wraps the devicemgmt-service-beta.wyze.com/device-management/api/action/run_action endpoint
331
455
 
332
456
  :param device: The device for which to run the action
333
- :param state: on or off
334
- :return:
457
+ :param type: The type of action to run
458
+ :param value: The value of the action to run
335
459
  """
336
460
 
337
461
  await self._auth_lib.refresh_if_should()
@@ -339,30 +463,32 @@ class BaseService:
339
463
  capabilities = devicemgmt_create_capabilities_payload(type, value)
340
464
 
341
465
  payload = {
342
- "capabilities": [
343
- capabilities
344
- ],
466
+ "capabilities": [capabilities],
345
467
  "nonce": int(time.time() * 1000),
346
468
  "targetInfo": {
347
469
  "id": device.mac,
348
470
  "productModel": device.product_model,
349
- "type": "DEVICE"
471
+ "type": "DEVICE",
350
472
  },
351
- "transactionId": "0a5b20591fedd4du1b93f90743ba0csd" # OG cam needs this (doesn't matter what the value is)
473
+ "transactionId": "0a5b20591fedd4du1b93f90743ba0csd", # OG cam needs this (doesn't matter what the value is)
352
474
  }
353
475
 
354
476
  headers = {
355
477
  "authorization": self._auth_lib.token.access_token,
356
478
  }
357
479
 
358
- response_json = await self._auth_lib.post("https://devicemgmt-service-beta.wyze.com/device-management/api/action/run_action",
359
- json=payload, headers=headers)
480
+ response_json = await self._auth_lib.post(
481
+ "https://devicemgmt-service-beta.wyze.com/device-management/api/action/run_action",
482
+ json=payload,
483
+ headers=headers,
484
+ )
360
485
 
361
486
  check_for_errors_iot(self, response_json)
362
-
363
- async def _set_toggle(self, device: Device, toggleType: DeviceMgmtToggleType, state: str) -> None:
364
- """
365
- Wraps the ai-subscription-service-beta.wyzecam.com/v4/subscription-service/toggle-management endpoint
487
+
488
+ async def _set_toggle(
489
+ self, device: Device, toggleType: DeviceMgmtToggleType, state: str
490
+ ):
491
+ """Wraps the ai-subscription-service-beta.wyzecam.com/v4/subscription-service/toggle-management endpoint
366
492
 
367
493
  :param device: The device for which to get the state
368
494
  :param toggleType: Enum for the toggle type
@@ -377,21 +503,15 @@ class BaseService:
377
503
  "device_firmware": "1234567890",
378
504
  "device_id": device.mac,
379
505
  "device_model": device.product_model,
380
- "page_id": [
381
- toggleType.pageId
382
- ],
506
+ "page_id": [toggleType.pageId],
383
507
  "toggle_update": [
384
- {
385
- "toggle_id": toggleType.toggleId,
386
- "toggle_status": state
387
- }
388
- ]
508
+ {"toggle_id": toggleType.toggleId, "toggle_status": state}
509
+ ],
389
510
  }
390
511
  ],
391
- "nonce": str(int(time.time() * 1000))
512
+ "nonce": str(int(time.time() * 1000)),
392
513
  }
393
514
 
394
-
395
515
  signature = olive_create_signature(payload, self._auth_lib.token.access_token)
396
516
  headers = {
397
517
  "access_token": self._auth_lib.token.access_token,
@@ -401,20 +521,22 @@ class BaseService:
401
521
  "signature2": signature,
402
522
  "appplatform": APP_PLATFORM,
403
523
  "appversion": APP_VERSION,
404
- "requestid": "35374158s4s313b9a2be7c057f2da5d1"
524
+ "requestid": "35374158s4s313b9a2be7c057f2da5d1",
405
525
  }
406
526
 
407
- response_json = await self._auth_lib.put("https://ai-subscription-service-beta.wyzecam.com/v4/subscription-service/toggle-management",
408
- json=payload, headers=headers)
409
-
527
+ response_json = await self._auth_lib.put(
528
+ "https://ai-subscription-service-beta.wyzecam.com/v4/subscription-service/toggle-management",
529
+ json=payload,
530
+ headers=headers,
531
+ )
532
+
410
533
  check_for_errors_devicemgmt(self, response_json)
411
-
534
+
412
535
  async def _get_iot_prop_devicemgmt(self, device: Device) -> Dict[str, Any]:
413
- """
414
- Wraps the devicemgmt-service-beta.wyze.com/device-management/api/device-property/get_iot_prop endpoint
536
+ """Wraps the devicemgmt-service-beta.wyze.com/device-management/api/device-property/get_iot_prop endpoint
415
537
 
416
538
  :param device: The device for which to get the state
417
- :return:
539
+ :return: Response from the server after being validated
418
540
  """
419
541
 
420
542
  await self._auth_lib.refresh_if_should()
@@ -425,24 +547,26 @@ class BaseService:
425
547
  "targetInfo": {
426
548
  "id": device.mac,
427
549
  "productModel": device.product_model,
428
- "type": "DEVICE"
429
- }
550
+ "type": "DEVICE",
551
+ },
430
552
  }
431
553
 
432
554
  headers = {
433
555
  "authorization": self._auth_lib.token.access_token,
434
556
  }
435
557
 
436
- response_json = await self._auth_lib.post("https://devicemgmt-service-beta.wyze.com/device-management/api/device-property/get_iot_prop",
437
- json=payload, headers=headers)
438
-
558
+ response_json = await self._auth_lib.post(
559
+ "https://devicemgmt-service-beta.wyze.com/device-management/api/device-property/get_iot_prop",
560
+ json=payload,
561
+ headers=headers,
562
+ )
563
+
439
564
  check_for_errors_iot(self, response_json)
440
565
 
441
566
  return response_json
442
567
 
443
- async def _set_property(self, device: Device, pid: str, pvalue: str) -> None:
444
- """
445
- Wraps the api.wyzecam.com/app/v2/device/set_property endpoint
568
+ async def _set_property(self, device: Device, pid: str, pvalue: str):
569
+ """Wraps the api.wyzecam.com/app/v2/device/set_property endpoint
446
570
 
447
571
  :param device: The device for which to set the property
448
572
  :param pid: The property id
@@ -463,22 +587,21 @@ class BaseService:
463
587
  "pvalue": pvalue,
464
588
  "pid": pid,
465
589
  "device_model": device.product_model,
466
- "device_mac": device.mac
590
+ "device_mac": device.mac,
467
591
  }
468
592
 
469
- response_json = await self._auth_lib.post("https://api.wyzecam.com/app/v2/device/set_property",
470
- json=payload)
593
+ response_json = await self._auth_lib.post(
594
+ "https://api.wyzecam.com/app/v2/device/set_property", json=payload
595
+ )
471
596
 
472
597
  check_for_errors_standard(self, response_json)
473
598
 
474
- async def _monitoring_profile_active(self, hms_id: str, home: int, away: int) -> None:
475
- """
476
- Wraps the hms.api.wyze.com/api/v1/monitoring/v1/profile/active endpoint
599
+ async def _monitoring_profile_active(self, hms_id: str, home: int, away: int):
600
+ """Wraps the hms.api.wyze.com/api/v1/monitoring/v1/profile/active endpoint
477
601
 
478
602
  :param hms_id: The hms id
479
603
  :param home: 1 for home 0 for not
480
604
  :param away: 1 for away 0 for not
481
- :return:
482
605
  """
483
606
  await self._auth_lib.refresh_if_should()
484
607
 
@@ -486,31 +609,23 @@ class BaseService:
486
609
  query = olive_create_hms_patch_payload(hms_id)
487
610
  signature = olive_create_signature(query, self._auth_lib.token.access_token)
488
611
  headers = {
489
- 'Accept-Encoding': 'gzip',
490
- 'User-Agent': 'myapp',
491
- 'appid': OLIVE_APP_ID,
492
- 'appinfo': APP_INFO,
493
- 'phoneid': PHONE_ID,
494
- 'access_token': self._auth_lib.token.access_token,
495
- 'signature2': signature,
496
- 'Authorization': self._auth_lib.token.access_token
612
+ "Accept-Encoding": "gzip",
613
+ "User-Agent": "myapp",
614
+ "appid": OLIVE_APP_ID,
615
+ "appinfo": APP_INFO,
616
+ "phoneid": PHONE_ID,
617
+ "access_token": self._auth_lib.token.access_token,
618
+ "signature2": signature,
619
+ "Authorization": self._auth_lib.token.access_token,
497
620
  }
498
- payload = [
499
- {
500
- "state": "home",
501
- "active": home
502
- },
503
- {
504
- "state": "away",
505
- "active": away
506
- }
507
- ]
508
- response_json = await self._auth_lib.patch(url, headers=headers, params=query, json=payload)
621
+ payload = [{"state": "home", "active": home}, {"state": "away", "active": away}]
622
+ response_json = await self._auth_lib.patch(
623
+ url, headers=headers, params=query, json=payload
624
+ )
509
625
  check_for_errors_hms(self, response_json)
510
626
 
511
627
  async def _get_plan_binding_list_by_user(self) -> Dict[Any, Any]:
512
- """
513
- Wraps the wyze-membership-service.wyzecam.com/platform/v2/membership/get_plan_binding_list_by_user endpoint
628
+ """Wraps the wyze-membership-service.wyzecam.com/platform/v2/membership/get_plan_binding_list_by_user endpoint
514
629
 
515
630
  :return: The response to gathering the plan for the current user
516
631
  """
@@ -522,13 +637,13 @@ class BaseService:
522
637
  payload = olive_create_hms_payload()
523
638
  signature = olive_create_signature(payload, self._auth_lib.token.access_token)
524
639
  headers = {
525
- 'Accept-Encoding': 'gzip',
526
- 'User-Agent': 'myapp',
527
- 'appid': OLIVE_APP_ID,
528
- 'appinfo': APP_INFO,
529
- 'phoneid': PHONE_ID,
530
- 'access_token': self._auth_lib.token.access_token,
531
- 'signature2': signature
640
+ "Accept-Encoding": "gzip",
641
+ "User-Agent": "myapp",
642
+ "appid": OLIVE_APP_ID,
643
+ "appinfo": APP_INFO,
644
+ "phoneid": PHONE_ID,
645
+ "access_token": self._auth_lib.token.access_token,
646
+ "signature2": signature,
532
647
  }
533
648
 
534
649
  response_json = await self._auth_lib.get(url, headers=headers, params=payload)
@@ -544,13 +659,8 @@ class BaseService:
544
659
  await self._auth_lib.refresh_if_should()
545
660
 
546
661
  url = "https://hms.api.wyze.com/api/v1/reme-alarm"
547
- payload = {
548
- "hms_id": hms_id,
549
- "remediation_id": "emergency"
550
- }
551
- headers = {
552
- "Authorization": self._auth_lib.token.access_token
553
- }
662
+ payload = {"hms_id": hms_id, "remediation_id": "emergency"}
663
+ headers = {"Authorization": self._auth_lib.token.access_token}
554
664
 
555
665
  response_json = await self._auth_lib.delete(url, headers=headers, json=payload)
556
666
 
@@ -570,14 +680,14 @@ class BaseService:
570
680
  query = olive_create_hms_get_payload(hms_id)
571
681
  signature = olive_create_signature(query, self._auth_lib.token.access_token)
572
682
  headers = {
573
- 'User-Agent': 'myapp',
574
- 'appid': OLIVE_APP_ID,
575
- 'appinfo': APP_INFO,
576
- 'phoneid': PHONE_ID,
577
- 'access_token': self._auth_lib.token.access_token,
578
- 'signature2': signature,
579
- 'Authorization': self._auth_lib.token.access_token,
580
- 'Content-Type': "application/json"
683
+ "User-Agent": "myapp",
684
+ "appid": OLIVE_APP_ID,
685
+ "appinfo": APP_INFO,
686
+ "phoneid": PHONE_ID,
687
+ "access_token": self._auth_lib.token.access_token,
688
+ "signature2": signature,
689
+ "Authorization": self._auth_lib.token.access_token,
690
+ "Content-Type": "application/json",
581
691
  }
582
692
 
583
693
  response_json = await self._auth_lib.get(url, headers=headers, params=query)
@@ -594,9 +704,11 @@ class BaseService:
594
704
 
595
705
  payload = {
596
706
  "uuid": device_uuid,
597
- "action": action # "remoteLock" or "remoteUnlock"
707
+ "action": action, # "remoteLock" or "remoteUnlock"
598
708
  }
599
- payload = ford_create_payload(self._auth_lib.token.access_token, payload, url_path, "post")
709
+ payload = ford_create_payload(
710
+ self._auth_lib.token.access_token, payload, url_path, "post"
711
+ )
600
712
 
601
713
  url = "https://yd-saas-toc.wyzecam.com/openapi/lock/v1/control"
602
714
 
@@ -611,12 +723,11 @@ class BaseService:
611
723
 
612
724
  device_uuid = device.mac.split(".")[-1]
613
725
 
614
- payload = {
615
- "uuid": device_uuid,
616
- "with_keypad": "1"
617
- }
726
+ payload = {"uuid": device_uuid, "with_keypad": "1"}
618
727
 
619
- payload = ford_create_payload(self._auth_lib.token.access_token, payload, url_path, "get")
728
+ payload = ford_create_payload(
729
+ self._auth_lib.token.access_token, payload, url_path, "get"
730
+ )
620
731
 
621
732
  url = "https://yd-saas-toc.wyzecam.com/openapi/lock/v1/info"
622
733
 
@@ -631,11 +742,11 @@ class BaseService:
631
742
 
632
743
  url_path = "/openapi/lock/v1/ble/token"
633
744
 
634
- payload = {
635
- "uuid": device.mac
636
- }
745
+ payload = {"uuid": device.mac}
637
746
 
638
- payload = ford_create_payload(self._auth_lib.token.access_token, payload, url_path, "get")
747
+ payload = ford_create_payload(
748
+ self._auth_lib.token.access_token, payload, url_path, "get"
749
+ )
639
750
 
640
751
  url = f"https://yd-saas-toc.wyzecam.com{url_path}"
641
752
 
@@ -659,29 +770,32 @@ class BaseService:
659
770
  "sv": "c86fa16fc99d4d6580f82ef3b942e586",
660
771
  "access_token": self._auth_lib.token.access_token,
661
772
  "phone_id": PHONE_ID,
662
- "app_name": APP_NAME
773
+ "app_name": APP_NAME,
663
774
  }
664
775
 
665
- response_json = await self._auth_lib.post("https://api.wyzecam.com/app/v2/device/get_device_Info",
666
- json=payload)
776
+ response_json = await self._auth_lib.post(
777
+ "https://api.wyzecam.com/app/v2/device/get_device_Info", json=payload
778
+ )
667
779
 
668
780
  check_for_errors_standard(self, response_json)
669
781
 
670
782
  return response_json
671
783
 
672
- async def _get_iot_prop(self, url: str, device: Device, keys: str) -> Dict[Any, Any]:
784
+ async def _get_iot_prop(
785
+ self, url: str, device: Device, keys: str
786
+ ) -> Dict[Any, Any]:
673
787
  await self._auth_lib.refresh_if_should()
674
788
 
675
789
  payload = olive_create_get_payload(device.mac, keys)
676
790
  signature = olive_create_signature(payload, self._auth_lib.token.access_token)
677
791
  headers = {
678
- 'Accept-Encoding': 'gzip',
679
- 'User-Agent': 'myapp',
680
- 'appid': OLIVE_APP_ID,
681
- 'appinfo': APP_INFO,
682
- 'phoneid': PHONE_ID,
683
- 'access_token': self._auth_lib.token.access_token,
684
- 'signature2': signature
792
+ "Accept-Encoding": "gzip",
793
+ "User-Agent": "myapp",
794
+ "appid": OLIVE_APP_ID,
795
+ "appinfo": APP_INFO,
796
+ "phoneid": PHONE_ID,
797
+ "access_token": self._auth_lib.token.access_token,
798
+ "signature2": signature,
685
799
  }
686
800
 
687
801
  response_json = await self._auth_lib.get(url, headers=headers, params=payload)
@@ -690,26 +804,34 @@ class BaseService:
690
804
 
691
805
  return response_json
692
806
 
693
- async def _set_iot_prop(self, url: str, device: Device, prop_key: str, value: Any) -> None:
807
+ async def _set_iot_prop(
808
+ self, url: str, device: Device, prop_key: str, value: Any
809
+ ) -> None:
694
810
  await self._auth_lib.refresh_if_should()
695
811
 
696
- payload = olive_create_post_payload(device.mac, device.product_model, prop_key, value)
697
- signature = olive_create_signature(json.dumps(payload, separators=(',', ':')),
698
- self._auth_lib.token.access_token)
812
+ payload = olive_create_post_payload(
813
+ device.mac, device.product_model, prop_key, value
814
+ )
815
+ signature = olive_create_signature(
816
+ json.dumps(payload, separators=(",", ":")),
817
+ self._auth_lib.token.access_token,
818
+ )
699
819
  headers = {
700
- 'Accept-Encoding': 'gzip',
701
- 'Content-Type': 'application/json',
702
- 'User-Agent': 'myapp',
703
- 'appid': OLIVE_APP_ID,
704
- 'appinfo': APP_INFO,
705
- 'phoneid': PHONE_ID,
706
- 'access_token': self._auth_lib.token.access_token,
707
- 'signature2': signature
820
+ "Accept-Encoding": "gzip",
821
+ "Content-Type": "application/json",
822
+ "User-Agent": "myapp",
823
+ "appid": OLIVE_APP_ID,
824
+ "appinfo": APP_INFO,
825
+ "phoneid": PHONE_ID,
826
+ "access_token": self._auth_lib.token.access_token,
827
+ "signature2": signature,
708
828
  }
709
829
 
710
- payload_str = json.dumps(payload, separators=(',', ':'))
830
+ payload_str = json.dumps(payload, separators=(",", ":"))
711
831
 
712
- response_json = await self._auth_lib.post(url, headers=headers, data=payload_str)
832
+ response_json = await self._auth_lib.post(
833
+ url, headers=headers, data=payload_str
834
+ )
713
835
 
714
836
  check_for_errors_iot(self, response_json)
715
837
 
@@ -720,20 +842,20 @@ class BaseService:
720
842
  "mac": bulb.mac.upper(),
721
843
  "index": "1",
722
844
  "ts": str(int(time.time_ns() // 1000000)),
723
- "plist": plist
845
+ "plist": plist,
724
846
  }
725
847
 
726
- characteristics_str = json.dumps(characteristics, separators=(',', ':'))
848
+ characteristics_str = json.dumps(characteristics, separators=(",", ":"))
727
849
  characteristics_enc = wyze_encrypt(bulb.enr, characteristics_str)
728
850
 
729
851
  payload = {
730
852
  "request": "set_status",
731
853
  "isSendQueue": 0,
732
- "characteristics": characteristics_enc
854
+ "characteristics": characteristics_enc,
733
855
  }
734
856
 
735
857
  # JSON likes to add a second \ so we have to remove it for the bulb to be happy
736
- payload_str = json.dumps(payload, separators=(',', ':')).replace('\\\\', '\\')
858
+ payload_str = json.dumps(payload, separators=(",", ":")).replace("\\\\", "\\")
737
859
 
738
860
  url = "http://%s:88/device_request" % bulb.ip
739
861
 
@@ -742,7 +864,9 @@ class BaseService:
742
864
  async with session.post(url, data=payload_str) as response:
743
865
  print(await response.text())
744
866
  except aiohttp.ClientConnectionError:
745
- _LOGGER.warning("Failed to connect to bulb %s, reverting to cloud." % bulb.mac)
867
+ _LOGGER.warning(
868
+ "Failed to connect to bulb %s, reverting to cloud." % bulb.mac
869
+ )
746
870
  await self._run_action_list(bulb, plist)
747
871
  bulb.cloud_fallback = True
748
872
 
@@ -775,3 +899,73 @@ class BaseService:
775
899
  check_for_errors_standard(self, response_json)
776
900
 
777
901
  return response_json["data"]["usage_record_list"]
902
+
903
+ async def _get_zone_by_device(self, url: str, device: Device) -> Dict[Any, Any]:
904
+ await self._auth_lib.refresh_if_should()
905
+
906
+ payload = olive_create_get_payload_irrigation(device.mac)
907
+ signature = olive_create_signature(payload, self._auth_lib.token.access_token)
908
+ headers = {
909
+ 'Accept-Encoding': 'gzip',
910
+ 'User-Agent': 'myapp',
911
+ 'appid': OLIVE_APP_ID,
912
+ 'appinfo': APP_INFO,
913
+ 'phoneid': PHONE_ID,
914
+ 'access_token': self._auth_lib.token.access_token,
915
+ 'signature2': signature
916
+ }
917
+
918
+ response_json = await self._auth_lib.get(url, headers=headers, params=payload)
919
+
920
+ check_for_errors_iot(self, response_json)
921
+
922
+ return response_json
923
+
924
+
925
+ async def _stop_running_schedule(self, url: str, device: Device, action: str) -> Dict[Any, Any]:
926
+ await self._auth_lib.refresh_if_should()
927
+
928
+ payload = olive_create_post_payload_irrigation_stop(device.mac, action)
929
+ signature = olive_create_signature(json.dumps(payload, separators=(',', ':')),
930
+ self._auth_lib.token.access_token)
931
+ headers = {
932
+ 'Accept-Encoding': 'gzip',
933
+ 'Content-Type': 'application/json',
934
+ 'User-Agent': 'myapp',
935
+ 'appid': OLIVE_APP_ID,
936
+ 'appinfo': APP_INFO,
937
+ 'phoneid': PHONE_ID,
938
+ 'access_token': self._auth_lib.token.access_token,
939
+ 'signature2': signature
940
+ }
941
+
942
+ payload_str = json.dumps(payload, separators=(',', ':'))
943
+ response_json = await self._auth_lib.post(url, headers=headers, data=payload_str)
944
+
945
+ check_for_errors_iot(self, response_json)
946
+
947
+ return response_json
948
+
949
+ async def _start_zone(self, url: str, device: Device, zone_number: int, duration: int) -> Dict[Any, Any]:
950
+ await self._auth_lib.refresh_if_should()
951
+
952
+ payload = olive_create_post_payload_irrigation_quickrun(device.mac, zone_number, duration)
953
+ signature = olive_create_signature(json.dumps(payload, separators=(',', ':')),
954
+ self._auth_lib.token.access_token)
955
+ headers = {
956
+ 'Accept-Encoding': 'gzip',
957
+ 'Content-Type': 'application/json',
958
+ 'User-Agent': 'myapp',
959
+ 'appid': OLIVE_APP_ID,
960
+ 'appinfo': APP_INFO,
961
+ 'phoneid': PHONE_ID,
962
+ 'access_token': self._auth_lib.token.access_token,
963
+ 'signature2': signature
964
+ }
965
+
966
+ payload_str = json.dumps(payload, separators=(',', ':'))
967
+ response_json = await self._auth_lib.post(url, headers=headers, data=payload_str)
968
+
969
+ check_for_errors_iot(self, response_json)
970
+
971
+ return response_json