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.
Files changed (64) hide show
  1. {pyvesync-3.4.2/src/pyvesync.egg-info → pyvesync-3.5.0}/PKG-INFO +53 -25
  2. {pyvesync-3.4.2 → pyvesync-3.5.0}/README.md +49 -21
  3. {pyvesync-3.4.2 → pyvesync-3.5.0}/pyproject.toml +4 -4
  4. pyvesync-3.5.0/requirements.txt +2 -0
  5. pyvesync-3.5.0/src/pyvesync/base_devices/fryer_base.py +1337 -0
  6. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/humidifier_base.py +50 -0
  7. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/outlet_base.py +18 -0
  8. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/const.py +527 -9
  9. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/device_container.py +11 -2
  10. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/device_map.py +766 -24
  11. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesynchumidifier.py +192 -3
  12. pyvesync-3.5.0/src/pyvesync/devices/vesynckitchen.py +1089 -0
  13. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesyncoutlet.py +10 -0
  14. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesyncthermostat.py +2 -2
  15. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/bypass_models.py +2 -1
  16. pyvesync-3.5.0/src/pyvesync/models/fryer_models.py +312 -0
  17. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/humidifier_models.py +15 -0
  18. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/colors.py +127 -0
  19. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/errors.py +47 -23
  20. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/helpers.py +10 -0
  21. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/vesync.py +12 -5
  22. {pyvesync-3.4.2 → pyvesync-3.5.0/src/pyvesync.egg-info}/PKG-INFO +53 -25
  23. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync.egg-info/requires.txt +3 -3
  24. pyvesync-3.4.2/requirements.txt +0 -3
  25. pyvesync-3.4.2/src/pyvesync/base_devices/fryer_base.py +0 -68
  26. pyvesync-3.4.2/src/pyvesync/devices/vesynckitchen.py +0 -653
  27. pyvesync-3.4.2/src/pyvesync/models/fryer_models.py +0 -34
  28. {pyvesync-3.4.2 → pyvesync-3.5.0}/LICENSE +0 -0
  29. {pyvesync-3.4.2 → pyvesync-3.5.0}/MANIFEST.in +0 -0
  30. {pyvesync-3.4.2 → pyvesync-3.5.0}/setup.cfg +0 -0
  31. {pyvesync-3.4.2 → pyvesync-3.5.0}/setup.py +0 -0
  32. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/__init__.py +0 -0
  33. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/auth.py +0 -0
  34. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/__init__.py +0 -0
  35. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/bulb_base.py +0 -0
  36. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/fan_base.py +0 -0
  37. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/purifier_base.py +0 -0
  38. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/switch_base.py +0 -0
  39. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/thermostat_base.py +0 -0
  40. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/base_devices/vesyncbasedevice.py +0 -0
  41. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/__init__.py +0 -0
  42. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesyncbulb.py +0 -0
  43. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesyncfan.py +0 -0
  44. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesyncpurifier.py +0 -0
  45. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/devices/vesyncswitch.py +0 -0
  46. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/__init__.py +0 -0
  47. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/base_models.py +0 -0
  48. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/bulb_models.py +0 -0
  49. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/fan_models.py +0 -0
  50. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/home_models.py +0 -0
  51. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/outlet_models.py +0 -0
  52. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/purifier_models.py +0 -0
  53. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/switch_models.py +0 -0
  54. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/thermostat_models.py +0 -0
  55. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/models/vesync_models.py +0 -0
  56. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/py.typed +0 -0
  57. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/__init__.py +0 -0
  58. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/device_mixins.py +0 -0
  59. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/enum_utils.py +0 -0
  60. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/utils/logs.py +0 -0
  61. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync/vesynchome.py +0 -0
  62. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync.egg-info/SOURCES.txt +0 -0
  63. {pyvesync-3.4.2 → pyvesync-3.5.0}/src/pyvesync.egg-info/dependency_links.txt +0 -0
  64. {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.4.2
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.8.1
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
- ## What's new in pyvesync 3.0
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 VeSyncFan objects
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 VeSyncHumid objects
130
- # manager.devices.air_purifiers is a list of VeSyncAir objects
131
- # manager.devices.air_fryers is a list of VeSyncAirFryer objects
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. `airfryer` - Air fryers
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. WHOPLUG / Greensun Smart Outlet
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
- # the default location is ~/.vesync_token
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
- To set debug, use the `logger` object in the `VeSync` class. Setting the logger level to `DEBUG` will print debug information to the console. The `log_to_file()` method can be used to log to a file.
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
- The `redact` argument removes any tokens and account identifiers from the output to allow for easier sharing. The `redact` argument has no impact if `debug` is not `True`.
456
+ ### Debug to the console
450
457
 
451
- This is an example of debug mode with redact enabled:
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
- ### Logging to File
488
+ ### Debug to a file (recommended for sharing with issues)
480
489
 
481
- To log to a file, use the `log_to_file()` method of the `VeSync` class. Pass the file path as an argument.
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
- async with VeSync("user", "password") as manager:
489
- manager.log_to_file("pyvesync.log", stdout=True) # stdout argument prints log to console as well
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
- ## What's new in pyvesync 3.0
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 VeSyncFan objects
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 VeSyncHumid objects
82
- # manager.devices.air_purifiers is a list of VeSyncAir objects
83
- # manager.devices.air_fryers is a list of VeSyncAirFryer objects
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. `airfryer` - Air fryers
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. WHOPLUG / Greensun Smart Outlet
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
- # the default location is ~/.vesync_token
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
- To set debug, use the `logger` object in the `VeSync` class. Setting the logger level to `DEBUG` will print debug information to the console. The `log_to_file()` method can be used to log to a file.
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
- The `redact` argument removes any tokens and account identifiers from the output to allow for easier sharing. The `redact` argument has no impact if `debug` is not `True`.
408
+ ### Debug to the console
402
409
 
403
- This is an example of debug mode with redact enabled:
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
- ### Logging to File
440
+ ### Debug to a file (recommended for sharing with issues)
432
441
 
433
- To log to a file, use the `log_to_file()` method of the `VeSync` class. Pass the file path as an argument.
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
- async with VeSync("user", "password") as manager:
441
- manager.log_to_file("pyvesync.log", stdout=True) # stdout argument prints log to console as well
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.4.2"
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.8.1",
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",
@@ -0,0 +1,2 @@
1
+ aiohttp>=3.14.4
2
+ mashumaro[orjson]>=3.13.1