pyvesync 3.4.0__tar.gz → 3.4.2__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.4.0/src/pyvesync.egg-info → pyvesync-3.4.2}/PKG-INFO +115 -131
- {pyvesync-3.4.0 → pyvesync-3.4.2}/README.md +114 -130
- {pyvesync-3.4.0 → pyvesync-3.4.2}/pyproject.toml +1 -1
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/auth.py +43 -28
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/base_devices/fan_base.py +1 -1
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/base_devices/humidifier_base.py +2 -2
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/device_map.py +3 -3
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/devices/vesyncfan.py +1 -1
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/vesync.py +20 -2
- {pyvesync-3.4.0 → pyvesync-3.4.2/src/pyvesync.egg-info}/PKG-INFO +115 -131
- {pyvesync-3.4.0 → pyvesync-3.4.2}/LICENSE +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/MANIFEST.in +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/requirements.txt +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/setup.cfg +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/setup.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/__init__.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/base_devices/__init__.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/base_devices/bulb_base.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/base_devices/fryer_base.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/base_devices/outlet_base.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/base_devices/purifier_base.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/base_devices/switch_base.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/base_devices/thermostat_base.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/base_devices/vesyncbasedevice.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/const.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/device_container.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/devices/__init__.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/devices/vesyncbulb.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/devices/vesynchumidifier.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/devices/vesynckitchen.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/devices/vesyncoutlet.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/devices/vesyncpurifier.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/devices/vesyncswitch.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/devices/vesyncthermostat.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/models/__init__.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/models/base_models.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/models/bulb_models.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/models/bypass_models.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/models/fan_models.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/models/fryer_models.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/models/home_models.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/models/humidifier_models.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/models/outlet_models.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/models/purifier_models.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/models/switch_models.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/models/thermostat_models.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/models/vesync_models.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/py.typed +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/utils/__init__.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/utils/colors.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/utils/device_mixins.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/utils/enum_utils.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/utils/errors.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/utils/helpers.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/utils/logs.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync/vesynchome.py +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync.egg-info/SOURCES.txt +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync.egg-info/dependency_links.txt +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/src/pyvesync.egg-info/requires.txt +0 -0
- {pyvesync-3.4.0 → pyvesync-3.4.2}/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.4.
|
|
3
|
+
Version: 3.4.2
|
|
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>
|
|
@@ -46,7 +46,7 @@ Requires-Dist: griffe-inherited-docstrings; extra == "docs"
|
|
|
46
46
|
Requires-Dist: griffe_warnings_deprecated; extra == "docs"
|
|
47
47
|
Dynamic: license-file
|
|
48
48
|
|
|
49
|
-
# pyvesync [](https://pypi.python.org/pypi/pyvesync) [](https://pypi.python.org/pypi/pyvesync) [](https://github.com/Naereen/badges/) [](https://pypi.python.org/pypi/ansicolortags/) <!-- omit in toc -->
|
|
50
50
|
|
|
51
51
|
pyvesync is a library to manage VeSync compatible [smart home devices](#supported-devices)
|
|
52
52
|
|
|
@@ -83,7 +83,6 @@ Some of the changes are:
|
|
|
83
83
|
- Implemented custom exceptions and error (code) handling for API responses.
|
|
84
84
|
- `const` module to hold all library constants
|
|
85
85
|
- Built the `DeviceMap` class to hold the mapping and features of devices.
|
|
86
|
-
- COMING SOON: Use API to pull device modes and operating features.
|
|
87
86
|
|
|
88
87
|
See [pyvesync V3](https://webdjoe.github.io/pyvesync/latest/pyvesync3/) for more information on the changes.
|
|
89
88
|
|
|
@@ -94,7 +93,7 @@ Library is now asynchronous, using aiohttp as a replacement for requests. The `p
|
|
|
94
93
|
```python
|
|
95
94
|
import asyncio
|
|
96
95
|
import aiohttp
|
|
97
|
-
from pyvesync
|
|
96
|
+
from pyvesync import VeSync
|
|
98
97
|
|
|
99
98
|
async def main():
|
|
100
99
|
async with VeSync(
|
|
@@ -119,7 +118,7 @@ async def main():
|
|
|
119
118
|
if not manager.enabled:
|
|
120
119
|
print("Not logged in.")
|
|
121
120
|
return
|
|
122
|
-
await manager.get_devices() # Instantiates supported devices in device list
|
|
121
|
+
await manager.get_devices() # Instantiates supported devices in device list
|
|
123
122
|
await manager.update() # Updates the state of all devices
|
|
124
123
|
|
|
125
124
|
# manager.devices is a DeviceContainer object
|
|
@@ -140,8 +139,8 @@ async def main():
|
|
|
140
139
|
|
|
141
140
|
# State of object held in `device.state` attribute
|
|
142
141
|
print(outlet.state)
|
|
143
|
-
state_json = outlet.
|
|
144
|
-
state_bytes =
|
|
142
|
+
state_json = outlet.to_json(state=True) # Returns JSON string of device state
|
|
143
|
+
state_bytes = outlet.to_jsonb(state=True) # Returns JSON bytes of device state
|
|
145
144
|
|
|
146
145
|
# to view the response information of the last API call
|
|
147
146
|
print(outlet.last_response)
|
|
@@ -153,7 +152,7 @@ async def main():
|
|
|
153
152
|
session = aiohttp.ClientSession()
|
|
154
153
|
|
|
155
154
|
async def main():
|
|
156
|
-
async with VeSync("user", "password", session=session):
|
|
155
|
+
async with VeSync("user", "password", session=session) as manager:
|
|
157
156
|
await manager.login()
|
|
158
157
|
await manager.update()
|
|
159
158
|
|
|
@@ -166,7 +165,7 @@ if __name__ == "__main__":
|
|
|
166
165
|
If using `async with` is not ideal, the `__aenter__()` and `__aexit__()` methods need to be called manually:
|
|
167
166
|
|
|
168
167
|
```python
|
|
169
|
-
manager = VeSync(user, password)
|
|
168
|
+
manager = VeSync("user", "password")
|
|
170
169
|
|
|
171
170
|
await manager.__aenter__()
|
|
172
171
|
|
|
@@ -175,7 +174,7 @@ await manager.__aenter__()
|
|
|
175
174
|
await manager.__aexit__(None, None, None)
|
|
176
175
|
```
|
|
177
176
|
|
|
178
|
-
|
|
177
|
+
pyvesync will close the `ClientSession` that was created by the library on `__aexit__`. If a session is passed in as an argument, the library does not close it. If a session is passed in and not closed, aiohttp will generate an error on exit:
|
|
179
178
|
|
|
180
179
|
```text
|
|
181
180
|
2025-02-16 14:41:07 - ERROR - asyncio - Unclosed client session
|
|
@@ -190,9 +189,9 @@ The VeSync signature is:
|
|
|
190
189
|
VeSync(
|
|
191
190
|
username: str,
|
|
192
191
|
password: str,
|
|
193
|
-
country_code: str =
|
|
192
|
+
country_code: str = DEFAULT_REGION, # "US"
|
|
194
193
|
session: ClientSession | None = None,
|
|
195
|
-
time_zone: str = DEFAULT_TZ # America/New_York
|
|
194
|
+
time_zone: str = DEFAULT_TZ, # "America/New_York"
|
|
196
195
|
redact: bool = True,
|
|
197
196
|
)
|
|
198
197
|
```
|
|
@@ -209,6 +208,7 @@ There is a new nomenclature for product types that defines the device class. The
|
|
|
209
208
|
5. `humidifier` - Humidifiers (not air purifiers)
|
|
210
209
|
6. `bulb` - Light bulbs (not dimmers or switches)
|
|
211
210
|
7. `airfryer` - Air fryers
|
|
211
|
+
8. `thermostat` - Thermostats
|
|
212
212
|
|
|
213
213
|
See [Supported Devices](#supported-devices) for a complete list of supported devices and models.
|
|
214
214
|
|
|
@@ -218,22 +218,22 @@ Exceptions are no longer caught by the library and must be handled by the user.
|
|
|
218
218
|
|
|
219
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 inherited from `pyvesync.
|
|
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.utils.errors.VeSyncError` is raised.
|
|
222
222
|
|
|
223
223
|
Custom Exceptions raised by all API calls:
|
|
224
224
|
|
|
225
|
-
- `pyvesync.
|
|
226
|
-
- `pyvesync.
|
|
227
|
-
- `pyvesync.
|
|
228
|
-
- `pyvesync.
|
|
225
|
+
- `pyvesync.utils.errors.VeSyncServerError` - The API connected and returned a code indicated there is a server-side error.
|
|
226
|
+
- `pyvesync.utils.errors.VeSyncRateLimitError` - The API's rate limit has been exceeded.
|
|
227
|
+
- `pyvesync.utils.errors.VeSyncAPIStatusCodeError` - The API returned a non-200 status code.
|
|
228
|
+
- `pyvesync.utils.errors.VeSyncAPIResponseError` - The response from the API was not in an expected format.
|
|
229
229
|
|
|
230
230
|
Login API Exceptions
|
|
231
231
|
|
|
232
|
-
- `pyvesync.
|
|
232
|
+
- `pyvesync.utils.errors.VeSyncLoginError` - The username or password is incorrect.
|
|
233
233
|
|
|
234
|
-
See [errors](https://webdjoe.github.io/pyvesync/latest/development/utils/errors) documentation for a complete list of error codes and exceptions.
|
|
234
|
+
See the [errors](https://webdjoe.github.io/pyvesync/latest/development/utils/errors/) documentation for a complete list of error codes and exceptions.
|
|
235
235
|
|
|
236
|
-
The
|
|
236
|
+
The `raise_api_errors()` function is called for every API call and checks for general response errors. It can raise the following exceptions:
|
|
237
237
|
|
|
238
238
|
- `VeSyncServerError` - The API connected and returned a code indicated there is a server-side error.
|
|
239
239
|
- `VeSyncRateLimitError` - The API's rate limit has been exceeded.
|
|
@@ -257,12 +257,14 @@ pip install pyvesync
|
|
|
257
257
|
|
|
258
258
|
### Etekcity Outlets
|
|
259
259
|
|
|
260
|
-
1. Voltson Smart WiFi Outlet- Round (7A model ESW01-USA)
|
|
260
|
+
1. Voltson Smart WiFi Outlet - Round (7A model ESW01-USA)
|
|
261
261
|
2. Voltson Smart WiFi Outlet - Round (10A model ESW01-EU)
|
|
262
|
-
3. Voltson Smart
|
|
263
|
-
4. Voltson Smart
|
|
262
|
+
3. Voltson Smart WiFi Outlet - Round (10A model ESW03-USA)
|
|
263
|
+
4. Voltson Smart WiFi Outlet - Round (10A model ESW10-USA)
|
|
264
264
|
5. Voltson Smart WiFi Outlet - Rectangle (15A model ESW15-USA)
|
|
265
265
|
6. Two Plug Outdoor Outlet (ESO15-TB) (Each plug is a separate `VeSyncOutlet` object, energy readings are for both plugs combined)
|
|
266
|
+
7. BSDOG / Greensun Smart Outlet Series (BSDOG01, BSDOG02, WYSMTOD16A, WM-PLUG and more)
|
|
267
|
+
8. WHOPLUG / Greensun Smart Outlet
|
|
266
268
|
|
|
267
269
|
<!--SUPPORTED OUTLETS END-->
|
|
268
270
|
|
|
@@ -271,46 +273,54 @@ pip install pyvesync
|
|
|
271
273
|
### Wall Switches
|
|
272
274
|
|
|
273
275
|
1. Etekcity Smart WiFi Light Switch (model ESWL01)
|
|
274
|
-
2. Etekcity
|
|
276
|
+
2. Etekcity WiFi 3-Way Switch (model ESWL03)
|
|
277
|
+
3. Etekcity WiFi Dimmer Switch (model ESWD16)
|
|
275
278
|
|
|
276
279
|
<!--SUPPORTED SWITCHES END-->
|
|
277
280
|
|
|
278
281
|
### Levoit Air Purifiers
|
|
279
282
|
|
|
280
283
|
1. LV-PUR131S
|
|
281
|
-
2.
|
|
282
|
-
3. Core
|
|
283
|
-
4. Core
|
|
284
|
-
5. Core
|
|
285
|
-
6.
|
|
286
|
-
7. Vital 200S
|
|
284
|
+
2. LV-RH131S
|
|
285
|
+
3. Core 200S
|
|
286
|
+
4. Core 300S
|
|
287
|
+
5. Core 400S
|
|
288
|
+
6. Core 600S
|
|
289
|
+
7. Vital 100S / 200S
|
|
287
290
|
8. Everest Air
|
|
291
|
+
9. Sprout Air Purifier
|
|
288
292
|
|
|
289
|
-
### Etekcity Bulbs
|
|
293
|
+
### Etekcity / Valceno Bulbs
|
|
290
294
|
|
|
291
295
|
1. Soft White Dimmable Smart Bulb (ESL100)
|
|
292
296
|
2. Cool to Soft White Tunable Dimmable Bulb (ESL100CW)
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
1. Valceno Multicolor Bulb (XYD0001)
|
|
297
|
+
3. Multicolor Dimmable Bulb (ESL100MC)
|
|
298
|
+
4. Valceno Multicolor Bulb (XYD0001)
|
|
297
299
|
|
|
298
300
|
### Levoit Humidifiers
|
|
299
301
|
|
|
300
|
-
1.
|
|
301
|
-
2.
|
|
302
|
-
3.
|
|
303
|
-
4.
|
|
304
|
-
5. OasisMist 600S
|
|
302
|
+
1. Classic 200S
|
|
303
|
+
2. Dual 200S
|
|
304
|
+
3. Classic 300S
|
|
305
|
+
4. LV600S / LV603S
|
|
306
|
+
5. OasisMist 450S / 600S
|
|
305
307
|
6. OasisMist 1000S
|
|
308
|
+
7. Superior 6000S
|
|
309
|
+
8. Sprout Humidifier
|
|
306
310
|
|
|
307
|
-
###
|
|
311
|
+
### Levoit Fans
|
|
308
312
|
|
|
309
|
-
1.
|
|
313
|
+
1. 42 in. Tower Fan (LTF-F422S Series)
|
|
314
|
+
2. Pedestal Fan (LPF-R432S Series)
|
|
310
315
|
|
|
311
|
-
###
|
|
316
|
+
### Cosori Air Fryers
|
|
312
317
|
|
|
313
|
-
1.
|
|
318
|
+
1. Cosori 3.7 Quart Air Fryer (CS137-AF)
|
|
319
|
+
2. Cosori 5.8 Quart Air Fryer (CS158-AF)
|
|
320
|
+
|
|
321
|
+
### Thermostats
|
|
322
|
+
|
|
323
|
+
1. Aura Thermostat (LTM-A401S-WUS)
|
|
314
324
|
|
|
315
325
|
<!--SUPPORTED DEVICES END-->
|
|
316
326
|
|
|
@@ -319,10 +329,6 @@ pip install pyvesync
|
|
|
319
329
|
```python
|
|
320
330
|
import asyncio
|
|
321
331
|
from pyvesync import VeSync
|
|
322
|
-
from pyvesync.logs import VeSyncLoginError
|
|
323
|
-
|
|
324
|
-
# VeSync is an asynchronous context manager
|
|
325
|
-
# VeSync(username, password, redact=True, session=None)
|
|
326
332
|
|
|
327
333
|
async def main():
|
|
328
334
|
async with VeSync("user", "password") as manager:
|
|
@@ -332,14 +338,14 @@ async def main():
|
|
|
332
338
|
# Acts as a set of device instances
|
|
333
339
|
device_container = manager.devices
|
|
334
340
|
|
|
335
|
-
outlets = device_container.outlets
|
|
341
|
+
outlets = device_container.outlets # List of outlet instances
|
|
336
342
|
outlet = outlets[0]
|
|
337
343
|
await outlet.update()
|
|
338
344
|
await outlet.turn_off()
|
|
339
345
|
outlet.display()
|
|
340
346
|
|
|
341
|
-
# Iterate
|
|
342
|
-
for
|
|
347
|
+
# Iterate over entire device list
|
|
348
|
+
for device in device_container:
|
|
343
349
|
device.display()
|
|
344
350
|
|
|
345
351
|
|
|
@@ -347,15 +353,11 @@ if __name__ == "__main__":
|
|
|
347
353
|
asyncio.run(main())
|
|
348
354
|
```
|
|
349
355
|
|
|
350
|
-
If you want to reuse your token and account_id between runs. The `VeSync.auth` object holds the credentials and helper methods to save and load credentials.
|
|
356
|
+
If you want to reuse your token and account_id between runs. The `VeSync.auth` object holds the credentials and helper methods to save and load credentials. See the [Authentication Documentation](https://webdjoe.github.io/pyvesync/latest/authentication) for more details.
|
|
351
357
|
|
|
352
358
|
```python
|
|
353
359
|
import asyncio
|
|
354
360
|
from pyvesync import VeSync
|
|
355
|
-
from pyvesync.logs import VeSyncLoginError
|
|
356
|
-
|
|
357
|
-
# VeSync is an asynchronous context manager
|
|
358
|
-
# VeSync(username, password, redact=True, session=None)
|
|
359
361
|
|
|
360
362
|
async def main():
|
|
361
363
|
async with VeSync("user", "password") as manager:
|
|
@@ -367,32 +369,37 @@ async def main():
|
|
|
367
369
|
await manager.load_credentials_from_file("/path/to/token_file")
|
|
368
370
|
|
|
369
371
|
# Or credentials can be passed directly
|
|
370
|
-
manager.set_credentials(
|
|
371
|
-
|
|
372
|
-
|
|
372
|
+
manager.set_credentials(
|
|
373
|
+
token="your_token",
|
|
374
|
+
account_id="your_account_id",
|
|
375
|
+
country_code="US",
|
|
376
|
+
region="US",
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
# No login needed if token is valid
|
|
373
380
|
# await manager.login()
|
|
374
381
|
|
|
375
382
|
# To store credentials to a file after login
|
|
376
|
-
await manager.save_credentials() # Saves to default location ~/.vesync_token
|
|
377
|
-
# or pass a file path
|
|
378
383
|
await manager.save_credentials("/path/to/token_file")
|
|
379
384
|
|
|
380
|
-
# Output
|
|
381
|
-
|
|
385
|
+
# Output credentials as JSON string
|
|
386
|
+
print(manager.output_credentials_json())
|
|
387
|
+
# Output credentials as dictionary
|
|
388
|
+
print(manager.output_credentials_dict())
|
|
382
389
|
|
|
383
390
|
await manager.update()
|
|
384
391
|
|
|
385
392
|
# Acts as a set of device instances
|
|
386
393
|
device_container = manager.devices
|
|
387
394
|
|
|
388
|
-
outlets = device_container.outlets
|
|
395
|
+
outlets = device_container.outlets # List of outlet instances
|
|
389
396
|
outlet = outlets[0]
|
|
390
397
|
await outlet.update()
|
|
391
398
|
await outlet.turn_off()
|
|
392
399
|
outlet.display()
|
|
393
400
|
|
|
394
|
-
# Iterate
|
|
395
|
-
for
|
|
401
|
+
# Iterate over entire device list
|
|
402
|
+
for device in device_container:
|
|
396
403
|
device.display()
|
|
397
404
|
|
|
398
405
|
|
|
@@ -417,7 +424,7 @@ manager.devices.bulbs = [VeSyncBulbInstances]
|
|
|
417
424
|
manager.devices.air_purifiers = [VeSyncPurifierInstances]
|
|
418
425
|
manager.devices.humidifiers = [VeSyncHumidifierInstances]
|
|
419
426
|
manager.devices.air_fryers = [VeSyncAirFryerInstances]
|
|
420
|
-
|
|
427
|
+
manager.devices.thermostats = [VeSyncThermostatInstances]
|
|
421
428
|
|
|
422
429
|
# Get device by device name
|
|
423
430
|
dev_name = "My Device"
|
|
@@ -446,8 +453,7 @@ This is an example of debug mode with redact enabled:
|
|
|
446
453
|
```python
|
|
447
454
|
import logging
|
|
448
455
|
import asyncio
|
|
449
|
-
import
|
|
450
|
-
from pyvesync.vesync import VeSync
|
|
456
|
+
from pyvesync import VeSync
|
|
451
457
|
|
|
452
458
|
logger = logging.getLogger("pyvesync")
|
|
453
459
|
logger.setLevel(logging.DEBUG)
|
|
@@ -460,7 +466,7 @@ async def main():
|
|
|
460
466
|
await manager.login()
|
|
461
467
|
await manager.update()
|
|
462
468
|
|
|
463
|
-
outlet = manager.outlets[0]
|
|
469
|
+
outlet = manager.devices.outlets[0]
|
|
464
470
|
await outlet.update()
|
|
465
471
|
await outlet.turn_off()
|
|
466
472
|
outlet.display()
|
|
@@ -475,17 +481,16 @@ if __name__ == "__main__":
|
|
|
475
481
|
To log to a file, use the `log_to_file()` method of the `VeSync` class. Pass the file path as an argument.
|
|
476
482
|
|
|
477
483
|
```python
|
|
478
|
-
|
|
479
484
|
import asyncio
|
|
480
485
|
from pyvesync import VeSync
|
|
481
486
|
|
|
482
487
|
async def main():
|
|
483
488
|
async with VeSync("user", "password") as manager:
|
|
484
|
-
manager.log_to_file("pyvesync.log",
|
|
489
|
+
manager.log_to_file("pyvesync.log", stdout=True) # stdout argument prints log to console as well
|
|
485
490
|
await manager.login()
|
|
486
491
|
await manager.update()
|
|
487
492
|
|
|
488
|
-
outlet = manager.outlets[0]
|
|
493
|
+
outlet = manager.devices.outlets[0]
|
|
489
494
|
await outlet.update()
|
|
490
495
|
await outlet.turn_off()
|
|
491
496
|
outlet.display()
|
|
@@ -497,13 +502,13 @@ if __name__ == "__main__":
|
|
|
497
502
|
|
|
498
503
|
## Feature Requests
|
|
499
504
|
|
|
500
|
-
Before filing an issue to request a new feature or device, please ensure that you will take the time to test the feature
|
|
505
|
+
Before filing an issue to request a new feature or device, please ensure that you will take the time to test the feature thoroughly. New features cannot be simply tested on Home Assistant. A separate integration must be created which is not part of this library. In order to test a new feature, clone the branch and install into a new virtual environment.
|
|
501
506
|
|
|
502
507
|
```bash
|
|
503
508
|
mkdir python_test && cd python_test
|
|
504
509
|
|
|
505
510
|
# Check Python version is 3.11 or higher
|
|
506
|
-
python3 --version # or python --version
|
|
511
|
+
python3 --version # or python --version
|
|
507
512
|
# Create a new venv
|
|
508
513
|
python3 -m venv pyvesync-venv
|
|
509
514
|
# Activate the venv on linux
|
|
@@ -521,14 +526,11 @@ pip install git+https://github.com/webdjoe/pyvesync.git@refs/pull/PR_NUMBER/head
|
|
|
521
526
|
|
|
522
527
|
Test functionality with a script, please adjust methods and logging statements to the device you are testing.
|
|
523
528
|
|
|
524
|
-
See
|
|
529
|
+
See [testing_scripts](./testing_scripts/README.md) for a fully functioning test script for all devices.
|
|
525
530
|
|
|
526
531
|
```python
|
|
527
532
|
import asyncio
|
|
528
|
-
import sys
|
|
529
533
|
import logging
|
|
530
|
-
import json
|
|
531
|
-
from functool import chain
|
|
532
534
|
from pyvesync import VeSync
|
|
533
535
|
|
|
534
536
|
vs_logger = logging.getLogger("pyvesync")
|
|
@@ -540,65 +542,47 @@ logger.setLevel(logging.DEBUG)
|
|
|
540
542
|
USERNAME = "YOUR USERNAME"
|
|
541
543
|
PASSWORD = "YOUR PASSWORD"
|
|
542
544
|
|
|
543
|
-
DEVICE_NAME = "Device"
|
|
545
|
+
DEVICE_NAME = "Device" # Device to test
|
|
544
546
|
|
|
545
547
|
async def test_device():
|
|
546
548
|
# Instantiate VeSync class and login
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
logger.debug("Device is on %s", dev.is_on)
|
|
581
|
-
|
|
582
|
-
logger.debug("Sleep mode")
|
|
583
|
-
fan.sleep_mode()
|
|
584
|
-
logger.debug("Current mode - %s", dev.details['mode'])
|
|
585
|
-
|
|
586
|
-
fan.auto_mode()
|
|
587
|
-
|
|
588
|
-
logger.debug("Set Fan Speed - %s", dev.set_fan_speed)
|
|
589
|
-
logger.debug("Current Fan Level - %s", dev.fan_level)
|
|
590
|
-
logger.debug("Current mode - %s", dev.mode)
|
|
591
|
-
|
|
592
|
-
# Display all device info
|
|
593
|
-
logger.debug(dev.display(state=True))
|
|
594
|
-
logger.debug(dev.to_json(state=True, indent=True))
|
|
595
|
-
dev_dict = dev.to_dict(state=True)
|
|
549
|
+
async with VeSync(USERNAME, PASSWORD, redact=True) as manager:
|
|
550
|
+
await manager.login()
|
|
551
|
+
|
|
552
|
+
# Pull and update devices
|
|
553
|
+
await manager.update()
|
|
554
|
+
|
|
555
|
+
for dev in manager.devices:
|
|
556
|
+
# Print all device info
|
|
557
|
+
logger.debug(dev.device_name)
|
|
558
|
+
dev.display()
|
|
559
|
+
|
|
560
|
+
# Find correct device
|
|
561
|
+
if dev.device_name.lower() != DEVICE_NAME.lower():
|
|
562
|
+
logger.debug("%s is not %s, continuing", dev.device_name, DEVICE_NAME)
|
|
563
|
+
continue
|
|
564
|
+
|
|
565
|
+
logger.debug('-------------- %s -----------------', dev.device_name)
|
|
566
|
+
dev.display()
|
|
567
|
+
|
|
568
|
+
# Test device methods
|
|
569
|
+
logger.debug("Device is on: %s", dev.is_on)
|
|
570
|
+
|
|
571
|
+
logger.debug("Turning on")
|
|
572
|
+
await dev.turn_on()
|
|
573
|
+
logger.debug("Device is on: %s", dev.is_on)
|
|
574
|
+
|
|
575
|
+
logger.debug("Turning off")
|
|
576
|
+
await dev.turn_off()
|
|
577
|
+
logger.debug("Device is on: %s", dev.is_on)
|
|
578
|
+
|
|
579
|
+
# Display all device info as JSON
|
|
580
|
+
logger.debug(dev.to_json(state=True, indent=True))
|
|
581
|
+
dev_dict = dev.to_dict(state=True)
|
|
596
582
|
|
|
597
583
|
if __name__ == "__main__":
|
|
598
584
|
logger.debug("Testing device")
|
|
599
585
|
asyncio.run(test_device())
|
|
600
|
-
...
|
|
601
|
-
|
|
602
586
|
```
|
|
603
587
|
|
|
604
588
|
## Device Requests
|