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.
@@ -0,0 +1,536 @@
1
+ import unittest
2
+ from unittest.mock import AsyncMock, MagicMock
3
+ from wyzeapy.services.irrigation_service import (
4
+ IrrigationService, Irrigation, Zone
5
+ )
6
+ from wyzeapy.types import DeviceTypes, Device
7
+ from wyzeapy.wyze_auth_lib import WyzeAuthLib
8
+
9
+ # todo: add tests for irrigation service
10
+
11
+ class TestIrrigationService(unittest.IsolatedAsyncioTestCase):
12
+ async def asyncSetUp(self):
13
+ self.mock_auth_lib = MagicMock(spec=WyzeAuthLib)
14
+ self.irrigation_service = IrrigationService(auth_lib=self.mock_auth_lib)
15
+ self.irrigation_service.get_iot_prop = AsyncMock()
16
+ self.irrigation_service.get_zone_by_device = AsyncMock()
17
+ self.irrigation_service.get_object_list = AsyncMock()
18
+ self.irrigation_service._get_iot_prop = AsyncMock()
19
+ self.irrigation_service._get_zone_by_device = AsyncMock()
20
+ self.irrigation_service._irrigation_device_info = AsyncMock()
21
+
22
+ # Create test irrigation
23
+ self.test_irrigation = Irrigation({
24
+ "device_type": DeviceTypes.IRRIGATION.value,
25
+ "product_model": "BS_WK1",
26
+ "mac": "IRRIG123",
27
+ "nickname": "Test Irrigation",
28
+ "device_params": {"ip": "192.168.1.100"},
29
+ "raw_dict": {}
30
+ })
31
+
32
+ async def test_update_irrigation(self):
33
+ # Mock IoT properties response
34
+ self.irrigation_service.get_iot_prop.return_value = {
35
+ 'data': {
36
+ 'props': {
37
+ 'RSSI': '-65',
38
+ 'IP': '192.168.1.100',
39
+ 'sn': 'SN123456789',
40
+ 'ssid': 'TestSSID',
41
+ 'iot_state': 'connected'
42
+ }
43
+ }
44
+ }
45
+
46
+ # Mock zones response
47
+ self.irrigation_service.get_zone_by_device.return_value = {
48
+ 'data': {
49
+ 'zones': [
50
+ {
51
+ 'zone_number': 1,
52
+ 'name': 'Zone 1',
53
+ 'enabled': True,
54
+ 'zone_id': 'zone1',
55
+ 'smart_duration': 600
56
+ },
57
+ {
58
+ 'zone_number': 2,
59
+ 'name': 'Zone 2',
60
+ 'enabled': True,
61
+ 'zone_id': 'zone2',
62
+ 'smart_duration': 900
63
+ }
64
+ ]
65
+ }
66
+ }
67
+
68
+ updated_irrigation = await self.irrigation_service.update(self.test_irrigation)
69
+
70
+ # Test IoT properties
71
+ self.assertEqual(updated_irrigation.RSSI, '-65')
72
+ self.assertEqual(updated_irrigation.IP, '192.168.1.100')
73
+ self.assertEqual(updated_irrigation.sn, 'SN123456789')
74
+ self.assertEqual(updated_irrigation.ssid, 'TestSSID')
75
+ self.assertTrue(updated_irrigation.available)
76
+
77
+ # Test zones
78
+ self.assertEqual(len(updated_irrigation.zones), 2)
79
+ self.assertEqual(updated_irrigation.zones[0].zone_number, 1)
80
+ self.assertEqual(updated_irrigation.zones[0].name, 'Zone 1')
81
+ self.assertTrue(updated_irrigation.zones[0].enabled)
82
+ self.assertEqual(updated_irrigation.zones[0].quickrun_duration, 600)
83
+ self.assertEqual(updated_irrigation.zones[1].zone_number, 2)
84
+ self.assertEqual(updated_irrigation.zones[1].name, 'Zone 2')
85
+ self.assertTrue(updated_irrigation.zones[1].enabled)
86
+ self.assertEqual(updated_irrigation.zones[1].quickrun_duration, 900)
87
+
88
+ async def test_get_irrigations(self):
89
+ # Create a mock irrigation device with all required attributes
90
+ mock_irrigation = MagicMock()
91
+ mock_irrigation.type = DeviceTypes.IRRIGATION
92
+ mock_irrigation.product_model = "BS_WK1"
93
+ mock_irrigation.raw_dict = {
94
+ "device_type": DeviceTypes.IRRIGATION.value,
95
+ "product_model": "BS_WK1",
96
+ "mac": "IRRIG123",
97
+ "nickname": "Test Irrigation",
98
+ "device_params": {"ip": "192.168.1.100"},
99
+ "raw_dict": {}
100
+ }
101
+
102
+ # Mock the get_object_list to return our mock irrigation device
103
+ self.irrigation_service.get_object_list.return_value = [mock_irrigation]
104
+
105
+ # Get the irrigations
106
+ irrigations = await self.irrigation_service.get_irrigations()
107
+
108
+ # Verify the results
109
+ self.assertEqual(len(irrigations), 1)
110
+ self.assertIsInstance(irrigations[0], Irrigation)
111
+ self.assertEqual(irrigations[0].product_model, "BS_WK1")
112
+ self.assertEqual(irrigations[0].mac, "IRRIG123")
113
+ self.irrigation_service.get_object_list.assert_awaited_once()
114
+
115
+ async def test_set_zone_quickrun_duration(self):
116
+ # Setup test irrigation with zones
117
+ self.test_irrigation.zones = [
118
+ Zone({
119
+ 'zone_number': 1,
120
+ 'name': 'Zone 1',
121
+ 'enabled': True,
122
+ 'zone_id': 'zone1',
123
+ 'smart_duration': 400
124
+ }),
125
+ Zone({
126
+ 'zone_number': 2,
127
+ 'name': 'Zone 2',
128
+ 'enabled': True,
129
+ 'zone_id': 'zone2',
130
+ 'smart_duration': 900
131
+ })
132
+ ]
133
+
134
+ # Test setting quickrun duration
135
+ await self.irrigation_service.set_zone_quickrun_duration(
136
+ self.test_irrigation,
137
+ 1,
138
+ 300
139
+ )
140
+ self.assertEqual(self.test_irrigation.zones[0].quickrun_duration, 300)
141
+
142
+ # Test setting quickrun duration for non-existent zone
143
+ await self.irrigation_service.set_zone_quickrun_duration(
144
+ self.test_irrigation,
145
+ 999,
146
+ 300
147
+ )
148
+ # Verify that no zones were modified
149
+ self.assertEqual(len(self.test_irrigation.zones), 2)
150
+ self.assertEqual(self.test_irrigation.zones[0].quickrun_duration, 300) # First zone changed to 300
151
+ self.assertEqual(self.test_irrigation.zones[1].quickrun_duration, 900) # Second zone should be unchanged at 900
152
+
153
+ async def test_update_with_invalid_property(self):
154
+ self.irrigation_service.get_iot_prop.return_value = {
155
+ 'data': {
156
+ 'props': {
157
+ 'invalid_property': 'some_value',
158
+ 'RSSI': '-65'
159
+ }
160
+ }
161
+ }
162
+
163
+ self.irrigation_service.get_zone_by_device.return_value = {
164
+ 'data': {
165
+ 'zones': []
166
+ }
167
+ }
168
+
169
+ updated_irrigation = await self.irrigation_service.update(self.test_irrigation)
170
+ self.assertEqual(updated_irrigation.RSSI, '-65')
171
+ # Other properties should maintain their default values
172
+ self.assertEqual(updated_irrigation.IP, "192.168.1.100")
173
+ self.assertEqual(updated_irrigation.sn, "SN123456789")
174
+ self.assertEqual(updated_irrigation.ssid, "ssid")
175
+
176
+ async def test_start_zone(self):
177
+ # Mock the _start_zone method
178
+ self.irrigation_service._start_zone = AsyncMock()
179
+ expected_response = {'data': {'result': 'success'}}
180
+ self.irrigation_service._start_zone.return_value = expected_response
181
+
182
+ # Test starting a zone
183
+ result = await self.irrigation_service.start_zone(
184
+ self.test_irrigation,
185
+ zone_number=1,
186
+ quickrun_duration=300
187
+ )
188
+
189
+ # Verify the call was made with correct parameters
190
+ self.irrigation_service._start_zone.assert_awaited_once_with(
191
+ "https://wyze-lockwood-service.wyzecam.com/plugin/irrigation/quickrun",
192
+ self.test_irrigation,
193
+ 1,
194
+ 300
195
+ )
196
+ self.assertEqual(result, expected_response)
197
+
198
+ async def test_stop_running_schedule(self):
199
+ # Mock the _stop_running_schedule method
200
+ self.irrigation_service._stop_running_schedule = AsyncMock()
201
+ expected_response = {'data': {'result': 'stopped'}}
202
+ self.irrigation_service._stop_running_schedule.return_value = expected_response
203
+
204
+ # Test stopping running schedule
205
+ result = await self.irrigation_service.stop_running_schedule(self.test_irrigation)
206
+
207
+ # Verify the call was made with correct parameters
208
+ self.irrigation_service._stop_running_schedule.assert_awaited_once_with(
209
+ "https://wyze-lockwood-service.wyzecam.com/plugin/irrigation/runningschedule",
210
+ self.test_irrigation,
211
+ "STOP"
212
+ )
213
+ self.assertEqual(result, expected_response)
214
+
215
+ async def test_update_device_props(self):
216
+ # Mock IoT properties response
217
+ self.irrigation_service.get_iot_prop.return_value = {
218
+ 'data': {
219
+ 'props': {
220
+ 'RSSI': '-70',
221
+ 'IP': '192.168.1.101',
222
+ 'sn': 'SN987654321',
223
+ 'ssid': 'NewSSID',
224
+ 'iot_state': 'connected'
225
+ }
226
+ }
227
+ }
228
+
229
+ updated_irrigation = await self.irrigation_service.update_device_props(self.test_irrigation)
230
+
231
+ # Test that properties were updated correctly
232
+ self.assertEqual(updated_irrigation.RSSI, '-70')
233
+ self.assertEqual(updated_irrigation.IP, '192.168.1.101')
234
+ self.assertEqual(updated_irrigation.sn, 'SN987654321')
235
+ self.assertEqual(updated_irrigation.ssid, 'NewSSID')
236
+ self.assertTrue(updated_irrigation.available)
237
+
238
+ async def test_update_device_props_disconnected(self):
239
+ # Mock IoT properties response with disconnected state
240
+ self.irrigation_service.get_iot_prop.return_value = {
241
+ 'data': {
242
+ 'props': {
243
+ 'RSSI': '-80',
244
+ 'IP': '192.168.1.102',
245
+ 'sn': 'SN555666777',
246
+ 'ssid': 'TestSSID2',
247
+ 'iot_state': 'disconnected'
248
+ }
249
+ }
250
+ }
251
+
252
+ updated_irrigation = await self.irrigation_service.update_device_props(self.test_irrigation)
253
+
254
+ # Test that device is marked as unavailable
255
+ self.assertFalse(updated_irrigation.available)
256
+ self.assertEqual(updated_irrigation.RSSI, '-80')
257
+ self.assertEqual(updated_irrigation.IP, '192.168.1.102')
258
+
259
+ async def test_get_iot_prop(self):
260
+ # Mock the get_iot_prop method directly to test the public interface
261
+ expected_response = {'data': {'props': {'RSSI': '-65'}}}
262
+ self.irrigation_service.get_iot_prop.return_value = expected_response
263
+
264
+ # Test get_iot_prop
265
+ result = await self.irrigation_service.get_iot_prop(self.test_irrigation)
266
+
267
+ # Verify the call was made and returned expected result
268
+ self.irrigation_service.get_iot_prop.assert_awaited_once_with(self.test_irrigation)
269
+ self.assertEqual(result, expected_response)
270
+
271
+ async def test_get_device_info(self):
272
+ # Mock the _irrigation_device_info method
273
+ self.irrigation_service._irrigation_device_info = AsyncMock()
274
+ expected_response = {'data': {'props': {'enable_schedules': True}}}
275
+ self.irrigation_service._irrigation_device_info.return_value = expected_response
276
+
277
+ # Test get_device_info
278
+ result = await self.irrigation_service.get_device_info(self.test_irrigation)
279
+
280
+ # Verify the call was made with correct parameters
281
+ expected_keys = 'wiring,sensor,enable_schedules,notification_enable,notification_watering_begins,notification_watering_ends,notification_watering_is_skipped,skip_low_temp,skip_wind,skip_rain,skip_saturation'
282
+ self.irrigation_service._irrigation_device_info.assert_awaited_once_with(
283
+ "https://wyze-lockwood-service.wyzecam.com/plugin/irrigation/device_info",
284
+ self.test_irrigation,
285
+ expected_keys
286
+ )
287
+ self.assertEqual(result, expected_response)
288
+
289
+ async def test_get_zone_by_device_method(self):
290
+ # Mock the get_zone_by_device method directly to test the public interface
291
+ expected_response = {'data': {'zones': [{'zone_number': 1, 'name': 'Zone 1'}]}}
292
+ self.irrigation_service.get_zone_by_device.return_value = expected_response
293
+
294
+ # Test get_zone_by_device
295
+ result = await self.irrigation_service.get_zone_by_device(self.test_irrigation)
296
+
297
+ # Verify the call was made and returned expected result
298
+ self.irrigation_service.get_zone_by_device.assert_awaited_once_with(self.test_irrigation)
299
+ self.assertEqual(result, expected_response)
300
+
301
+
302
+ class TestZone(unittest.TestCase):
303
+ def test_zone_initialization_with_defaults(self):
304
+ # Test zone initialization with minimal data
305
+ zone_data = {'zone_number': 3, 'name': 'Test Zone'}
306
+ zone = Zone(zone_data)
307
+
308
+ self.assertEqual(zone.zone_number, 3)
309
+ self.assertEqual(zone.name, 'Test Zone')
310
+ self.assertTrue(zone.enabled) # Default value
311
+ self.assertEqual(zone.zone_id, 'zone_id') # Default value
312
+ self.assertEqual(zone.smart_duration, 600) # Default value
313
+ self.assertEqual(zone.quickrun_duration, 600) # Default value from smart_duration
314
+
315
+ def test_zone_initialization_with_all_data(self):
316
+ # Test zone initialization with all data
317
+ zone_data = {
318
+ 'zone_number': 2,
319
+ 'name': 'Garden Zone',
320
+ 'enabled': False,
321
+ 'zone_id': 'zone_garden',
322
+ 'smart_duration': 1200
323
+ }
324
+ zone = Zone(zone_data)
325
+
326
+ self.assertEqual(zone.zone_number, 2)
327
+ self.assertEqual(zone.name, 'Garden Zone')
328
+ self.assertFalse(zone.enabled)
329
+ self.assertEqual(zone.zone_id, 'zone_garden')
330
+ self.assertEqual(zone.smart_duration, 1200)
331
+ self.assertEqual(zone.quickrun_duration, 1200) # Should use smart_duration
332
+
333
+ def test_zone_initialization_empty_dict(self):
334
+ # Test zone initialization with empty dict
335
+ zone = Zone({})
336
+
337
+ self.assertEqual(zone.zone_number, 1) # Default value
338
+ self.assertEqual(zone.name, 'Zone 1') # Default value
339
+ self.assertTrue(zone.enabled) # Default value
340
+ self.assertEqual(zone.zone_id, 'zone_id') # Default value
341
+ self.assertEqual(zone.smart_duration, 600) # Default value
342
+ self.assertEqual(zone.quickrun_duration, 600) # Default value
343
+
344
+
345
+ class TestIrrigation(unittest.TestCase):
346
+ def test_irrigation_initialization(self):
347
+ # Test irrigation device initialization
348
+ irrigation_data = {
349
+ "device_type": DeviceTypes.IRRIGATION.value,
350
+ "product_model": "BS_WK1",
351
+ "mac": "IRRIG456",
352
+ "nickname": "Backyard Sprinkler",
353
+ "device_params": {"ip": "192.168.1.200"}
354
+ }
355
+ irrigation = Irrigation(irrigation_data)
356
+
357
+ self.assertEqual(irrigation.product_model, "BS_WK1")
358
+ self.assertEqual(irrigation.mac, "IRRIG456")
359
+ self.assertEqual(irrigation.nickname, "Backyard Sprinkler")
360
+
361
+ # Test default values
362
+ self.assertEqual(irrigation.RSSI, 0)
363
+ self.assertEqual(irrigation.IP, "192.168.1.100")
364
+ self.assertEqual(irrigation.sn, "SN123456789")
365
+ self.assertFalse(irrigation.available)
366
+ self.assertEqual(irrigation.ssid, "ssid")
367
+ self.assertEqual(len(irrigation.zones), 0)
368
+
369
+ def test_irrigation_inheritance(self):
370
+ # Test that Irrigation inherits from Device
371
+ irrigation_data = {
372
+ "product_type": DeviceTypes.IRRIGATION.value,
373
+ "product_model": "BS_WK1",
374
+ "mac": "IRRIG789",
375
+ "nickname": "Front Yard Sprinkler"
376
+ }
377
+ irrigation = Irrigation(irrigation_data)
378
+
379
+ # Test inherited Device properties
380
+ self.assertIsInstance(irrigation, Device)
381
+ self.assertEqual(irrigation.type, DeviceTypes.IRRIGATION)
382
+
383
+
384
+ class TestIrrigationServiceEdgeCases(unittest.IsolatedAsyncioTestCase):
385
+ async def asyncSetUp(self):
386
+ self.mock_auth_lib = MagicMock(spec=WyzeAuthLib)
387
+ self.irrigation_service = IrrigationService(auth_lib=self.mock_auth_lib)
388
+ self.irrigation_service.get_iot_prop = AsyncMock()
389
+ self.irrigation_service.get_zone_by_device = AsyncMock()
390
+ self.irrigation_service.get_object_list = AsyncMock()
391
+
392
+ # Create test irrigation
393
+ self.test_irrigation = Irrigation({
394
+ "device_type": DeviceTypes.IRRIGATION.value,
395
+ "product_model": "BS_WK1",
396
+ "mac": "IRRIG123",
397
+ "nickname": "Test Irrigation",
398
+ "device_params": {"ip": "192.168.1.100"},
399
+ "raw_dict": {}
400
+ })
401
+
402
+ async def test_update_with_empty_zones(self):
403
+ # Mock IoT properties response
404
+ self.irrigation_service.get_iot_prop.return_value = {
405
+ 'data': {
406
+ 'props': {
407
+ 'RSSI': '-65',
408
+ 'IP': '192.168.1.100',
409
+ 'sn': 'SN123456789',
410
+ 'ssid': 'TestSSID',
411
+ 'iot_state': 'connected'
412
+ }
413
+ }
414
+ }
415
+
416
+ # Mock empty zones response
417
+ self.irrigation_service.get_zone_by_device.return_value = {
418
+ 'data': {
419
+ 'zones': []
420
+ }
421
+ }
422
+
423
+ updated_irrigation = await self.irrigation_service.update(self.test_irrigation)
424
+
425
+ # Verify empty zones list
426
+ self.assertEqual(len(updated_irrigation.zones), 0)
427
+ self.assertTrue(updated_irrigation.available)
428
+
429
+ async def test_update_with_missing_iot_props(self):
430
+ # Mock IoT properties response with missing props
431
+ self.irrigation_service.get_iot_prop.return_value = {
432
+ 'data': {
433
+ 'props': {}
434
+ }
435
+ }
436
+
437
+ self.irrigation_service.get_zone_by_device.return_value = {
438
+ 'data': {
439
+ 'zones': []
440
+ }
441
+ }
442
+
443
+ updated_irrigation = await self.irrigation_service.update(self.test_irrigation)
444
+
445
+ # Verify default values are used
446
+ self.assertEqual(updated_irrigation.RSSI, -65)
447
+ self.assertEqual(updated_irrigation.IP, '192.168.1.100')
448
+ self.assertEqual(updated_irrigation.sn, 'SN123456789')
449
+ self.assertEqual(updated_irrigation.ssid, 'ssid')
450
+ self.assertFalse(updated_irrigation.available) # iot_state missing, so not connected
451
+
452
+ async def test_get_irrigations_empty_device_list(self):
453
+ # Mock empty device list
454
+ self.irrigation_service.get_object_list.return_value = []
455
+
456
+ irrigations = await self.irrigation_service.get_irrigations()
457
+
458
+ # Verify empty list returned
459
+ self.assertEqual(len(irrigations), 0)
460
+ self.irrigation_service.get_object_list.assert_awaited_once()
461
+
462
+ async def test_get_irrigations_no_irrigation_devices(self):
463
+ # Mock device list with non-irrigation devices
464
+ mock_camera = MagicMock()
465
+ mock_camera.type = DeviceTypes.CAMERA
466
+ mock_camera.product_model = "CAM_V1"
467
+
468
+ mock_bulb = MagicMock()
469
+ mock_bulb.type = DeviceTypes.LIGHT
470
+ mock_bulb.product_model = "LIGHT_V1"
471
+
472
+ self.irrigation_service.get_object_list.return_value = [mock_camera, mock_bulb]
473
+
474
+ irrigations = await self.irrigation_service.get_irrigations()
475
+
476
+ # Verify no irrigation devices returned
477
+ self.assertEqual(len(irrigations), 0)
478
+
479
+ async def test_get_irrigations_wrong_product_model(self):
480
+ # Mock device list with irrigation type but wrong product model
481
+ mock_irrigation = MagicMock()
482
+ mock_irrigation.type = DeviceTypes.IRRIGATION
483
+ mock_irrigation.product_model = "WRONG_MODEL"
484
+ mock_irrigation.raw_dict = {
485
+ "device_type": DeviceTypes.IRRIGATION.value,
486
+ "product_model": "WRONG_MODEL",
487
+ "mac": "IRRIG123",
488
+ "nickname": "Test Irrigation"
489
+ }
490
+
491
+ self.irrigation_service.get_object_list.return_value = [mock_irrigation]
492
+
493
+ irrigations = await self.irrigation_service.get_irrigations()
494
+
495
+ # Verify no irrigation devices returned due to wrong product model
496
+ self.assertEqual(len(irrigations), 0)
497
+
498
+ async def test_set_zone_quickrun_duration_zone_not_found(self):
499
+ # Setup test irrigation with zones
500
+ self.test_irrigation.zones = [
501
+ Zone({
502
+ 'zone_number': 1,
503
+ 'name': 'Zone 1',
504
+ 'enabled': True,
505
+ 'zone_id': 'zone1',
506
+ 'smart_duration': 600
507
+ })
508
+ ]
509
+
510
+ # Try to set duration for non-existent zone
511
+ result = await self.irrigation_service.set_zone_quickrun_duration(
512
+ self.test_irrigation,
513
+ 99, # Non-existent zone
514
+ 300
515
+ )
516
+
517
+ # Verify existing zone unchanged
518
+ self.assertEqual(self.test_irrigation.zones[0].quickrun_duration, 600)
519
+ self.assertEqual(result, self.test_irrigation)
520
+
521
+ async def test_set_zone_quickrun_duration_no_zones(self):
522
+ # Test with irrigation that has no zones
523
+ self.test_irrigation.zones = []
524
+
525
+ result = await self.irrigation_service.set_zone_quickrun_duration(
526
+ self.test_irrigation,
527
+ 1,
528
+ 300
529
+ )
530
+
531
+ # Verify no error and empty zones list
532
+ self.assertEqual(len(self.test_irrigation.zones), 0)
533
+ self.assertEqual(result, self.test_irrigation)
534
+
535
+ if __name__ == '__main__':
536
+ unittest.main()
wyzeapy/types.py CHANGED
@@ -3,6 +3,11 @@
3
3
  # of the attached license. You should have received a copy of
