pyvesync 3.3.2__tar.gz → 3.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyvesync-3.3.2 → pyvesync-3.4.0}/MANIFEST.in +2 -1
- {pyvesync-3.3.2/src/pyvesync.egg-info → pyvesync-3.4.0}/PKG-INFO +3 -3
- {pyvesync-3.3.2 → pyvesync-3.4.0}/README.md +2 -2
- {pyvesync-3.3.2 → pyvesync-3.4.0}/pyproject.toml +4 -1
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/base_devices/fan_base.py +12 -8
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/base_devices/humidifier_base.py +92 -5
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/base_devices/outlet_base.py +6 -6
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/const.py +28 -5
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/device_container.py +26 -36
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/device_map.py +61 -21
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/devices/vesyncbulb.py +9 -8
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/devices/vesyncfan.py +5 -9
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/devices/vesynchumidifier.py +577 -32
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/devices/vesynckitchen.py +12 -11
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/devices/vesyncoutlet.py +29 -13
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/models/bypass_models.py +26 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/models/humidifier_models.py +104 -2
- pyvesync-3.4.0/src/pyvesync/py.typed +1 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/utils/device_mixins.py +12 -26
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/utils/errors.py +9 -3
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/utils/helpers.py +69 -26
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/utils/logs.py +24 -13
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/vesync.py +32 -30
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/vesynchome.py +6 -7
- {pyvesync-3.3.2 → pyvesync-3.4.0/src/pyvesync.egg-info}/PKG-INFO +3 -3
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync.egg-info/SOURCES.txt +1 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/LICENSE +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/requirements.txt +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/setup.cfg +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/setup.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/__init__.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/auth.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/base_devices/__init__.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/base_devices/bulb_base.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/base_devices/fryer_base.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/base_devices/purifier_base.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/base_devices/switch_base.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/base_devices/thermostat_base.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/base_devices/vesyncbasedevice.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/devices/__init__.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/devices/vesyncpurifier.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/devices/vesyncswitch.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/devices/vesyncthermostat.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/models/__init__.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/models/base_models.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/models/bulb_models.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/models/fan_models.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/models/fryer_models.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/models/home_models.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/models/outlet_models.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/models/purifier_models.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/models/switch_models.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/models/thermostat_models.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/models/vesync_models.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/utils/__init__.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/utils/colors.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync/utils/enum_utils.py +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync.egg-info/dependency_links.txt +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync.egg-info/requires.txt +0 -0
- {pyvesync-3.3.2 → pyvesync-3.4.0}/src/pyvesync.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyvesync
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.4.0
|
|
4
4
|
Summary: pyvesync is a library to manage Etekcity Devices, Cosori Air Fryers, and Levoit Air Purifiers run on the VeSync app.
|
|
5
5
|
Author: Mark Perdue
|
|
6
6
|
Author-email: Joe Trabulsy <webdjoe@gmail.com>
|
|
@@ -216,9 +216,9 @@ See [Supported Devices](#supported-devices) for a complete list of supported dev
|
|
|
216
216
|
|
|
217
217
|
Exceptions are no longer caught by the library and must be handled by the user. Exceptions are raised by server errors and aiohttp connection errors.
|
|
218
218
|
|
|
219
|
-
Errors that occur at the aiohttp level are raised automatically and
|
|
219
|
+
Errors that occur at the aiohttp level are raised automatically and propagated to the user. That means exceptions raised by aiohttp that inherit from `aiohttp.ClientError` are propagated.
|
|
220
220
|
|
|
221
|
-
When the connection to the VeSync API succeeds but returns an error code that prevents the library from functioning a custom exception
|
|
221
|
+
When the connection to the VeSync API succeeds but returns an error code that prevents the library from functioning a custom exception inherited from `pyvesync.logs.VeSyncError` is raised.
|
|
222
222
|
|
|
223
223
|
Custom Exceptions raised by all API calls:
|
|
224
224
|
|
|
@@ -168,9 +168,9 @@ See [Supported Devices](#supported-devices) for a complete list of supported dev
|
|
|
168
168
|
|
|
169
169
|
Exceptions are no longer caught by the library and must be handled by the user. Exceptions are raised by server errors and aiohttp connection errors.
|
|
170
170
|
|
|
171
|
-
Errors that occur at the aiohttp level are raised automatically and
|
|
171
|
+
Errors that occur at the aiohttp level are raised automatically and propagated to the user. That means exceptions raised by aiohttp that inherit from `aiohttp.ClientError` are propagated.
|
|
172
172
|
|
|
173
|
-
When the connection to the VeSync API succeeds but returns an error code that prevents the library from functioning a custom exception
|
|
173
|
+
When the connection to the VeSync API succeeds but returns an error code that prevents the library from functioning a custom exception inherited from `pyvesync.logs.VeSyncError` is raised.
|
|
174
174
|
|
|
175
175
|
Custom Exceptions raised by all API calls:
|
|
176
176
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pyvesync"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.4.0"
|
|
8
8
|
description = "pyvesync is a library to manage Etekcity Devices, Cosori Air Fryers, and Levoit Air Purifiers run on the VeSync app."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -64,6 +64,9 @@ docs = [
|
|
|
64
64
|
where = ["src"]
|
|
65
65
|
exclude = ["tests", "test*"]
|
|
66
66
|
|
|
67
|
+
[tool.setuptools.package-data]
|
|
68
|
+
pyvesync = ["py.typed"]
|
|
69
|
+
|
|
67
70
|
[tool.pytest.ini_options]
|
|
68
71
|
addopts = "--tb=short --color=yes"
|
|
69
72
|
testpaths = ["src/tests"]
|
|
@@ -87,7 +87,7 @@ class FanState(DeviceState):
|
|
|
87
87
|
feature_map (FanMap): Feature map.
|
|
88
88
|
"""
|
|
89
89
|
super().__init__(device, details, feature_map)
|
|
90
|
-
self.mode: str =
|
|
90
|
+
self.mode: str | None = None
|
|
91
91
|
self.fan_level: int | None = None
|
|
92
92
|
self.fan_set_level: int | None = None
|
|
93
93
|
self.child_lock: str | None = None
|
|
@@ -145,6 +145,7 @@ class VeSyncFanBase(VeSyncBaseToggleDevice):
|
|
|
145
145
|
"""
|
|
146
146
|
|
|
147
147
|
__slots__ = (
|
|
148
|
+
'_reverse_modes',
|
|
148
149
|
'fan_levels',
|
|
149
150
|
'modes',
|
|
150
151
|
'sleep_preferences',
|
|
@@ -169,7 +170,10 @@ class VeSyncFanBase(VeSyncBaseToggleDevice):
|
|
|
169
170
|
super().__init__(details, manager, feature_map)
|
|
170
171
|
self.features: list[str] = feature_map.features
|
|
171
172
|
self.state: FanState = FanState(self, details, feature_map)
|
|
172
|
-
self.modes:
|
|
173
|
+
self.modes: dict[str, str] = feature_map.modes
|
|
174
|
+
self._reverse_modes: dict[str, str] = {}
|
|
175
|
+
for k, v in self.modes.items():
|
|
176
|
+
self._reverse_modes[v] = k
|
|
173
177
|
self.fan_levels: list[int] = feature_map.fan_levels
|
|
174
178
|
self.sleep_preferences: list[str] = feature_map.sleep_preferences
|
|
175
179
|
|
|
@@ -278,9 +282,9 @@ class VeSyncFanBase(VeSyncBaseToggleDevice):
|
|
|
278
282
|
This method is not supported by all devices, will return
|
|
279
283
|
false with warning debug message if not supported.
|
|
280
284
|
"""
|
|
281
|
-
if FanModes.
|
|
282
|
-
return await self.set_mode(FanModes.
|
|
283
|
-
logger.warning('
|
|
285
|
+
if FanModes.SLEEP in self.modes:
|
|
286
|
+
return await self.set_mode(FanModes.SLEEP)
|
|
287
|
+
logger.warning('Sleep mode not supported for this device.')
|
|
284
288
|
return False
|
|
285
289
|
|
|
286
290
|
async def set_sleep_mode(self) -> bool:
|
|
@@ -295,8 +299,8 @@ class VeSyncFanBase(VeSyncBaseToggleDevice):
|
|
|
295
299
|
This method is not supported by all devices, will return
|
|
296
300
|
false with warning debug message if not supported.
|
|
297
301
|
"""
|
|
298
|
-
if FanModes.
|
|
299
|
-
return await self.set_mode(FanModes.
|
|
302
|
+
if FanModes.SLEEP in self.modes:
|
|
303
|
+
return await self.set_mode(FanModes.SLEEP)
|
|
300
304
|
logger.warning('Sleep mode not supported for this device.')
|
|
301
305
|
return False
|
|
302
306
|
|
|
@@ -510,7 +514,7 @@ class VeSyncFanBase(VeSyncBaseToggleDevice):
|
|
|
510
514
|
@deprecated('Use `set_advanced_sleep_mode` method instead')
|
|
511
515
|
async def advanced_sleep_mode(self) -> bool:
|
|
512
516
|
"""Set advanced sleep mode."""
|
|
513
|
-
return await self.set_mode(
|
|
517
|
+
return await self.set_mode(FanModes.SLEEP)
|
|
514
518
|
|
|
515
519
|
@deprecated('Use `set_sleep_mode` method instead')
|
|
516
520
|
async def sleep_mode(self) -> bool:
|
|
@@ -4,14 +4,17 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
6
|
from abc import abstractmethod
|
|
7
|
+
from dataclasses import dataclass
|
|
7
8
|
from typing import TYPE_CHECKING
|
|
8
9
|
|
|
9
10
|
from pyvesync.base_devices.vesyncbasedevice import DeviceState, VeSyncBaseToggleDevice
|
|
10
|
-
from pyvesync.const import DeviceStatus, HumidifierFeatures, HumidifierModes
|
|
11
|
+
from pyvesync.const import DeviceStatus, DryingModes, HumidifierFeatures, HumidifierModes
|
|
12
|
+
from pyvesync.models.bypass_models import ResponseBaseModel
|
|
11
13
|
|
|
12
14
|
if TYPE_CHECKING:
|
|
13
15
|
from pyvesync import VeSync
|
|
14
16
|
from pyvesync.device_map import HumidifierMap
|
|
17
|
+
from pyvesync.models.humidifier_models import SproutBreathinglamp
|
|
15
18
|
from pyvesync.models.vesync_models import ResponseDeviceDetailsModel
|
|
16
19
|
|
|
17
20
|
|
|
@@ -55,6 +58,7 @@ class HumidifierState(DeviceState):
|
|
|
55
58
|
'auto_stop_target_reached',
|
|
56
59
|
'auto_target_humidity',
|
|
57
60
|
'automatic_stop_config',
|
|
61
|
+
'breathing_lamp',
|
|
58
62
|
'child_lock',
|
|
59
63
|
'display_set_status',
|
|
60
64
|
'display_status',
|
|
@@ -63,17 +67,20 @@ class HumidifierState(DeviceState):
|
|
|
63
67
|
'drying_mode_status',
|
|
64
68
|
'drying_mode_time_remain',
|
|
65
69
|
'filter_life',
|
|
70
|
+
'hepa_filter_life',
|
|
66
71
|
'humidity',
|
|
67
72
|
'humidity_high',
|
|
68
73
|
'mist_level',
|
|
69
74
|
'mist_virtual_level',
|
|
70
75
|
'mode',
|
|
71
76
|
'nightlight_brightness',
|
|
77
|
+
'nightlight_color_temp',
|
|
72
78
|
'nightlight_status',
|
|
73
79
|
'temperature',
|
|
74
80
|
'warm_mist_enabled',
|
|
75
81
|
'warm_mist_level',
|
|
76
82
|
'water_lacks',
|
|
83
|
+
'water_lacks_drying_switch',
|
|
77
84
|
'water_tank_lifted',
|
|
78
85
|
)
|
|
79
86
|
|
|
@@ -105,19 +112,23 @@ class HumidifierState(DeviceState):
|
|
|
105
112
|
self.mode: str | None = None
|
|
106
113
|
self.nightlight_brightness: int | None = None
|
|
107
114
|
self.nightlight_status: str | None = None
|
|
115
|
+
self.nightlight_color_temp: int | None = None
|
|
108
116
|
self.warm_mist_enabled: bool | None = None
|
|
109
117
|
self.warm_mist_level: int | None = None
|
|
110
118
|
self.water_lacks: bool = False
|
|
111
119
|
self.water_tank_lifted: bool = False
|
|
112
120
|
self.child_lock: bool | None = None
|
|
113
121
|
self.temperature: float | None = None # Fahrenheit
|
|
114
|
-
# Superior 6000S States
|
|
122
|
+
# Superior 6000S States / Sprout
|
|
115
123
|
self.auto_preference: int | None = None
|
|
116
124
|
self.filter_life: int | None = None
|
|
117
125
|
self.drying_mode_level: int | None = None
|
|
118
126
|
self.drying_mode_auto_switch: str | None = None
|
|
119
|
-
self.drying_mode_status:
|
|
127
|
+
self.drying_mode_status: DryingModes | None = None
|
|
120
128
|
self.drying_mode_time_remain: int | None = None
|
|
129
|
+
self.water_lacks_drying_switch: str | None = None
|
|
130
|
+
self.hepa_filter_life: int | None = None
|
|
131
|
+
self.breathing_lamp: BreathingLampState | None = None
|
|
121
132
|
|
|
122
133
|
@property
|
|
123
134
|
def automatic_stop(self) -> bool:
|
|
@@ -170,13 +181,24 @@ class HumidifierState(DeviceState):
|
|
|
170
181
|
return self.drying_mode_time_remain
|
|
171
182
|
|
|
172
183
|
@property
|
|
173
|
-
def
|
|
184
|
+
def drying_mode_running(self) -> bool:
|
|
174
185
|
"""Return True if drying mode is enabled.
|
|
175
186
|
|
|
176
187
|
Returns:
|
|
177
188
|
bool | None: True if drying mode is enabled, False otherwise.
|
|
178
189
|
"""
|
|
179
|
-
return self.drying_mode_status ==
|
|
190
|
+
return self.drying_mode_status == DryingModes.RUNNING
|
|
191
|
+
|
|
192
|
+
@property
|
|
193
|
+
def breathing_lamp_status(self) -> str | None:
|
|
194
|
+
"""Return the breathing lamp status.
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
str | None: Breathing lamp status.
|
|
198
|
+
"""
|
|
199
|
+
if self.breathing_lamp is not None:
|
|
200
|
+
return self.breathing_lamp.breathing_lamp_switch
|
|
201
|
+
return None
|
|
180
202
|
|
|
181
203
|
|
|
182
204
|
class VeSyncHumidifier(VeSyncBaseToggleDevice):
|
|
@@ -213,6 +235,7 @@ class VeSyncHumidifier(VeSyncBaseToggleDevice):
|
|
|
213
235
|
"""
|
|
214
236
|
|
|
215
237
|
__slots__ = (
|
|
238
|
+
'_reverse_mist_modes',
|
|
216
239
|
'mist_levels',
|
|
217
240
|
'mist_modes',
|
|
218
241
|
'target_minmax',
|
|
@@ -235,6 +258,9 @@ class VeSyncHumidifier(VeSyncBaseToggleDevice):
|
|
|
235
258
|
super().__init__(details, manager, feature_map)
|
|
236
259
|
self.state: HumidifierState = HumidifierState(self, details, feature_map)
|
|
237
260
|
self.mist_modes: dict[str, str] = feature_map.mist_modes
|
|
261
|
+
self._reverse_mist_modes: dict[str, str] = {}
|
|
262
|
+
for k, v in self.mist_modes.items():
|
|
263
|
+
self._reverse_mist_modes[v] = k
|
|
238
264
|
self.mist_levels: list[str | int] = feature_map.mist_levels
|
|
239
265
|
self.features: list[str] = feature_map.features
|
|
240
266
|
self.warm_mist_levels: list[int | str] = feature_map.warm_mist_levels
|
|
@@ -278,6 +304,9 @@ class VeSyncHumidifier(VeSyncBaseToggleDevice):
|
|
|
278
304
|
bool: Success of request.
|
|
279
305
|
"""
|
|
280
306
|
del toggle
|
|
307
|
+
if HumidifierFeatures.AUTO_STOP in self.features:
|
|
308
|
+
logger.warning('Automatic stop has not been configured for this device.')
|
|
309
|
+
return False
|
|
281
310
|
logger.warning('Automatic stop is not supported or configured for this device.')
|
|
282
311
|
return False
|
|
283
312
|
|
|
@@ -480,3 +509,61 @@ class VeSyncHumidifier(VeSyncBaseToggleDevice):
|
|
|
480
509
|
async def turn_off_drying_mode(self) -> bool:
|
|
481
510
|
"""Turn off drying mode."""
|
|
482
511
|
return await self.toggle_drying_mode(False)
|
|
512
|
+
|
|
513
|
+
async def toggle_child_lock(self, toggle: bool | None = None) -> bool:
|
|
514
|
+
"""Toggle child lock on/off.
|
|
515
|
+
|
|
516
|
+
Args:
|
|
517
|
+
toggle (bool): True to turn on child lock, False to turn off.
|
|
518
|
+
|
|
519
|
+
Returns:
|
|
520
|
+
bool: Success of request.
|
|
521
|
+
"""
|
|
522
|
+
del toggle
|
|
523
|
+
logger.error('Child lock is not supported or configured for this device.')
|
|
524
|
+
return False
|
|
525
|
+
|
|
526
|
+
async def turn_on_child_lock(self) -> bool:
|
|
527
|
+
"""Turn on child lock.
|
|
528
|
+
|
|
529
|
+
Returns:
|
|
530
|
+
bool: Success of request.
|
|
531
|
+
"""
|
|
532
|
+
return await self.toggle_child_lock(True)
|
|
533
|
+
|
|
534
|
+
async def turn_off_child_lock(self) -> bool:
|
|
535
|
+
"""Turn off child lock.
|
|
536
|
+
|
|
537
|
+
Returns:
|
|
538
|
+
bool: Success of request.
|
|
539
|
+
"""
|
|
540
|
+
return await self.toggle_child_lock(False)
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
@dataclass
|
|
544
|
+
class BreathingLampState(ResponseBaseModel):
|
|
545
|
+
"""Breathing Lamp State Object."""
|
|
546
|
+
|
|
547
|
+
breathing_lamp_switch: str
|
|
548
|
+
color_temperature: int
|
|
549
|
+
time_interval: int
|
|
550
|
+
brightness_start: int
|
|
551
|
+
brightness_end: int
|
|
552
|
+
|
|
553
|
+
@classmethod
|
|
554
|
+
def from_model(cls, model: SproutBreathinglamp) -> BreathingLampState:
|
|
555
|
+
"""Create BreathingLampState from SproutBreathinglamp model.
|
|
556
|
+
|
|
557
|
+
Args:
|
|
558
|
+
model (SproutBreathinglamp): The SproutBreathinglamp model.
|
|
559
|
+
|
|
560
|
+
Returns:
|
|
561
|
+
BreathingLampState: The created BreathingLampState object.
|
|
562
|
+
"""
|
|
563
|
+
return cls(
|
|
564
|
+
breathing_lamp_switch=DeviceStatus.from_int(model.breathingLampSwitch),
|
|
565
|
+
color_temperature=model.colorTemperature,
|
|
566
|
+
time_interval=model.timeInterval,
|
|
567
|
+
brightness_start=model.brightnessStart,
|
|
568
|
+
brightness_end=model.brightnessEnd,
|
|
569
|
+
)
|
|
@@ -12,7 +12,6 @@ from pyvesync.const import (
|
|
|
12
12
|
NightlightModes,
|
|
13
13
|
OutletFeatures,
|
|
14
14
|
)
|
|
15
|
-
from pyvesync.models.base_models import DefaultValues
|
|
16
15
|
from pyvesync.models.outlet_models import RequestEnergyHistory, ResponseEnergyHistory
|
|
17
16
|
from pyvesync.utils.helpers import Helpers
|
|
18
17
|
|
|
@@ -192,7 +191,7 @@ class VeSyncOutlet(VeSyncBaseToggleDevice):
|
|
|
192
191
|
|
|
193
192
|
def _build_energy_request(self, method: str) -> RequestEnergyHistory:
|
|
194
193
|
"""Build energy request post."""
|
|
195
|
-
request_keys =
|
|
194
|
+
request_keys = (
|
|
196
195
|
'acceptLanguage',
|
|
197
196
|
'accountID',
|
|
198
197
|
'appVersion',
|
|
@@ -205,10 +204,11 @@ class VeSyncOutlet(VeSyncBaseToggleDevice):
|
|
|
205
204
|
'debugMode',
|
|
206
205
|
'homeTimeZone',
|
|
207
206
|
'uuid',
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
body
|
|
211
|
-
body.update(Helpers.
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
body = Helpers.get_defaultvalues_attributes(request_keys)
|
|
210
|
+
body.update(Helpers.get_manager_attributes(self.manager, request_keys))
|
|
211
|
+
body.update(Helpers.get_device_attributes(self, request_keys))
|
|
212
212
|
body['method'] = method
|
|
213
213
|
return RequestEnergyHistory.from_dict(body)
|
|
214
214
|
|
|
@@ -27,10 +27,9 @@ Attributes:
|
|
|
27
27
|
from __future__ import annotations
|
|
28
28
|
|
|
29
29
|
import platform
|
|
30
|
-
import string
|
|
31
30
|
import uuid
|
|
32
31
|
from enum import Enum, IntEnum, StrEnum
|
|
33
|
-
from random import
|
|
32
|
+
from random import randint
|
|
34
33
|
from types import MappingProxyType
|
|
35
34
|
|
|
36
35
|
from pyvesync.utils.enum_utils import IntEnumMixin
|
|
@@ -54,7 +53,7 @@ USER_AGENT = (
|
|
|
54
53
|
DEFAULT_TZ = 'America/New_York'
|
|
55
54
|
DEFAULT_REGION = 'US'
|
|
56
55
|
APP_VERSION = '5.6.60'
|
|
57
|
-
APP_ID = ''
|
|
56
|
+
APP_ID = 'eldodkfj'
|
|
58
57
|
PHONE_BRAND = 'pyvesync'
|
|
59
58
|
PHONE_OS = 'Android'
|
|
60
59
|
MOBILE_ID = str(randint(1000000000000000, 9999999999999999)) # noqa: S311
|
|
@@ -674,12 +673,11 @@ class FanModes(StrEnum):
|
|
|
674
673
|
AUTO = 'auto'
|
|
675
674
|
NORMAL = 'normal'
|
|
676
675
|
MANUAL = 'normal'
|
|
677
|
-
SLEEP = '
|
|
676
|
+
SLEEP = 'sleep'
|
|
678
677
|
TURBO = 'turbo'
|
|
679
678
|
PET = 'pet'
|
|
680
679
|
ECO = 'eco'
|
|
681
680
|
UNKNOWN = 'unknown'
|
|
682
|
-
ADVANCED_SLEEP = 'advancedSleep'
|
|
683
681
|
|
|
684
682
|
|
|
685
683
|
# Air Fryer Constants
|
|
@@ -888,6 +886,31 @@ class DryingModes(StrEnum):
|
|
|
888
886
|
RUNNING = 'on'
|
|
889
887
|
PAUSE = 'pause'
|
|
890
888
|
|
|
889
|
+
@classmethod
|
|
890
|
+
def from_int(cls, value: int) -> DryingModes | None:
|
|
891
|
+
"""Convert integer value to corresponding string.
|
|
892
|
+
|
|
893
|
+
If value is 1, return ON and if 0, return OFF.
|
|
894
|
+
If value is -999, return NOT_SUPPORTED.
|
|
895
|
+
"""
|
|
896
|
+
if value == 0:
|
|
897
|
+
return cls.DONE
|
|
898
|
+
if value == 1:
|
|
899
|
+
return cls.RUNNING
|
|
900
|
+
if value == 2: # noqa: PLR2004
|
|
901
|
+
return cls.PAUSE
|
|
902
|
+
return None
|
|
903
|
+
|
|
904
|
+
def __int__(self) -> int:
|
|
905
|
+
"""Return integer representation of the enum."""
|
|
906
|
+
match self:
|
|
907
|
+
case DryingModes.DONE:
|
|
908
|
+
return 0
|
|
909
|
+
case DryingModes.RUNNING:
|
|
910
|
+
return 1
|
|
911
|
+
case DryingModes.PAUSE:
|
|
912
|
+
return 2
|
|
913
|
+
|
|
891
914
|
|
|
892
915
|
DRYING_MODES: dict[str, int] = {
|
|
893
916
|
DryingModes.DONE: 0,
|
|
@@ -17,22 +17,22 @@ from __future__ import annotations
|
|
|
17
17
|
import logging
|
|
18
18
|
import re
|
|
19
19
|
from collections.abc import Iterator, MutableSet, Sequence
|
|
20
|
-
from typing import TYPE_CHECKING, TypeVar
|
|
21
|
-
|
|
22
|
-
from pyvesync.base_devices.bulb_base import VeSyncBulb
|
|
23
|
-
from pyvesync.base_devices.fan_base import VeSyncFanBase
|
|
24
|
-
from pyvesync.base_devices.fryer_base import VeSyncFryer
|
|
25
|
-
from pyvesync.base_devices.humidifier_base import VeSyncHumidifier
|
|
26
|
-
from pyvesync.base_devices.outlet_base import VeSyncOutlet
|
|
27
|
-
from pyvesync.base_devices.purifier_base import VeSyncPurifier
|
|
28
|
-
from pyvesync.base_devices.switch_base import VeSyncSwitch
|
|
29
|
-
from pyvesync.base_devices.thermostat_base import VeSyncThermostat
|
|
20
|
+
from typing import TYPE_CHECKING, TypeVar, cast
|
|
21
|
+
|
|
30
22
|
from pyvesync.base_devices.vesyncbasedevice import VeSyncBaseDevice
|
|
31
23
|
from pyvesync.const import ProductTypes
|
|
32
24
|
from pyvesync.device_map import get_device_config
|
|
33
25
|
|
|
34
26
|
if TYPE_CHECKING:
|
|
35
27
|
from pyvesync import VeSync
|
|
28
|
+
from pyvesync.base_devices.bulb_base import VeSyncBulb
|
|
29
|
+
from pyvesync.base_devices.fan_base import VeSyncFanBase
|
|
30
|
+
from pyvesync.base_devices.fryer_base import VeSyncFryer
|
|
31
|
+
from pyvesync.base_devices.humidifier_base import VeSyncHumidifier
|
|
32
|
+
from pyvesync.base_devices.outlet_base import VeSyncOutlet
|
|
33
|
+
from pyvesync.base_devices.purifier_base import VeSyncPurifier
|
|
34
|
+
from pyvesync.base_devices.switch_base import VeSyncSwitch
|
|
35
|
+
from pyvesync.base_devices.thermostat_base import VeSyncThermostat
|
|
36
36
|
from pyvesync.models.vesync_models import (
|
|
37
37
|
ResponseDeviceDetailsModel,
|
|
38
38
|
ResponseDeviceListModel,
|
|
@@ -291,82 +291,72 @@ class DeviceContainer(_DeviceContainerBase):
|
|
|
291
291
|
def outlets(self) -> list[VeSyncOutlet]:
|
|
292
292
|
"""Return a list of devices that are outlets."""
|
|
293
293
|
return [
|
|
294
|
-
device
|
|
294
|
+
cast('VeSyncOutlet', device)
|
|
295
295
|
for device in self
|
|
296
|
-
if
|
|
297
|
-
and device.product_type == ProductTypes.OUTLET
|
|
296
|
+
if device.product_type == ProductTypes.OUTLET
|
|
298
297
|
]
|
|
299
298
|
|
|
300
299
|
@property
|
|
301
300
|
def switches(self) -> list[VeSyncSwitch]:
|
|
302
301
|
"""Return a list of devices that are switches."""
|
|
303
302
|
return [
|
|
304
|
-
device
|
|
303
|
+
cast('VeSyncSwitch', device)
|
|
305
304
|
for device in self
|
|
306
|
-
if
|
|
307
|
-
isinstance(device, VeSyncSwitch)
|
|
308
|
-
and device.product_type == ProductTypes.SWITCH
|
|
309
|
-
)
|
|
305
|
+
if device.product_type == ProductTypes.SWITCH
|
|
310
306
|
]
|
|
311
307
|
|
|
312
308
|
@property
|
|
313
309
|
def bulbs(self) -> list[VeSyncBulb]:
|
|
314
310
|
"""Return a list of devices that are lights."""
|
|
315
311
|
return [
|
|
316
|
-
device
|
|
312
|
+
cast('VeSyncBulb', device)
|
|
317
313
|
for device in self
|
|
318
|
-
if
|
|
319
|
-
and (device.product_type == ProductTypes.BULB)
|
|
314
|
+
if device.product_type == ProductTypes.BULB
|
|
320
315
|
]
|
|
321
316
|
|
|
322
317
|
@property
|
|
323
318
|
def air_purifiers(self) -> list[VeSyncPurifier]:
|
|
324
319
|
"""Return a list of devices that are air purifiers."""
|
|
325
320
|
return [
|
|
326
|
-
device
|
|
321
|
+
cast('VeSyncPurifier', device)
|
|
327
322
|
for device in self
|
|
328
|
-
if
|
|
329
|
-
and device.product_type == ProductTypes.PURIFIER
|
|
323
|
+
if device.product_type == ProductTypes.PURIFIER
|
|
330
324
|
]
|
|
331
325
|
|
|
332
326
|
@property
|
|
333
327
|
def fans(self) -> list[VeSyncFanBase]:
|
|
334
328
|
"""Return a list of devices that are fans."""
|
|
335
329
|
return [
|
|
336
|
-
device
|
|
330
|
+
cast('VeSyncFanBase', device)
|
|
337
331
|
for device in self
|
|
338
|
-
if
|
|
339
|
-
and device.product_type == ProductTypes.FAN
|
|
332
|
+
if device.product_type == ProductTypes.FAN
|
|
340
333
|
]
|
|
341
334
|
|
|
342
335
|
@property
|
|
343
336
|
def humidifiers(self) -> list[VeSyncHumidifier]:
|
|
344
337
|
"""Return a list of devices that are humidifiers."""
|
|
345
338
|
return [
|
|
346
|
-
device
|
|
339
|
+
cast('VeSyncHumidifier', device)
|
|
347
340
|
for device in self
|
|
348
|
-
if
|
|
349
|
-
and device.product_type == ProductTypes.HUMIDIFIER
|
|
341
|
+
if device.product_type == ProductTypes.HUMIDIFIER
|
|
350
342
|
]
|
|
351
343
|
|
|
352
344
|
@property
|
|
353
345
|
def air_fryers(self) -> list[VeSyncFryer]:
|
|
354
346
|
"""Return a list of devices that are air fryers."""
|
|
355
347
|
return [
|
|
356
|
-
device
|
|
348
|
+
cast('VeSyncFryer', device)
|
|
357
349
|
for device in self
|
|
358
|
-
if
|
|
359
|
-
and device.product_type == ProductTypes.AIR_FRYER
|
|
350
|
+
if device.product_type == ProductTypes.AIR_FRYER
|
|
360
351
|
]
|
|
361
352
|
|
|
362
353
|
@property
|
|
363
354
|
def thermostats(self) -> list[VeSyncThermostat]:
|
|
364
355
|
"""Return a list of devices that are thermostats."""
|
|
365
356
|
return [
|
|
366
|
-
device
|
|
357
|
+
cast('VeSyncThermostat', device)
|
|
367
358
|
for device in self
|
|
368
|
-
if
|
|
369
|
-
and device.product_type == ProductTypes.THERMOSTAT
|
|
359
|
+
if device.product_type == ProductTypes.THERMOSTAT
|
|
370
360
|
]
|
|
371
361
|
|
|
372
362
|
|