pyvesync 3.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.
Files changed (50) hide show
  1. pyvesync/__init__.py +5 -0
  2. pyvesync/base_devices/__init__.py +35 -0
  3. pyvesync/base_devices/bulb_base.py +330 -0
  4. pyvesync/base_devices/fan_base.py +392 -0
  5. pyvesync/base_devices/fryer_base.py +68 -0
  6. pyvesync/base_devices/humidifier_base.py +462 -0
  7. pyvesync/base_devices/outlet_base.py +327 -0
  8. pyvesync/base_devices/purifier_base.py +525 -0
  9. pyvesync/base_devices/switch_base.py +271 -0
  10. pyvesync/base_devices/thermostat_base.py +283 -0
  11. pyvesync/base_devices/vesyncbasedevice.py +572 -0
  12. pyvesync/const.py +825 -0
  13. pyvesync/device_container.py +373 -0
  14. pyvesync/device_map.py +1172 -0
  15. pyvesync/devices/__init__.py +1 -0
  16. pyvesync/devices/vesyncbulb.py +1126 -0
  17. pyvesync/devices/vesyncfan.py +233 -0
  18. pyvesync/devices/vesynchumidifier.py +808 -0
  19. pyvesync/devices/vesynckitchen.py +651 -0
  20. pyvesync/devices/vesyncoutlet.py +954 -0
  21. pyvesync/devices/vesyncpurifier.py +990 -0
  22. pyvesync/devices/vesyncswitch.py +415 -0
  23. pyvesync/devices/vesyncthermostat.py +171 -0
  24. pyvesync/models/__init__.py +11 -0
  25. pyvesync/models/base_models.py +129 -0
  26. pyvesync/models/bulb_models.py +197 -0
  27. pyvesync/models/bypass_models.py +289 -0
  28. pyvesync/models/fan_models.py +47 -0
  29. pyvesync/models/fryer_models.py +34 -0
  30. pyvesync/models/home_models.py +169 -0
  31. pyvesync/models/humidifier_models.py +202 -0
  32. pyvesync/models/outlet_models.py +220 -0
  33. pyvesync/models/purifier_models.py +261 -0
  34. pyvesync/models/switch_models.py +101 -0
  35. pyvesync/models/thermostat_models.py +134 -0
  36. pyvesync/models/vesync_models.py +439 -0
  37. pyvesync/utils/__init__.py +1 -0
  38. pyvesync/utils/colors.py +250 -0
  39. pyvesync/utils/device_mixins.py +362 -0
  40. pyvesync/utils/enum_utils.py +26 -0
  41. pyvesync/utils/errors.py +867 -0
  42. pyvesync/utils/helpers.py +700 -0
  43. pyvesync/utils/logs.py +525 -0
  44. pyvesync/vesync.py +638 -0
  45. pyvesync/vesynchome.py +152 -0
  46. pyvesync-3.0.0.dist-info/METADATA +567 -0
  47. pyvesync-3.0.0.dist-info/RECORD +50 -0
  48. pyvesync-3.0.0.dist-info/WHEEL +5 -0
  49. pyvesync-3.0.0.dist-info/licenses/LICENSE +21 -0
  50. pyvesync-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,525 @@