4
4
  # the license with this file. If not, please write to:
5
5
  # katie@mulliken.net to receive a copy
6
+ """
7
+ Type definitions and data models for Wyzeapy library, including devices, events,
8
+ and API response code enums.
9
+ """
10
+
6
11
  from enum import Enum
7
12
  from typing import Union, List, Dict, Any
8
13
 
@@ -43,6 +48,7 @@ class DeviceTypes(Enum):
43
48
  SENSE_V2_GATEWAY = "S1Gateway"
44
49
  KEYPAD = "Keypad"
45
50
  LIGHTSTRIP = "LightStrip"
51
+ IRRIGATION = "Common"
46
52
 
47
53
 
48
54
  class Device:
@@ -79,15 +85,17 @@ class Sensor(Device):
79
85
  @property
80
86
  def activity_detected(self) -> int:
81
87
  if self.type is DeviceTypes.CONTACT_SENSOR:
82
- return int(self.device_params['open_close_state'])
88
+ return int(self.device_params["open_close_state"])
83
89
  elif self.type is DeviceTypes.MOTION_SENSOR:
84
- return int(self.device_params['motion_state'])
90
+ return int(self.device_params["motion_state"])
85
91
  else:
86
- raise AssertionError("Device must be of type CONTACT_SENSOR or MOTION_SENSOR")
92
+ raise AssertionError(
93
+ "Device must be of type CONTACT_SENSOR or MOTION_SENSOR"
94
+ )
87
95
 
