pyvesync 3.4.2__tar.gz → 3.5.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.4.2/src/pyvesync.egg-info → pyvesync-3.5.0}/PKG-INFO +53 -25
- {pyvesync-3.4.2 → pyvesync-3.5.0}/README.md +49 -21
- {pyvesync-3.4.2 → pyvesync-3.5.0}/pyproject.toml +4 -4
- pyvesync-3.5.0/requirements.txt +2 -0
- pyvesync-3.5.0/src/pyvesync/base_devices/fryer_base.py +1337 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/humidifier_base.py +50 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/outlet_base.py +18 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/const.py +527 -9
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/device_container.py +11 -2
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/device_map.py +766 -24
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesynchumidifier.py +192 -3
- pyvesync-3.5.0/src/pyvesync/devices/vesynckitchen.py +1089 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesyncoutlet.py +10 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesyncthermostat.py +2 -2
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/bypass_models.py +2 -1
- pyvesync-3.5.0/src/pyvesync/models/fryer_models.py +312 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/humidifier_models.py +15 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/colors.py +127 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/errors.py +47 -23
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/helpers.py +10 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/vesync.py +12 -5
- {pyvesync-3.4.2 → pyvesync-3.5.0/src/pyvesync.egg-info}/PKG-INFO +53 -25
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync.egg-info/requires.txt +3 -3
- pyvesync-3.4.2/requirements.txt +0 -3
- pyvesync-3.4.2/src/pyvesync/base_devices/fryer_base.py +0 -68
- pyvesync-3.4.2/src/pyvesync/devices/vesynckitchen.py +0 -653
- pyvesync-3.4.2/src/pyvesync/models/fryer_models.py +0 -34
- {pyvesync-3.4.2 → pyvesync-3.5.0}/LICENSE +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/MANIFEST.in +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/setup.cfg +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/setup.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/__init__.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/auth.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/__init__.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/bulb_base.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/fan_base.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/purifier_base.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/switch_base.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/thermostat_base.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/vesyncbasedevice.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/__init__.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesyncbulb.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesyncfan.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesyncpurifier.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesyncswitch.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/__init__.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/base_models.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/bulb_models.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/fan_models.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/home_models.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/outlet_models.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/purifier_models.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/switch_models.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/thermostat_models.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/vesync_models.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/py.typed +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/__init__.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/device_mixins.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/enum_utils.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/logs.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/vesynchome.py +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync.egg-info/SOURCES.txt +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync.egg-info/dependency_links.txt +0 -0
- {pyvesync-3.4.2 → pyvesync-3.5.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.5.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>
|
|
@@ -15,7 +15,7 @@ Classifier: Topic :: Home Automation
|
|
|
15
15
|
Requires-Python: >=3.11
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE
|
|
18
|
-
Requires-Dist: aiohttp>=3.
|
|
18
|
+
Requires-Dist: aiohttp>=3.14.4
|
|
19
19
|
Requires-Dist: mashumaro[orjson]>=3.13.1
|
|
20
20
|
Provides-Extra: dev
|
|
21
21
|
Requires-Dist: pytest; extra == "dev"
|
|
@@ -23,7 +23,7 @@ Requires-Dist: pytest-cov; extra == "dev"
|
|
|
23
23
|
Requires-Dist: pyyaml; extra == "dev"
|
|
24
24
|
Requires-Dist: pylint; extra == "dev"
|
|
25
25
|
Requires-Dist: mypy; extra == "dev"
|
|
26
|
-
Requires-Dist: ruff; extra == "dev"
|
|
26
|
+
Requires-Dist: ruff==0.15.21; extra == "dev"
|
|
27
27
|
Requires-Dist: pre-commit; extra == "dev"
|
|
28
28
|
Requires-Dist: tox; extra == "dev"
|
|
29
29
|
Requires-Dist: requests; extra == "dev"
|
|
@@ -31,7 +31,7 @@ Requires-Dist: aiofiles; extra == "dev"
|
|
|
31
31
|
Provides-Extra: docs
|
|
32
32
|
Requires-Dist: mkdocstrings-python; extra == "docs"
|
|
33
33
|
Requires-Dist: mkdocs; extra == "docs"
|
|
34
|
-
Requires-Dist: ruff; extra == "docs"
|
|
34
|
+
Requires-Dist: ruff==0.15.21; extra == "docs"
|
|
35
35
|
Requires-Dist: Pygments; extra == "docs"
|
|
36
36
|
Requires-Dist: mkdocs-material; extra == "docs"
|
|
37
37
|
Requires-Dist: mkdocstrings; extra == "docs"
|
|
@@ -52,7 +52,7 @@ pyvesync is a library to manage VeSync compatible [smart home devices](#supporte
|
|
|
52
52
|
|
|
53
53
|
<a href="https://webdjoe.github.io/pyvesync/latest"><img src="./docs/assets/docs.svg"></a>
|
|
54
54
|
|
|
55
|
-
**Check out the new [pyvesync documentation](https://webdjoe.github.io/pyvesync/) for usage and full API details.**
|
|
55
|
+
**Check out the new [pyvesync documentation](https://webdjoe.github.io/pyvesync/latest/) for usage and full API details.**
|
|
56
56
|
|
|
57
57
|
## Supported Product Types
|
|
58
58
|
|
|
@@ -67,7 +67,7 @@ pyvesync is a library to manage VeSync compatible [smart home devices](#supporte
|
|
|
67
67
|
|
|
68
68
|
See the [supported devices](https://webdjoe.github.io/pyvesync/latest/supported_devices/) page for a complete list of supported devices and device types.
|
|
69
69
|
|
|
70
|
-
##
|
|
70
|
+
## pyvesync v3 Features
|
|
71
71
|
|
|
72
72
|
**BREAKING CHANGES** - The release of pyvesync 3.0 comes with many improvements and new features, but as a result there are many breaking changes. The structure has been completely refactored, so please read through the README and thoroughly test before deploying.
|
|
73
73
|
|
|
@@ -108,9 +108,6 @@ async def main():
|
|
|
108
108
|
# Redact mode is enabled by default, set to False to disable
|
|
109
109
|
manager.redact = False
|
|
110
110
|
|
|
111
|
-
# To print request & response content for all API calls enable verbose mode
|
|
112
|
-
manager.verbose = True
|
|
113
|
-
|
|
114
111
|
# To print logs to file
|
|
115
112
|
manager.log_to_file("pyvesync.log")
|
|
116
113
|
|
|
@@ -124,11 +121,11 @@ async def main():
|
|
|
124
121
|
# manager.devices is a DeviceContainer object
|
|
125
122
|
# manager.devices.outlets is a list of VeSyncOutlet objects
|
|
126
123
|
# manager.devices.switches is a list of VeSyncSwitch objects
|
|
127
|
-
# manager.devices.fans is a list of
|
|
124
|
+
# manager.devices.fans is a list of VeSyncFanBase objects
|
|
128
125
|
# manager.devices.bulbs is a list of VeSyncBulb objects
|
|
129
|
-
# manager.devices.humidifiers is a list of
|
|
130
|
-
# manager.devices.air_purifiers is a list of
|
|
131
|
-
# manager.devices.air_fryers is a list of
|
|
126
|
+
# manager.devices.humidifiers is a list of VeSyncHumidifier objects
|
|
127
|
+
# manager.devices.air_purifiers is a list of VeSyncPurifier objects
|
|
128
|
+
# manager.devices.air_fryers is a list of VeSyncFryer objects
|
|
132
129
|
# manager.devices.thermostats is a list of VeSyncThermostat objects
|
|
133
130
|
|
|
134
131
|
for outlet in manager.devices.outlets:
|
|
@@ -207,7 +204,7 @@ There is a new nomenclature for product types that defines the device class. The
|
|
|
207
204
|
4. `purifier` - Air purifiers (not humidifiers)
|
|
208
205
|
5. `humidifier` - Humidifiers (not air purifiers)
|
|
209
206
|
6. `bulb` - Light bulbs (not dimmers or switches)
|
|
210
|
-
7. `
|
|
207
|
+
7. `air fryer` - Air fryers
|
|
211
208
|
8. `thermostat` - Thermostats
|
|
212
209
|
|
|
213
210
|
See [Supported Devices](#supported-devices) for a complete list of supported devices and models.
|
|
@@ -264,7 +261,8 @@ pip install pyvesync
|
|
|
264
261
|
5. Voltson Smart WiFi Outlet - Rectangle (15A model ESW15-USA)
|
|
265
262
|
6. Two Plug Outdoor Outlet (ESO15-TB) (Each plug is a separate `VeSyncOutlet` object, energy readings are for both plugs combined)
|
|
266
263
|
7. BSDOG / Greensun Smart Outlet Series (BSDOG01, BSDOG02, WYSMTOD16A, WM-PLUG and more)
|
|
267
|
-
8.
|
|
264
|
+
8. WHOGPLUG / Greensun Smart Plug
|
|
265
|
+
9. WYLDR Smart Plug (WYLDR16A1081) (Supports energy monitoring but not energy history)
|
|
268
266
|
|
|
269
267
|
<!--SUPPORTED OUTLETS END-->
|
|
270
268
|
|
|
@@ -317,6 +315,10 @@ pip install pyvesync
|
|
|
317
315
|
|
|
318
316
|
1. Cosori 3.7 Quart Air Fryer (CS137-AF)
|
|
319
317
|
2. Cosori 5.8 Quart Air Fryer (CS158-AF)
|
|
318
|
+
3. Cosori TurboBlaze 6 Quart Air Fryer (CAF-DC601S)
|
|
319
|
+
4. Cosori Dual Blaze 6.8 Quart Air Fryer (CAF-P583S)
|
|
320
|
+
5. Cosori Dual Air Fryer (CAF-TF101S)
|
|
321
|
+
6. Cosori Turbo Tower Pro Smart Air Fryer (CAF-DC111S-AEU)
|
|
320
322
|
|
|
321
323
|
### Thermostats
|
|
322
324
|
|
|
@@ -363,7 +365,8 @@ async def main():
|
|
|
363
365
|
async with VeSync("user", "password") as manager:
|
|
364
366
|
|
|
365
367
|
# If credentials are stored in a file, it can be loaded
|
|
366
|
-
#
|
|
368
|
+
# with no path, .vesync_auth is read from the current directory,
|
|
369
|
+
# then from the home directory
|
|
367
370
|
await manager.load_credentials_from_file()
|
|
368
371
|
# or the file path can be passed
|
|
369
372
|
await manager.load_credentials_from_file("/path/to/token_file")
|
|
@@ -444,25 +447,31 @@ See the [device documentation](https://webdjoe.github.io/pyvesync/latest/devices
|
|
|
444
447
|
|
|
445
448
|
## Debug mode and redact
|
|
446
449
|
|
|
447
|
-
|
|
450
|
+
There are three independent knobs that control logging output:
|
|
451
|
+
|
|
452
|
+
- **Debug logging** - set the `pyvesync` logger level to `DEBUG`. The read-only `manager.debug` property reflects whether debug logging is currently active.
|
|
453
|
+
- **`redact`** - the `redact` argument (default `True`) replaces tokens, account IDs, and other sensitive values (`token`, `password`, `email`, `accountId`, `authKey`, `uuid`, `cid`, `authorizeCode`) with `##_REDACTED_##` so logs can be shared safely. It only has an effect while debug logging is enabled.
|
|
454
|
+
- **`LibraryLogger.verbose`** - set this class attribute to `True` to additionally print the full request & response body of every API call.
|
|
448
455
|
|
|
449
|
-
|
|
456
|
+
### Debug to the console
|
|
450
457
|
|
|
451
|
-
|
|
458
|
+
Setting the `pyvesync` logger to `DEBUG` sends debug output to wherever your logging is configured (the console by default). `redact` stays on so tokens are not exposed:
|
|
452
459
|
|
|
453
460
|
```python
|
|
454
461
|
import logging
|
|
455
462
|
import asyncio
|
|
456
463
|
from pyvesync import VeSync
|
|
464
|
+
from pyvesync.utils.logs import LibraryLogger
|
|
457
465
|
|
|
458
466
|
logger = logging.getLogger("pyvesync")
|
|
459
467
|
logger.setLevel(logging.DEBUG)
|
|
468
|
+
logging.basicConfig() # Send log records to the console
|
|
460
469
|
|
|
461
470
|
|
|
462
471
|
async def main():
|
|
463
472
|
async with VeSync("user", "password") as manager:
|
|
464
|
-
manager.debug = True
|
|
465
473
|
manager.redact = True # True by default
|
|
474
|
+
LibraryLogger.verbose = True # Optional - print full request/response content
|
|
466
475
|
await manager.login()
|
|
467
476
|
await manager.update()
|
|
468
477
|
|
|
@@ -476,17 +485,26 @@ if __name__ == "__main__":
|
|
|
476
485
|
asyncio.run(main())
|
|
477
486
|
```
|
|
478
487
|
|
|
479
|
-
###
|
|
488
|
+
### Debug to a file (recommended for sharing with issues)
|
|
480
489
|
|
|
481
|
-
|
|
490
|
+
The `log_to_file()` method is the simplest way to capture a full debug log. It sets the `pyvesync` logger to `DEBUG` **and** attaches a file handler in one call, so you do not need to configure logging yourself. It also prints to the console by default; pass `stdout=False` to log only to the file. Keep `redact=True` (the default) so the log is safe to attach to a GitHub issue:
|
|
482
491
|
|
|
483
492
|
```python
|
|
484
493
|
import asyncio
|
|
485
494
|
from pyvesync import VeSync
|
|
495
|
+
from pyvesync.utils.logs import LibraryLogger
|
|
496
|
+
|
|
486
497
|
|
|
487
498
|
async def main():
|
|
488
|
-
|
|
489
|
-
|
|
499
|
+
# redact=True is the default - sensitive values are scrubbed from the log
|
|
500
|
+
async with VeSync("user", "password", redact=True) as manager:
|
|
501
|
+
# Enables DEBUG logging and writes it to pyvesync.log
|
|
502
|
+
# stdout=True (the default) also prints the log to the console
|
|
503
|
+
manager.log_to_file("pyvesync.log", stdout=True)
|
|
504
|
+
|
|
505
|
+
# Optional - include the full request & response body of every API call
|
|
506
|
+
LibraryLogger.verbose = True
|
|
507
|
+
|
|
490
508
|
await manager.login()
|
|
491
509
|
await manager.update()
|
|
492
510
|
|
|
@@ -495,11 +513,21 @@ async def main():
|
|
|
495
513
|
await outlet.turn_off()
|
|
496
514
|
outlet.display()
|
|
497
515
|
|
|
516
|
+
|
|
498
517
|
if __name__ == "__main__":
|
|
499
518
|
asyncio.run(main())
|
|
500
|
-
|
|
501
519
|
```
|
|
502
520
|
|
|
521
|
+
## Contribution Expectations
|
|
522
|
+
|
|
523
|
+
Contributions — from humans and AI coding assistants alike — must follow three rules. These keep the library correct and maintainable. See the [contributing guide](https://webdjoe.github.io/pyvesync/latest/development/contributing) for full detail.
|
|
524
|
+
|
|
525
|
+
1. **Follow the intended architecture.** New devices are added through the three-tier hierarchy (base class → concrete device + API mixin → device map), with state in the device's `DeviceState` subclass, models in `models/`, and constants in `pyvesync.const`. API request/response shapes must come from a real packet capture — never invented.
|
|
526
|
+
2. **Verify on real hardware before merge.** New device support and any change to device behavior must be tested on the physical device, and the pull request must state the model and firmware version tested. Testing only through Home Assistant does not count.
|
|
527
|
+
3. **One change per pull request.** Each PR must be a single feature, fix, or edit. Large or mixed PRs that bundle unrelated changes will be asked to be broken up before review.
|
|
528
|
+
|
|
529
|
+
> **Using an AI assistant?** Agent instructions live in [`AGENTS.md`](AGENTS.md), which Codex and most tools read directly; [`CLAUDE.md`](CLAUDE.md) imports it for Claude Code. Point your assistant at it and the [contributing guide](https://webdjoe.github.io/pyvesync/latest/development/contributing). You are responsible for the result: it must follow the architecture, must not fabricate API fields, must not be submitted without real-device testing, and must be a single focused change.
|
|
530
|
+
|
|
503
531
|
## Feature Requests
|
|
504
532
|
|
|
505
533
|
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.
|
|
@@ -4,7 +4,7 @@ pyvesync is a library to manage VeSync compatible [smart home devices](#supporte
|
|
|
4
4
|
|
|
5
5
|
<a href="https://webdjoe.github.io/pyvesync/latest"><img src="./docs/assets/docs.svg"></a>
|
|
6
6
|
|
|
7
|
-
**Check out the new [pyvesync documentation](https://webdjoe.github.io/pyvesync/) for usage and full API details.**
|
|
7
|
+
**Check out the new [pyvesync documentation](https://webdjoe.github.io/pyvesync/latest/) for usage and full API details.**
|
|
8
8
|
|
|
9
9
|
## Supported Product Types
|
|
10
10
|
|
|
@@ -19,7 +19,7 @@ pyvesync is a library to manage VeSync compatible [smart home devices](#supporte
|
|
|
19
19
|
|
|
20
20
|
See the [supported devices](https://webdjoe.github.io/pyvesync/latest/supported_devices/) page for a complete list of supported devices and device types.
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## pyvesync v3 Features
|
|
23
23
|
|
|
24
24
|
**BREAKING CHANGES** - The release of pyvesync 3.0 comes with many improvements and new features, but as a result there are many breaking changes. The structure has been completely refactored, so please read through the README and thoroughly test before deploying.
|
|
25
25
|
|
|
@@ -60,9 +60,6 @@ async def main():
|
|
|
60
60
|
# Redact mode is enabled by default, set to False to disable
|
|
61
61
|
manager.redact = False
|
|
62
62
|
|
|
63
|
-
# To print request & response content for all API calls enable verbose mode
|
|
64
|
-
manager.verbose = True
|
|
65
|
-
|
|
66
63
|
# To print logs to file
|
|
67
64
|
manager.log_to_file("pyvesync.log")
|
|
68
65
|
|
|
@@ -76,11 +73,11 @@ async def main():
|
|
|
76
73
|
# manager.devices is a DeviceContainer object
|
|
77
74
|
# manager.devices.outlets is a list of VeSyncOutlet objects
|
|
78
75
|
# manager.devices.switches is a list of VeSyncSwitch objects
|
|
79
|
-
# manager.devices.fans is a list of
|
|
76
|
+
# manager.devices.fans is a list of VeSyncFanBase objects
|
|
80
77
|
# manager.devices.bulbs is a list of VeSyncBulb objects
|
|
81
|
-
# manager.devices.humidifiers is a list of
|
|
82
|
-
# manager.devices.air_purifiers is a list of
|
|
83
|
-
# manager.devices.air_fryers is a list of
|
|
78
|
+
# manager.devices.humidifiers is a list of VeSyncHumidifier objects
|
|
79
|
+
# manager.devices.air_purifiers is a list of VeSyncPurifier objects
|
|
80
|
+
# manager.devices.air_fryers is a list of VeSyncFryer objects
|
|
84
81
|
# manager.devices.thermostats is a list of VeSyncThermostat objects
|
|
85
82
|
|
|
86
83
|
for outlet in manager.devices.outlets:
|
|
@@ -159,7 +156,7 @@ There is a new nomenclature for product types that defines the device class. The
|
|
|
159
156
|
4. `purifier` - Air purifiers (not humidifiers)
|
|
160
157
|
5. `humidifier` - Humidifiers (not air purifiers)
|
|
161
158
|
6. `bulb` - Light bulbs (not dimmers or switches)
|
|
162
|
-
7. `
|
|
159
|
+
7. `air fryer` - Air fryers
|
|
163
160
|
8. `thermostat` - Thermostats
|
|
164
161
|
|
|
165
162
|
See [Supported Devices](#supported-devices) for a complete list of supported devices and models.
|
|
@@ -216,7 +213,8 @@ pip install pyvesync
|
|
|
216
213
|
5. Voltson Smart WiFi Outlet - Rectangle (15A model ESW15-USA)
|
|
217
214
|
6. Two Plug Outdoor Outlet (ESO15-TB) (Each plug is a separate `VeSyncOutlet` object, energy readings are for both plugs combined)
|
|
218
215
|
7. BSDOG / Greensun Smart Outlet Series (BSDOG01, BSDOG02, WYSMTOD16A, WM-PLUG and more)
|
|
219
|
-
8.
|
|
216
|
+
8. WHOGPLUG / Greensun Smart Plug
|
|
217
|
+
9. WYLDR Smart Plug (WYLDR16A1081) (Supports energy monitoring but not energy history)
|
|
220
218
|
|
|
221
219
|
<!--SUPPORTED OUTLETS END-->
|
|
222
220
|
|
|
@@ -269,6 +267,10 @@ pip install pyvesync
|
|
|
269
267
|
|
|
270
268
|
1. Cosori 3.7 Quart Air Fryer (CS137-AF)
|
|
271
269
|
2. Cosori 5.8 Quart Air Fryer (CS158-AF)
|
|
270
|
+
3. Cosori TurboBlaze 6 Quart Air Fryer (CAF-DC601S)
|
|
271
|
+
4. Cosori Dual Blaze 6.8 Quart Air Fryer (CAF-P583S)
|
|
272
|
+
5. Cosori Dual Air Fryer (CAF-TF101S)
|
|
273
|
+
6. Cosori Turbo Tower Pro Smart Air Fryer (CAF-DC111S-AEU)
|
|
272
274
|
|
|
273
275
|
### Thermostats
|
|
274
276
|
|
|
@@ -315,7 +317,8 @@ async def main():
|
|
|
315
317
|
async with VeSync("user", "password") as manager:
|
|
316
318
|
|
|
317
319
|
# If credentials are stored in a file, it can be loaded
|
|
318
|
-
#
|
|
320
|
+
# with no path, .vesync_auth is read from the current directory,
|
|
321
|
+
# then from the home directory
|
|
319
322
|
await manager.load_credentials_from_file()
|
|
320
323
|
# or the file path can be passed
|
|
321
324
|
await manager.load_credentials_from_file("/path/to/token_file")
|
|
@@ -396,25 +399,31 @@ See the [device documentation](https://webdjoe.github.io/pyvesync/latest/devices
|
|
|
396
399
|
|
|
397
400
|
## Debug mode and redact
|
|
398
401
|
|
|
399
|
-
|
|
402
|
+
There are three independent knobs that control logging output:
|
|
403
|
+
|
|
404
|
+
- **Debug logging** - set the `pyvesync` logger level to `DEBUG`. The read-only `manager.debug` property reflects whether debug logging is currently active.
|
|
405
|
+
- **`redact`** - the `redact` argument (default `True`) replaces tokens, account IDs, and other sensitive values (`token`, `password`, `email`, `accountId`, `authKey`, `uuid`, `cid`, `authorizeCode`) with `##_REDACTED_##` so logs can be shared safely. It only has an effect while debug logging is enabled.
|
|
406
|
+
- **`LibraryLogger.verbose`** - set this class attribute to `True` to additionally print the full request & response body of every API call.
|
|
400
407
|
|
|
401
|
-
|
|
408
|
+
### Debug to the console
|
|
402
409
|
|
|
403
|
-
|
|
410
|
+
Setting the `pyvesync` logger to `DEBUG` sends debug output to wherever your logging is configured (the console by default). `redact` stays on so tokens are not exposed:
|
|
404
411
|
|
|
405
412
|
```python
|
|
406
413
|
import logging
|
|
407
414
|
import asyncio
|
|
408
415
|
from pyvesync import VeSync
|
|
416
|
+
from pyvesync.utils.logs import LibraryLogger
|
|
409
417
|
|
|
410
418
|
logger = logging.getLogger("pyvesync")
|
|
411
419
|
logger.setLevel(logging.DEBUG)
|
|
420
|
+
logging.basicConfig() # Send log records to the console
|
|
412
421
|
|
|
413
422
|
|
|
414
423
|
async def main():
|
|
415
424
|
async with VeSync("user", "password") as manager:
|
|
416
|
-
manager.debug = True
|
|
417
425
|
manager.redact = True # True by default
|
|
426
|
+
LibraryLogger.verbose = True # Optional - print full request/response content
|
|
418
427
|
await manager.login()
|
|
419
428
|
await manager.update()
|
|
420
429
|
|
|
@@ -428,17 +437,26 @@ if __name__ == "__main__":
|
|
|
428
437
|
asyncio.run(main())
|
|
429
438
|
```
|
|
430
439
|
|
|
431
|
-
###
|
|
440
|
+
### Debug to a file (recommended for sharing with issues)
|
|
432
441
|
|
|
433
|
-
|
|
442
|
+
The `log_to_file()` method is the simplest way to capture a full debug log. It sets the `pyvesync` logger to `DEBUG` **and** attaches a file handler in one call, so you do not need to configure logging yourself. It also prints to the console by default; pass `stdout=False` to log only to the file. Keep `redact=True` (the default) so the log is safe to attach to a GitHub issue:
|
|
434
443
|
|
|
435
444
|
```python
|
|
436
445
|
import asyncio
|
|
437
446
|
from pyvesync import VeSync
|
|
447
|
+
from pyvesync.utils.logs import LibraryLogger
|
|
448
|
+
|
|
438
449
|
|
|
439
450
|
async def main():
|
|
440
|
-
|
|
441
|
-
|
|
451
|
+
# redact=True is the default - sensitive values are scrubbed from the log
|
|
452
|
+
async with VeSync("user", "password", redact=True) as manager:
|
|
453
|
+
# Enables DEBUG logging and writes it to pyvesync.log
|
|
454
|
+
# stdout=True (the default) also prints the log to the console
|
|
455
|
+
manager.log_to_file("pyvesync.log", stdout=True)
|
|
456
|
+
|
|
457
|
+
# Optional - include the full request & response body of every API call
|
|
458
|
+
LibraryLogger.verbose = True
|
|
459
|
+
|
|
442
460
|
await manager.login()
|
|
443
461
|
await manager.update()
|
|
444
462
|
|
|
@@ -447,11 +465,21 @@ async def main():
|
|
|
447
465
|
await outlet.turn_off()
|
|
448
466
|
outlet.display()
|
|
449
467
|
|
|
468
|
+
|
|
450
469
|
if __name__ == "__main__":
|
|
451
470
|
asyncio.run(main())
|
|
452
|
-
|
|
453
471
|
```
|
|
454
472
|
|
|
473
|
+
## Contribution Expectations
|
|
474
|
+
|
|
475
|
+
Contributions — from humans and AI coding assistants alike — must follow three rules. These keep the library correct and maintainable. See the [contributing guide](https://webdjoe.github.io/pyvesync/latest/development/contributing) for full detail.
|
|
476
|
+
|
|
477
|
+
1. **Follow the intended architecture.** New devices are added through the three-tier hierarchy (base class → concrete device + API mixin → device map), with state in the device's `DeviceState` subclass, models in `models/`, and constants in `pyvesync.const`. API request/response shapes must come from a real packet capture — never invented.
|
|
478
|
+
2. **Verify on real hardware before merge.** New device support and any change to device behavior must be tested on the physical device, and the pull request must state the model and firmware version tested. Testing only through Home Assistant does not count.
|
|
479
|
+
3. **One change per pull request.** Each PR must be a single feature, fix, or edit. Large or mixed PRs that bundle unrelated changes will be asked to be broken up before review.
|
|
480
|
+
|
|
481
|
+
> **Using an AI assistant?** Agent instructions live in [`AGENTS.md`](AGENTS.md), which Codex and most tools read directly; [`CLAUDE.md`](CLAUDE.md) imports it for Claude Code. Point your assistant at it and the [contributing guide](https://webdjoe.github.io/pyvesync/latest/development/contributing). You are responsible for the result: it must follow the architecture, must not fabricate API fields, must not be submitted without real-device testing, and must be a single focused change.
|
|
482
|
+
|
|
455
483
|
## Feature Requests
|
|
456
484
|
|
|
457
485
|
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.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pyvesync"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.5.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"
|
|
@@ -21,7 +21,7 @@ classifiers = [
|
|
|
21
21
|
"Topic :: Home Automation"
|
|
22
22
|
]
|
|
23
23
|
dependencies = [
|
|
24
|
-
"aiohttp>=3.
|
|
24
|
+
"aiohttp>=3.14.4",
|
|
25
25
|
"mashumaro[orjson]>=3.13.1",
|
|
26
26
|
]
|
|
27
27
|
|
|
@@ -36,7 +36,7 @@ dev = [
|
|
|
36
36
|
"pyyaml",
|
|
37
37
|
"pylint",
|
|
38
38
|
"mypy",
|
|
39
|
-
"ruff",
|
|
39
|
+
"ruff==0.15.21",
|
|
40
40
|
"pre-commit",
|
|
41
41
|
"tox",
|
|
42
42
|
"requests",
|
|
@@ -45,7 +45,7 @@ dev = [
|
|
|
45
45
|
docs = [
|
|
46
46
|
"mkdocstrings-python",
|
|
47
47
|
"mkdocs",
|
|
48
|
-
"ruff",
|
|
48
|
+
"ruff==0.15.21",
|
|
49
49
|
"Pygments",
|
|
50
50
|
"mkdocs-material",
|
|
51
51
|
"mkdocstrings",
|