Skip to content

Commit 1496a5e

Browse files
authored
fix: Multiple models outlet support and logging logic (#425)
- Fix Core purifiers data model bug - Fix ESW03-USA and ESW01-USA device support - Documentation and Usage Improvements - Added contributing documentation with details on device captures - Clean up logging logic for the library to not change the loggers. Debug logging must now be enabled outside of the library. - Fix smart tower fan levels - Removed duplicate mode for 6000s - Fix support for WHOPLUG and BSDOG01/02 outlets
2 parents ef0d1bd + 6e38458 commit 1496a5e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1782
-955
lines changed

.github/dependabot.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: 2
2+
updates:
3+
# Enable version updates for Python
4+
- package-ecosystem: "github-actions"
5+
directory: "/"
6+
schedule:
7+
interval: "weekly"
8+
- package-ecosystem: "pip"
9+
directory: "/"
10+
schedule:
11+
interval: "weekly"

README.md

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,9 @@ async def main():
5555
country_code="US", # Optional - country Code to select correct server
5656
session=session, # Optional - aiohttp.ClientSession
5757
time_zone="America/New_York", # Optional - Timezone, defaults to America/New_York
58-
debug=False, # Optional - Debug output
5958
redact=True # Optional - Redact sensitive information from logs
6059
) as manager:
6160

62-
# To enable debug mode - prints request and response content for
63-
# api calls that return an error code
64-
manager.debug = True
6561
# Redact mode is enabled by default, set to False to disable
6662
manager.redact = False
6763

@@ -148,8 +144,7 @@ VeSync(
148144
password: str,
149145
country_code: str = DEFAULT_COUNTRY_CODE, # US
150146
session: ClientSession | None = None,
151-
time_zone: str = DEFAULT_TZ # America/New_York
152-
debug: bool = False,
147+
time_zone: str = DEFAULT_TZ # America/New_York,
153148
redact: bool = True,
154149
)
155150
```
@@ -279,7 +274,7 @@ from pyvesync import VeSync
279274
from pyvesync.logs import VeSyncLoginError
280275

281276
# VeSync is an asynchronous context manager
282-
# VeSync(username, password, debug=False, redact=True, session=None)
277+
# VeSync(username, password, redact=True, session=None)
283278

284279
async def main():
285280
async with VeSync("user", "password") as manager:
@@ -304,15 +299,15 @@ if __name__ == "__main__":
304299
asyncio.run(main())
305300
```
306301

307-
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.
302+
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.md) for more details.
308303

309304
```python
310305
import asyncio
311306
from pyvesync import VeSync
312307
from pyvesync.logs import VeSyncLoginError
313308

314309
# VeSync is an asynchronous context manager
315-
# VeSync(username, password, debug=False, redact=True, session=None)
310+
# VeSync(username, password, redact=True, session=None)
316311

317312
async def main():
318313
async with VeSync("user", "password") as manager:
@@ -357,7 +352,7 @@ if __name__ == "__main__":
357352
asyncio.run(main())
358353
```
359354

360-
Devices are stored in the respective lists in the instantiated `VeSync` class:
355+
Devices are stored in the `VeSync.devices` attribute, which is a `DeviceContainer` instance that acts as a mutable set. The `DeviceContainer` has properties for each product type that return lists of device instances:
361356

362357
```python
363358
await manager.login() # Asynchronous
@@ -394,15 +389,22 @@ See the [device documentation](https://webdjoe.github.io/pyvesync/latest/devices
394389

395390
## Debug mode and redact
396391

397-
To make it easier to debug, there is a `debug` argument in the `VeSync` method. This prints out your device list and any other debug log messages.
392+
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.
398393

399394
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`.
400395

396+
This is an example of debug mode with redact enabled:
397+
401398
```python
399+
import logging
402400
import asyncio
403401
import aiohttp
404402
from pyvesync.vesync import VeSync
405403

404+
logger = logging.getLogger("pyvesync")
405+
logger.setLevel(logging.DEBUG)
406+
407+
406408
async def main():
407409
async with VeSync("user", "password") as manager:
408410
manager.debug = True
@@ -420,6 +422,31 @@ if __name__ == "__main__":
420422
asyncio.run(main())
421423
```
422424