88
96
  @property
89
97
  def is_low_battery(self) -> int:
90
- return int(self.device_params['is_low_battery'])
98
+ return int(self.device_params["is_low_battery"])
91
99
 
92
100
 
93
101
  class PropertyIDs(Enum):
@@ -104,11 +112,11 @@ class PropertyIDs(Enum):
104
112
  CONTACT_STATE = "P1301"
105
113
  MOTION_STATE = "P1302"
106
114
  CAMERA_SIREN = "P1049"
107
- ACCESSORY = "P1056" # Is state for camera accessories, like garage doors, light sockets, and floodlights.
115
+ ACCESSORY = "P1056" # Is state for camera accessories, like garage doors, light sockets, and floodlights.
108
116
  SUN_MATCH = "P1528"
109
117
  MOTION_DETECTION = "P1047" # Current Motion Detection State of the Camera
110
118
  MOTION_DETECTION_TOGGLE = "P1001" # This toggles Camera Motion Detection On/Off
111
- WCO_MOTION_DETECTION = "P1029" # Wyze cam outdoor requires both P1047 and P1029 to be set. P1029 is set via set_property_list
119
+ WCO_MOTION_DETECTION = "P1029" # Wyze cam outdoor requires both P1047 and P1029 to be set. P1029 is set via set_property_list
112
120
 