1
+ """Air Purifier Base Class."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from abc import abstractmethod
7
+ from typing import TYPE_CHECKING
8
+
9
+ from typing_extensions import deprecated
10
+
11
+ from pyvesync.base_devices.vesyncbasedevice import DeviceState, VeSyncBaseToggleDevice
12
+ from pyvesync.const import (
13
+ AirQualityLevel,
14
+ DeviceStatus,
15
+ NightlightModes,
16
+ PurifierFeatures,
17
+ PurifierModes,
18
+ )
19
+
20
+ if TYPE_CHECKING:
21
+ from pyvesync import VeSync
22
+ from pyvesync.device_map import PurifierMap
23
+ from pyvesync.models.vesync_models import ResponseDeviceDetailsModel
24
+
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ class PurifierState(DeviceState):
30
+ """Base state class for Purifiers.
31
+
32
+ Attributes:
33
+ active_time (int): Active time of device, defaults to None.
34
+ connection_status (str): Connection status of device.
35
+ device (VeSyncOutlet): Device object.
36
+ device_status (str): Device status.
37
+ features (dict): Features of device.
38
+ last_update_ts (int): Last update timestamp of device, defaults to None.
39
+ mode (str): Current mode of the purifier.
40
+ fan_level (int): Current fan level of the purifier.
41
+ fan_set_level (int): Set fan level of the purifier.
42
+ filter_life (int): Filter life percentage of the purifier.
43
+ auto_preference_type (str): Auto preference type of the purifier.
44
+ auto_room_size (int): Auto room size of the purifier.
45
+ air_quality_level (AirQualityLevel): Air quality level of the purifier.
46
+ child_lock (bool): Child lock status of the purifier.
47
+ display_status (str): Display status of the purifier.
48
+ display_set_status (str): Display set status of the purifier.
49
+ display_forever (bool): Display forever status of the purifier.
50
+ timer (Timer): Timer object for the purifier.
51
+ pm25 (int): PM2.5 value of the purifier.
52
+ pm1 (int): PM1 value of the purifier.
53
+ pm10 (int): PM10 value of the purifier.
54
+ aq_percent (int): Air quality percentage of the purifier.
55
+ light_detection_switch (str): Light detection switch status of the purifier.
56
+ light_detection_status (str): Light detection status of the purifier.
57
+ nightlight_status (str): Nightlight status of the purifier.
58
+ fan_rotate_angle (int): Fan rotate angle of the purifier.
59
+ temperature (int): Temperature value of the purifier.
60
+ humidity (int): Humidity value of the purifier.
61
+ voc (int): VOC value of the purifier.
62
+ co2 (int): CO2 value of the purifier.
63
+ nightlight_brightness (int): Nightlight brightness level of the purifier.
64
+
65
+ Note:
66
+ Not all attributes are supported by all models.
67
+ """
68
+
69
+ __slots__ = (
70
+ '_air_quality_level',
71
+ 'aq_percent',
72
+ 'auto_preference_type',
73
+ 'auto_room_size',
74
+ 'child_lock',
75
+ 'co2',
76
+ 'display_forever',
77
+ 'display_set_status',
78
+ 'display_status',
79
+ 'fan_level',
80
+ 'fan_rotate_angle',
81
+ 'fan_set_level',
82
+ 'filter_life',
83
+ 'filter_open_state',
84
+ 'humidity',
85
+ 'light_detection_status',
86
+ 'light_detection_switch',
87
+ 'mode',
88
+ 'nightlight_brightness',
89
+ 'nightlight_status',
90
+ 'pm1',
91
+ 'pm10',
92
+ 'pm25',
93
+ 'temperature',
94
+ 'voc',
95
+ )
96
+
97
+ def __init__(
98
+ self,
99
+ device: VeSyncPurifier,
100
+ details: ResponseDeviceDetailsModel,
101
+ feature_map: PurifierMap,
102
+ ) -> None:
103
+ """Initialize Purifier State."""
104
+ super().__init__(device, details, feature_map)
105
+ self.mode: str = PurifierModes.UNKNOWN
106
+ self.fan_level: int | None = None
107
+ self.fan_set_level: int | None = None
108
+ self.filter_life: int | None = None
109
+ self.auto_preference_type: str | None = None
110
+ self.auto_room_size: int | None = None
111
+ self._air_quality_level: AirQualityLevel | None = None
112
+ self.child_lock: bool = False
113
+ self.filter_open_state: bool = False
114
+ self.display_status: str | None = None
115
+ self.display_set_status: str | None = None
116
+ self.display_forever: bool = False
117
+ self.humidity: int | None = None
118
+ self.temperature: int | None = None
119
+ # Attributes not supported by all purifiers
120
+ self.pm25: int | None = None
121
+ self.pm1: int | None = None
122
+ self.pm10: int | None = None
123
+ self.aq_percent: int | None = None
124
+ self.voc: int | None = None
125
+ self.co2: int | None = None
126
+ self.light_detection_switch: str | None = None
127
+ self.light_detection_status: str | None = None
128
+ self.nightlight_brightness: int | None = None
129
+ self.nightlight_status: str | None = None
130
+ self.fan_rotate_angle: int | None = None
131
+
132
+ @property
133
+ def air_quality_level(self) -> int:
134
+ """Return air quality level in integer from 1-4.
135
+
136
+ Returns -1 if unknown.
137
+ """
138
+ if self._air_quality_level is None:
139
+ return -1
140
+ return int(self._air_quality_level)
141
+
142
+ @air_quality_level.setter
143
+ def air_quality_level(self, value: int | None) -> None:
144
+ """Set air quality level."""
145
+ if isinstance(value, int):
146
+ self._air_quality_level = AirQualityLevel.from_int(value)
147
+
148
+ def set_air_quality_level(self, value: int | str | None) -> None:
149
+ """Set air quality level."""
150
+ if isinstance(value, str):
151
+ self._air_quality_level = AirQualityLevel.from_string(value)
152
+ elif isinstance(value, int):
153
+ self._air_quality_level = AirQualityLevel.from_int(value)
154
+
155
+ @property
156
+ def air_quality_string(self) -> str:
157
+ """Return air quality level as string."""
158
+ return str(self._air_quality_level)
159
+
160
+ @property
161
+ @deprecated('Use state.air_quality_level instead.')
162
+ def air_quality(self) -> int | str | None:
163
+ """Return air quality level."""
164
+ return self.air_quality_level
165
+
166
+ @property
167
+ @deprecated('Use light_detection_switch instead.')
168
+ def light_detection(self) -> bool:
169
+ """Return light detection status."""
170
+ return self.light_detection_switch == DeviceStatus.ON
171
+
172
+ @property
173
+ @deprecated('Use state.pm25 instead.')
174
+ def air_quality_value(self) -> int | None:
175
+ """Return air quality value."""
176
+ return self.pm25
177
+
178
+ @property
179
+ @deprecated('Use PurifierState.fan_level instead.')
180
+ def speed(self) -> int | None:
181
+ """Return fan speed."""
182
+ return self.fan_level
183
+
184
+ @property
185
+ @deprecated('Use PurifierState.nightlight_status instead.')
186
+ def night_light(self) -> str | None:
187
+ """Return night light status."""
188
+ return self.nightlight_status
189
+
190
+ @property
191
+ @deprecated('Use display_status instead.')
192
+ def display_state(self) -> str | None:
193
+ """Return display status."""
194
+ return self.display_status
195
+
196
+ @property
197
+ @deprecated('Use display_set_status instead.')
198
+ def display_switch(self) -> str | None:
199
+ """Return display switch status."""
200
+ return self.display_set_status
201
+
202
+
203
+ class VeSyncPurifier(VeSyncBaseToggleDevice):
204
+ """Base device for vesync air purifiers.
205
+
206
+ Args:
207
+ details (ResponseDeviceDetailsModel): Device details from API.
208
+ manager (VeSync): VeSync manager instance.
209
+ feature_map (PurifierMap): Feature map for the device.
210
+
211
+ Attributes:
212
+ state (PurifierState): State of the device.
213
+ last_response (ResponseInfo): Last response from API call.
214
+ manager (VeSync): Manager object for API calls.
215
+ device_name (str): Name of device.
216
+ device_image (str): URL for device image.
217
+ cid (str): Device ID.
218
+ connection_type (str): Connection type of device.
219
+ device_type (str): Type of device.
220
+ type (str): Type of device.
221
+ uuid (str): UUID of device, not always present.
222
+ config_module (str): Configuration module of device.
223
+ mac_id (str): MAC ID of device.
224
+ current_firm_version (str): Current firmware version of device.
225
+ device_region (str): Region of device. (US, EU, etc.)
226
+ pid (str): Product ID of device, pulled by some devices on update.
227
+ sub_device_no (int): Sub-device number of device.
228
+ product_type (str): Product type of device.
229
+ features (dict): Features of device.
230
+ modes (list[str]): List of modes supported by the device.
231
+ fan_levels (list[int]): List of fan levels supported by the device.
232
+ nightlight_modes (list[str]): List of nightlight modes supported by the device.
233
+ auto_preferences (list[str]): List of auto preferences supported by the device.
234
+ """
235
+
236
+ __slots__ = ('auto_preferences', 'fan_levels', 'modes', 'nightlight_modes')
237
+
238
+ def __init__(
239
+ self,
240
+ details: ResponseDeviceDetailsModel,
241
+ manager: VeSync,
242
+ feature_map: PurifierMap,
243
+ ) -> None:
244
+ """Initialize VeSync Purifier Base Class."""
245
+ super().__init__(details, manager, feature_map)
246
+ self.features: list[str] = feature_map.features
247
+ self.state: PurifierState = PurifierState(self, details, feature_map)
248
+ self.modes: list[str] = feature_map.modes
249
+ self.fan_levels: list[int] = feature_map.fan_levels
250
+ self.nightlight_modes: list[str] = feature_map.nightlight_modes
251
+ self.auto_preferences: list[str] = feature_map.auto_preferences
252
+
253
+ @property
254
+ def supports_air_quality(self) -> bool:
255
+ """Return True if device supports air quality."""
256
+ return PurifierFeatures.AIR_QUALITY in self.features
257
+
258
+ @property
259
+ def supports_fan_rotate(self) -> bool:
260
+ """Return True if device supports fan rotation."""
261
+ return PurifierFeatures.VENT_ANGLE in self.features
262
+
263
+ @property
264
+ def supports_nightlight(self) -> bool:
265
+ """Return True if device supports nightlight."""
266
+ return PurifierFeatures.NIGHTLIGHT in self.features
267
+
268
+ @property
269
+ def supports_light_detection(self) -> bool:
270
+ """Returns True if device supports light detection."""
271
+ return PurifierFeatures.LIGHT_DETECT in self.features
272
+
273
+ async def toggle_display(self, mode: bool) -> bool:
274
+ """Set Display Mode."""
275
+ del mode
276
+ raise NotImplementedError
277
+
278
+ async def turn_on_display(self) -> bool:
279
+ """Turn on Display."""
280
+ return await self.toggle_display(True)
281
+
282
+ async def turn_off_display(self) -> bool:
283
+ """Turn off Display."""
284
+ return await self.toggle_display(False)
285
+
286
+ async def set_nightlight_mode(self, mode: str) -> bool:
287
+ """Set Nightlight Mode.
288
+
289
+ Modes are defined in the `device.nightlight_modes` attribute.
290
+
291
+ Args:
292
+ mode (str): Nightlight mode to set.
293
+
294
+ Returns:
295
+ bool: True if successful, False otherwise.
296
+ """
297
+ del mode
298
+ return False
299
+
300
+ async def set_nightlight_dim(self) -> bool:
301
+ """Set Nightlight Dim."""
302
+ return await self.set_nightlight_mode(NightlightModes.DIM)
303
+
304
+ async def turn_on_nightlight(self) -> bool:
305
+ """Turn on Nightlight."""
306
+ return await self.set_nightlight_mode(NightlightModes.ON)
307
+
308
+ async def turn_off_nightlight(self) -> bool:
309
+ """Turn off Nightlight."""
310
+ return await self.set_nightlight_mode(NightlightModes.OFF)
311
+
312
+ async def toggle_child_lock(self, toggle: bool | None = None) -> bool:
313
+ """Toggle Child Lock (Display Lock).
314
+
315
+ Args:
316
+ toggle (bool | None): Toggle child lock. If None, toggle state.
317
+ """
318
+ del toggle
319
+ logger.debug('Child lock not configured for this device.')
320
+ return False
321
+
322
+ async def turn_on_child_lock(self) -> bool:
323
+ """Set child lock (display lock) to ON."""
324
+ return await self.toggle_child_lock(True)
325
+
326
+ async def turn_off_child_lock(self) -> bool:
327
+ """Set child lock (display lock) to OFF."""
328
+ return await self.toggle_child_lock(False)
329
+
330
+ @abstractmethod
331
+ async def set_mode(self, mode: str) -> bool:
332
+ """Set Purifier Mode.
333
+
334
+ Allowed modes are found in the `device.modes` attribute.
335
+
336
+ Args:
337
+ mode (str): Mode to set.
338
+
339
+ Returns:
340
+ bool: True if successful, False otherwise.
341
+ """
342
+
343
+ @abstractmethod
344
+ async def set_fan_speed(self, speed: int | None = None) -> bool:
345
+ """Set Purifier Fan Speed.
346
+
347
+ Args:
348
+ speed (int | None): Fan speed to set. If None, use default speed.
349
+
350
+ Returns:
351
+ bool: True if successful, False otherwise.
352
+ """
353
+
354
+ async def set_auto_mode(self) -> bool:
355
+ """Set Purifier to Auto Mode."""
356
+ if PurifierModes.AUTO in self.modes:
357
+ return await self.set_mode(PurifierModes.AUTO)
358
+ logger.error('Auto mode not supported for this device.')
359
+ return False
360
+
361
+ async def set_sleep_mode(self) -> bool:
362
+ """Set Purifier to Sleep Mode."""
363
+ if PurifierModes.SLEEP in self.modes:
364
+ return await self.set_mode(PurifierModes.SLEEP)
365
+ logger.error('Sleep mode not supported for this device.')
366
+ return False
367
+
368
+ async def set_manual_mode(self) -> bool:
369
+ """Set Purifier to Manual Mode."""
370
+ if PurifierModes.MANUAL in self.modes:
371
+ return await self.set_mode(PurifierModes.MANUAL)
372
+ logger.error('Manual mode not supported for this device.')
373
+ return False
374
+
375
+ async def set_turbo_mode(self) -> bool:
376
+ """Set Purifier to Turbo Mode."""
377
+ if PurifierModes.TURBO in self.modes:
378
+ return await self.set_mode(PurifierModes.TURBO)
379
+ logger.error('Turbo mode not supported for this device.')
380
+ return False
381
+
382
+ async def set_pet_mode(self) -> bool:
383
+ """Set Purifier to Pet Mode."""
384
+ if PurifierModes.PET in self.modes:
385
+ return await self.set_mode(PurifierModes.PET)
386
+ logger.error('Pet mode not supported for this device.')
387
+ return False
388
+
389
+ async def set_auto_preference(self, preference: str, room_size: int = 800) -> bool:
390
+ """Set auto preference.
391
+
392
+ Args:
393
+ preference (str): Auto preference to set, available preference is
394
+ found in `self.auto_preferences`.
395
+ room_size (int): Room size to set, defaults to 800ft2.
396
+
397
+ Returns:
398
+ bool: True if successful, False otherwise.
399
+ """
400
+ del preference, room_size
401
+ logger.debug('Auto preference not configured for this device.')
402
+ return False
403
+
404
+ async def toggle_light_detection(self, toggle: bool | None = None) -> bool:
405
+ """Set Light Detection Mode.
406
+
407
+ Args:
408
+ toggle (bool | None): Toggle light detection. If None, toggle state.
409
+
410
+ Returns:
411
+ bool: True if successful, False otherwise.
412
+ """
413
+ del toggle
414
+ if not self.supports_light_detection:
415
+ logger.debug('Light detection not supported for this device.')
416
+ else:
417
+ logger.debug('Light detection not configured for this device.')
418
+ return False
419
+
420
+ async def turn_on_light_detection(self) -> bool:
421
+ """Turn on Light Detection."""
422
+ return await self.toggle_light_detection(True)
423
+
424
+ async def turn_off_light_detection(self) -> bool:
425
+ """Turn off Light Detection."""
426
+ return await self.toggle_light_detection(False)
427
+
428
+ async def reset_filter(self) -> bool:
429
+ """Reset filter life."""
430
+ logger.debug('Filter life reset not configured for this device.')
431
+ return False
432
+
433
+ @deprecated('Use set_auto_mode instead.')
434
+ async def auto_mode(self) -> bool:
435
+ """Set Purifier to Auto Mode."""
436
+ return await self.set_auto_mode()
437
+
438
+ @deprecated('Use set_sleep_mode instead.')
439
+ async def sleep_mode(self) -> bool:
440
+ """Set Purifier to Sleep Mode."""
441
+ return await self.set_sleep_mode()
442
+
443
+ @deprecated('Use set_manual_mode instead.')
444
+ async def manual_mode(self) -> bool:
445
+ """Set Purifier to Manual Mode."""
446
+ return await self.set_manual_mode()
447
+
448
+ @deprecated('Use set_turbo_mode instead.')
449
+ async def turbo_mode(self) -> bool:
450
+ """Set Purifier to Turbo Mode."""
451
+ return await self.set_turbo_mode()
452
+
453
+ @deprecated('Use set_pet_mode instead.')
454
+ async def pet_mode(self) -> bool:
455
+ """Set Purifier to Pet Mode."""
456
+ return await self.set_pet_mode()
457
+
458
+ @deprecated('Use set_nightlight_mode instead.')
459
+ async def nightlight_mode(self, mode: str) -> bool:
460
+ """Set Nightlight Mode."""
461
+ return await self.set_nightlight_mode(mode)
462
+
463
+ @deprecated('Use `set_fan_speed()` instead.')
464
+ async def change_fan_speed(self, speed: int | None = None) -> bool:
465
+ """Deprecated - Set fan speed."""
466
+ return await self.set_fan_speed(speed)
467
+
468
+ @deprecated('Use `set_mode(mode: str)` instead.')
469
+ async def change_mode(self, mode: str) -> bool:
470
+ """Deprecated - Set purifier mode."""
471
+ return await self.set_mode(mode)
472
+
473
+ @deprecated('Use `toggle_child_lock()` instead.')
474
+ async def set_child_lock(self, toggle: bool) -> bool:
475
+ """Set child lock (display lock).
476
+
477
+ This has been deprecated in favor of `toggle_child_lock()`.
478
+ """
479
+ return await self.toggle_child_lock(toggle)
480
+
481
+ @deprecated('Use `turn_on_child_lock()` instead.')
482
+ async def child_lock_on(self) -> bool:
483
+ """Turn on child lock (display lock).
484
+
485
+ This has been deprecated, use `turn_on_child_lock()` instead.
486
+ """
487
+ return await self.toggle_child_lock(True)
488
+
489
+ @deprecated('Use `turn_off_child_lock()` instead.')
490
+ async def child_lock_off(self) -> bool:
491
+ """Turn off child lock (display lock).
492
+
493
+ This has been deprecated, use `turn_off_child_lock()` instead.
494
+ """
495
+ return await self.toggle_child_lock(False)
496
+
497
+ @property
498
+ @deprecated('Use self.state.child_lock instead.')
499
+ def child_lock(self) -> bool:
500
+ """Get child lock state.
501
+
502
+ Returns:
503
+ bool : True if child lock is enabled, False if not.
504
+ """
505
+ return self.state.child_lock
506
+
507
+ @property
508
+ @deprecated('Use self.state.nightlight_status instead.')
509
+ def night_light(self) -> str | None:
510
+ """Get night light state.
511
+
512
+ Returns:
513
+ str : Night light state (on, dim, off)
514
+ """
515
+ return self.state.nightlight_status
516
+
517
+ @deprecated('Use turn_on_light_detection() instead.')
518
+ async def set_light_detection_on(self) -> bool:
519
+ """Turn on light detection feature."""
520
+ return await self.toggle_light_detection(True)
521
+
522
+ @deprecated('Use turn_off_light_detection() instead.')
523
+ async def set_light_detection_off(self) -> bool:
524
+ """Turn off light detection feature."""
525
+ return await self.toggle_light_detection(False)