425+
### Logging to File
426+
427+
To log to a file, use the `log_to_file()` method of the `VeSync` class. Pass the file path as an argument.
428+
429+
```python
430+
431+
import asyncio
432+
from pyvesync import VeSync
433+
434+
async def main():
435+
async with VeSync("user", "password") as manager:
436+
manager.log_to_file("pyvesync.log", level=logging.DEBUG, stdout=True) # stdout argument prints log to console as well
437+
await manager.login()
438+
await manager.update()
439+
440+
outlet = manager.outlets[0]
441+
await outlet.update()
442+
await outlet.turn_off()
443+
outlet.display()
444+
445+
if __name__ == "__main__":
446+
asyncio.run(main())
447+
448+
```
449+
423450
## Feature Requests
424451

425452
Before filing an issue to request a new feature or device, please ensure that you will take the time to test the feature throuroughly. 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.
@@ -446,7 +473,7 @@ pip install git+https://github.com/webdjoe/pyvesync.git@refs/pull/PR_NUMBER/head
446473

447474
Test functionality with a script, please adjust methods and logging statements to the device you are testing.
448475

449-
`test.py`
476+
See `[testing_scripts](./testing_scripts/README.md)` for a fully functioning test script for all devices.
450477

451478
```python
452479
import asyncio
@@ -456,7 +483,10 @@ import json
456483
from functool import chain
457484
from pyvesync import VeSync
458485

459-
logger = logging.getLogger(__name__)
486+
vs_logger = logging.getLogger("pyvesync")
487+
vs_logger.setLevel(logging.DEBUG)
488+
489+
logger = logging.getLogger('pyvesync_test')
460490
logger.setLevel(logging.DEBUG)
461491

462492
USERNAME = "YOUR USERNAME"
@@ -466,7 +496,7 @@ DEVICE_NAME = "Device" # Device to test
466496

467497
async def test_device():
468498
# Instantiate VeSync class and login
469-
async with VeSync(USERNAME, PASSWORD, debug=True, redact=True) as manager:
499+
async with VeSync(USERNAME, PASSWORD, redact=True) as manager:
470500
await manager.login()
471501

472502
# Pull and update devices
@@ -525,35 +555,11 @@ if __name__ == "__main__":
525555

526556
## Device Requests
527557

528-
SSL pinning makes capturing packets much harder. In order to be able to capture packets, SSL pinning needs to be disabled before running an SSL proxy. Use an Android emulator such as Android Studio, which is available for Windows and Linux for free. Download the APK from APKPure or a similiar site and use [Objection](https://github.com/sensepost/objection) or [Frida](https://frida.re/docs/gadget/). Followed by capturing the packets with Charles Proxy or another SSL proxy application.
529-
530-
Be sure to capture all packets from the device list and each of the possible device menus and actions. Please redact the `accountid` and `token` from the captured packets. If you feel you must redact other keys, please do not delete them entirely. Replace letters with "A" and numbers with "1", leave all punctuation intact and maintain length.
531-
532-
For example:
533-
534-
Before:
535-
536-
```json
537-
{
538-
"tk": "abc123abc123==3rf",
539-
"accountId": "123456789",
540-
"cid": "abcdef12-3gh-ij"
541-
}
542-
```
543-
544-
After:
545-
546-
```json
547-
{
548-
"tk": "AAA111AAA111==1AA",
549-
"accountId": "111111111",
550-
"cid": "AAAAAA11-1AA-AA"
551-
}
552-
```
558+
If you would like to request a new device to be added to the library, please open an issue on GitHub. Be sure to include the device model number and a link to the product page. If you are able to provide packet captures or are willing to share the device temporarily, please indicate that in the issue. See the [Packet Capturing for New Device Support](https://webdjoe.github.io/pyvesync/latest/development/capturing.md) document for more details.
553559

554560
## Contributing
555561

556-
All [contributions](CONTRIBUTING.md) are welcome.
562+
All [contributions](https://webdjoe.github.io/pyvesync/latest/development/CONTRIBUTING.md) are welcome.
557563

558564
This project is licensed under [MIT](LICENSE).
559565

docs/authentication.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ async def main():
7474
manager.save_credentials(token_file)
7575

7676
# Output credentials as json string
77-
print(manager.output_credentials())
77+
print(manager.output_credentials_json())
78+
79+
# Output credentials as dictionary
80+
print(manager.output_credentials_dict())
7881

7982
print("Login successful and credentials saved!")
8083
else:

docs/development/capturing.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ day trial is sufficient for this purpose. If you do like the software, support t
1919

2020
5. **frida-server**: Download the latest frida-server from [frida-server](https://github.com/frida/frida/releases). Choose the release that matches the architecture of the MuMu emulator - `frida-server-x.x.x-android-x86_x64.xz`. Extract the `frida-server` binary and place it in the project directory.
2121

22-
2322
## Steps
2423

2524
1. **Set up project directory**:

docs/development/contributing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,4 @@ Specific test environments:
5656

5757
## Requests to Add Devices
5858

59-
Please see [CAPTURING.md](CAPTURING.md) for instructions on how to capture the necessary information to add a new device.
59+
Please see [CAPTURING.md](./capturing.md) for instructions on how to capture the necessary information to add a new device.

docs/devices/outlets.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
- [Etekcity 15A Outlet][pyvesync.devices.vesyncoutlet.VeSyncOutlet15A]
1111
- [Etekcity 15A Outdoor Dual Outlet][pyvesync.devices.vesyncoutlet.VeSyncOutdoorPlug]
1212
- [Etekcity 10A USA Outlet][pyvesync.devices.vesyncoutlet.VeSyncESW10USA]
13-
- [VeSync BSODG Smart Outlet][pyvesync.devices.vesyncoutlet.VeSyncOutletBSDGO1]
13+
- [VeSync BSODG Smart Outlet][pyvesync.devices.vesyncoutlet.VeSyncBSDOGPlug]
14+
- [VeSync Greensun WHOPLUG Smart Outlet][pyvesync.devices.vesyncoutlet.VeSyncOutletWHOGPlug]
1415
- [VeSyncOutlet Base Class][pyvesync.base_devices.outlet_base.VeSyncOutlet]
1516

1617
::: pyvesync.base_devices.outlet_base.OutletState
@@ -110,7 +111,7 @@
110111
summary:
111112
functions: false
112113
group_by_category: true
113-
toc_label: "VeSyncOutlet BSDGO1"
114+
toc_label: "VeSyncOutlet ESW10"
114115
show_root_heading: true
115116
show_root_toc_entry: true
116117
show_category_heading: true
@@ -121,7 +122,7 @@
121122
ignore_init_summary: true
122123
merge_init_into_class: false
123124

124-
::: pyvesync.devices.vesyncoutlet.VeSyncOutletBSDGO1
125+
::: pyvesync.devices.vesyncoutlet.VeSyncBSDOGPlug
125126
options:
126127
filters:
127128
- "!^_.*"
@@ -139,6 +140,24 @@
139140
ignore_init_summary: true
140141
merge_init_into_class: false
141142

143+
::: pyvesync.devices.vesyncoutlet.VeSyncOutletWHOGPlug
144+
options:
145+
filters:
146+
- "!^_.*"
147+
summary:
148+
functions: false
149+
group_by_category: true
150+
toc_label: "VeSyncOutlet WHOGPlug"
151+
show_root_heading: true
152+
show_root_toc_entry: true
153+
show_category_heading: true
154+
show_source: true
155+
show_if_no_docstring: true
156+
inherited_members: true
157+
docstring_options:
158+
ignore_init_summary: true
159+
merge_init_into_class: false
160+
142161
::: pyvesync.base_devices.outlet_base.VeSyncOutlet
143162
options:
144163
filters:

0 commit comments

Comments
 (0)