113
121
 
114
122
  class WallSwitchProps(Enum):
@@ -149,11 +157,19 @@ class ThermostatProps(Enum):
149
157
  ASW_HOLD = "asw_hold"
150
158
 
151
159
 
160
+ class IrrigationProps(Enum):
161
+ IOT_STATE = "iot_state" # Connection state: connected, disconnected
162
+ RSSI = "RSSI"
163
+ IP = "IP"
164
+ SN = "sn"
165
+ SSID = "ssid"
166
+
167
+
152
168
  class ResponseCodes(Enum):
153
169
  SUCCESS = "1"
154
170
  PARAMETER_ERROR = "1001"
155
171
  ACCESS_TOKEN_ERROR = "2001"
156
- DEVICE_OFFLINE = '3019'
172
+ DEVICE_OFFLINE = "3019"
157
173
 
158
174
 
159
175
  class ResponseCodesLock(Enum):
@@ -205,9 +221,9 @@ class Event:
205
221
 
206
222
 
207
223
  class HMSStatus(Enum):
208
- DISARMED = 'disarmed'
209
- HOME = 'home'
210
- AWAY = 'away'
224
+ DISARMED = "disarmed"
225
+ HOME = "home"
226
+ AWAY = "away"
211
227
 
212
228
 
213
229
  class DeviceMgmtToggleType:
@@ -217,6 +233,7 @@ class DeviceMgmtToggleType:
217
233
 
218
234
 
219
235
  class DeviceMgmtToggleProps(Enum):
220
- EVENT_RECORDING_TOGGLE = DeviceMgmtToggleType("cam_event_recording", "ge.motion_detect_recording")
236
+ EVENT_RECORDING_TOGGLE = DeviceMgmtToggleType(
237
+ "cam_event_recording", "ge.motion_detect_recording"
238
+ )
221
239
  NOTIFICATION_TOGGLE = DeviceMgmtToggleType("cam_device_notify", "ge.push_switch")
222
-