Skip to content

Commit 8090129

Browse files
authored
Merge pull request #404 from webdjoe/dev
fix: Disconnection and Core 200S Parse
2 parents 8ba672f + eb39c59 commit 8090129

File tree

15 files changed

+244
-196
lines changed

15 files changed

+244
-196
lines changed

.github/workflows/RunTest.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
pull_request:
55
branches:
66
- master
7+
- dev
78
push:
89
workflow_dispatch:
910

@@ -44,4 +45,4 @@ jobs:
4445
pytest -v
4546
- name: Fail if any steps failed
4647
run: |
47-
[ "${{ steps.ruff.outcome }}" == "failure" ] || [ "${{ steps.pylint.outcome }}" == "failure" ] || [ "${{ steps.pytest.outcome }}" == "failure" ] && exit 1 || exit 0
48+
[ "${{ steps.ruff.outcome }}" == "failure" ] || [ "${{ steps.pylint.outcome }}" == "failure" ] || [ "${{ steps.pytest.outcome }}" == "failure" ] && exit 1 || exit 0

docs/authentication.md

Lines changed: 43 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -2,68 +2,61 @@
22

33
The VeSync Authentication Module provides a clean separation of authentication logic from the main VeSync class, offering improved maintainability, better error handling, and additional features like token persistence.
44

5-
## Features
6-
7-
- **Flexible Authentication**: Support for both username/password and token-based authentication
8-
- **Token Persistence**: Automatic saving and loading of authentication tokens to/from disk
9-
- **Improved Error Handling**: More granular and descriptive error messages
10-
- **Better Security**: Secure file permissions for token storage
11-
- **Graceful Token Validation**: Automatic validation of existing tokens before use
12-
- **Cross-Region Support**: Automatic handling of region changes during authentication
13-
145
## Usage
156

7+
Username and password must still be provided when instantiating the `VeSync` class, but a token can be loaded instead of logging in. If the loaded token is not valid, the `login()` method will be automatically called.
8+
169
### Basic Username/Password Authentication
1710

1811
```python
1912
import asyncio
2013
from pyvesync import VeSync
2114

2215
async def main():
23-
manager = VeSync(
24-
username="[email protected]",
25-
password="your_password",
26-
country_code="US"
27-
)
28-
29-
# Login
30-
success = await manager.login()
31-
if success:
32-
print("Login successful!")
33-
# Use manager for device operations
34-
await manager.get_devices()
35-
await manager.update_all_devices()
16+
with VeSync(username="[email protected]", password="password") as manager:
17+
# Login
18+
success = await manager.login()
19+
if not success:
20+
print("Login failed!")
21+
return
3622

37-
await manager.__aexit__()
23+
print("Login successful!")
3824

3925
asyncio.run(main())
4026
```
4127

42-
### Token-Based Authentication
28+
### Loading authentication data
29+
30+
The authentication data can be provided to arguments of the `set_credentials()` or `load_credentials_from_file()` methods of the instantiated `VeSync` object.
31+
32+
The credentials needed are: `token`, `account_id`, `country_code`, and `region`.
4333

4434
```python
4535
import asyncio
4636
from pyvesync import VeSync
4737

4838
async def main():
49-
# Use existing token (e.g., from previous login)
50-
manager = VeSync(
51-
token="your_existing_token",
52-
account_id="your_account_id",
53-
country_code="US"
54-
)
55-
56-
# Login with token
57-
success = await manager.login()
58-
if success:
59-
print("Token authentication successful!")
60-
61-
await manager.__aexit__()
39+
with VeSync(username="[email protected]", password="password") as manager:
40+
# Load credentials from a dictionary
41+
credentials = {
42+
"token": "your_token_here",
43+
"account_id": "your_account_id_here",
44+
"country_code": "US",
45+
"region": "US"
46+
}
47+
success = await manager.set_credentials(**credentials)
48+
49+
# Or load from a file
50+
await manager.load_credentials_from_file("path/to/credentials.json")
6251

6352
asyncio.run(main())
6453
```
6554

66-
### Persistent Token Storage
55+
### Credential Storage
56+
57+
Credentials can be saved to a file or output as a json string. If no file path is provided the credentials will be saved to the users home directory as `.vesync_auth`.
58+
59+
The credentials file is a json file that has the keys `token`, `account_id`, `country_code`, and `region`.
6760

6861
```python
6962
import asyncio
@@ -73,142 +66,21 @@ from pyvesync import VeSync
7366
async def main():
7467
token_file = Path.home() / ".vesync_token"
7568

76-
manager = VeSync(
77-
username="[email protected]",
78-
password="your_password",
79-
token_file_path=token_file
80-
)
69+
with VeSync(username="[email protected]", password="password") as manager:
70+
# Login and save credentials to file
71+
success = await manager.login(token_file_path=token_file)
72+
if success:
73+
# Save credentials to file
74+
manager.save_credentials(token_file)
8175

82-
# First login saves token to file
83-
success = await manager.login()
84-
if success:
85-
print("Login successful! Token saved for future use.")
76+
# Output credentials as json string
77+
print(manager.output_credentials())
8678

87-
# Subsequent runs will automatically load the saved token
88-
# and validate it before falling back to username/password
89-
90-
await manager.__aexit__()
79+
print("Login successful and credentials saved!")
80+
else:
81+
print("Login failed!")
9182

9283
asyncio.run(main())
9384
```
9485

95-
### Direct Authentication Management
96-
97-
```python
98-
from pyvesync import VeSync
99-
100-
# Create manager without initial credentials
101-
manager = VeSync()
102-
103-
# Set credentials programmatically
104-
manager.auth.set_credentials(
105-
username="[email protected]",
106-
password="your_password"
107-
)
108-
109-
# Check authentication state
110-
print(f"Is authenticated: {manager.auth.is_authenticated}")
111-
print(f"Username: {manager.auth.username}")
112-
113-
# Clear credentials
114-
manager.auth.clear_credentials()
115-
```
116-
117-
## Authentication Flow
118-
119-
The authentication process follows these steps:
120-
121-
1. **Token Validation**: If a token exists, validate it first
122-
2. **Username/Password Login**: If no valid token, use credentials
123-
3. **Authorization Code Exchange**: Get auth code, then exchange for token
124-
4. **Cross-Region Handling**: Automatically handle region changes
125-
5. **Token Persistence**: Save token to file if path is provided
126-
127-
## VeSyncAuth Class
128-
129-
The `VeSyncAuth` class handles all authentication logic:
130-
131-
### Properties
132-
133-
- `token`: Authentication token
134-
- `account_id`: VeSync account ID
135-
- `country_code`: Country code for the account
136-
- `username`: Account username (read-only)
137-
- `password`: Account password (read-only)
138-
- `is_authenticated`: Boolean indicating if user is authenticated
139-
140-
### Methods
141-
142-
- `login()`: Perform authentication
143-
- `set_credentials()`: Set authentication credentials
144-
- `clear_credentials()`: Clear all stored credentials
145-
- `get_auth_headers()`: Get headers for authenticated API requests
146-
- `to_dict()`: Get authentication state as dictionary
147-
148-
## Migration from Old VeSync Class
149-
150-
The new authentication module is fully backward compatible. Existing code will continue to work:
151-
152-
```python
153-
# Old way (still works)
154-
manager = VeSync("[email protected]", "password")
155-
await manager.login()
156-
157-
# New way (recommended)
158-
manager = VeSync(
159-
username="[email protected]",
160-
password="password",
161-
token_file_path="~/.vesync_token"
162-
)
163-
await manager.login()
164-
```
165-
166-
## Advanced Features
167-
168-
### Custom Token File Location
169-
170-
```python
171-
from pathlib import Path
172-
173-
# Custom location
174-
token_file = Path("/secure/location/vesync_token.json")
175-
manager = VeSync(
176-
username="[email protected]",
177-
password="password",
178-
token_file_path=token_file
179-
)
180-
```
181-
182-
### Token-Only Authentication
183-
184-
```python
185-
# For applications that manage tokens externally
186-
manager = VeSync(
187-
token="externally_managed_token",
188-
account_id="known_account_id"
189-
)
190-
```
191-
192-
### Error Handling
193-
194-
```python
195-
from pyvesync.utils.errors import VeSyncLoginError, VeSyncAPIResponseError
196-
197-
try:
198-
success = await manager.login()
199-
except VeSyncLoginError as e:
200-
print(f"Login failed: {e}")
201-
except VeSyncAPIResponseError as e:
202-
print(f"API error: {e}")
203-
```
204-
205-
## Security Considerations
206-
207-
- Token files are created with restrictive permissions (0o600)
208-
- Sensitive information is not included in string representations
209-
- Credentials are cleared from memory when `clear_credentials()` is called
210-
- Token validation prevents use of expired tokens
211-
212-
## Thread Safety
213-
214-
The authentication module is designed for use with asyncio and is not thread-safe. Use appropriate synchronization if accessing from multiple threads.
86+
For a full list of methods and attributes, refer to the [auth](development/auth_api.md) and [vesync](development/vesync_api.md) documentation.

docs/development/auth_api.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Documentation for `pyvesync.auth` module
2+
3+
This module handles the authentication logic for the VeSync API. It is stored as the `auth` instance attribute of the `VeSync` class.
4+
5+
::: pyvesync.auth.VeSyncAuth
6+
handler: python
7+
options:
8+
group_by_category: true
9+
show_root_heading: true
10+
show_category_heading: true
11+
show_source: false
12+
filters:
13+
- "!.*_dev_test"
14+
- "!set_dev_id"
15+
- "!process_devices"
16+
- "!remove_old_devices"
17+
- "!device_time_check"
18+
merge_init_into_class: true
19+
show_signature_annotations: true

docs/development/capturing.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Packet Capturing for New Device Support
2+
3+
This document outlines the steps to capture network packets for adding support for new devices in the `pyvesync` library. It is intended for developers who want to extend the library's functionality by integrating additional VeSync devices. Packet captures are required in order to add new devices and functionality.
4+
5+
The process outlined below is time consuming and can be difficult. An alternative method is to temporarily share the device. If you would prefer this method, please indicate in an issue or contact the maintainer directly. Sharing a device is done by going to the device settings and selecting "Share Device". Please create a post to notify the maintainers to receive the correct email address to share the device with.
6+
7+
Please do not post a device request without being will to either capture packets or share the device.
8+
9+
## Prerequisites
10+
11+
1. **Mumu Emulator**: Download and install the Mumu Android emulator from [Mumu Player](https://www.mumuplayer.com/). This emulator allows you to run Android apps on your computer. Other emulators may work, but Mumu is known to be compatible with Arm64 apk's and allows `adb root` access.
12+
13+
2. **VeSync App**: The latest VeSync app from apkpure or another apk sharing site.
14+
15+
3. **Charles Proxy**: Download and install Charles Proxy from [Charles](https://www.charlesproxy.com/). The 30
16+
day trial is sufficient for this purpose. If you do like the software, support the developer by purchasing a license.
17+
18+
4. **ADB (Android Debug Bridge)**: Ensure you have ADB installed on your system. This is typically included with Android Studio, but can also be installed separately with Android Command Line Tools. This is the site for [Android Studio](https://developer.android.com/studio). Scroll to the "Command Line Tools Only" section to download just the command line tools. Once installed, ensure adb is in your system PATH. You may have to restart your terminal or IDE to pick up the PATH change. The following path is where the `adb` binary is located: `C:\Users\YOUR_USERNAME\AppData\Local\Android\Skd\platform-tools` on Windows or `/home/YOUR_USERNAME/Android/Sdk/platform-tools` on Linux.
19+
20+
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.
21+
22+
23+
## Steps
24+
25+
1. **Set up project directory**:
26+
- Create a new directory for the project and place the extracted `frida-server` binary in it.
27+
- Move the VeSync (x)apk to the project directory.
28+
- Open a terminal in the project directory.
29+
- Create a virtual environment and install frida:
30+
31+
```bash
32+
python -m venv venv
33+
source venv/bin/activate
34+
# On Windows cmd use `venv\Scripts\activate`
35+
# On powershell use `venv\Scripts\Activate.ps1`
36+
pip install frida-tools
37+
```
38+
39+
2. **Set up Charles Proxy**:
40+
- Open Charles Proxy and go to `Proxy` > `Proxy Settings`. Note the HTTP Proxy port (default is 8888).
41+
- Go to `Help` > `SSL Proxying` > `Save Root Certificate` > `cert format`.
42+
- Save the certificate to the project directory as `cert-der.crt`.
43+
44+
3. **Set up MuMu Emulator**:
45+
- Open the Mumu emulator and install the VeSync app by using the down arrow icon on the top right. Select "Install APK" from the bottom of the menu and choose the VeSync apk in the project directory.
46+
- Configure the proxy in `System Applications` > `Settings` > `Network & Internet` > `Internet` > Gear icon next to the connected network. If charles is running on the same machine, set the proxy hostname to `localhost:8888` (or the port you noted earlier).
47+
- Enable SSL Proxying in Charles by going to `Proxy` > `SSL Proxying Settings` and checking `Enable SSL Proxying`. Add a location with Host: `*` and Port: `*` if not already set.
48+
49+
4. **Configure MuMu to use Charles Proxy**:
50+
- Once the MuMu emulator is running, open a new terminal in the project directory and run:
51+
52+
```bash
53+
adb connect 127.0.0.1:7555
54+
adb root
55+
adb push cert-der.crt /data/local/tmp/
56+
adb push frida-server /data/local/tmp/
57+
adb shell
58+
59+
# This should bring up the android emulator command line
60+
cd /data/local/tmp
61+
chmod +x frida-server
62+
./frida-server
63+
```
64+
65+
- **LEAVE THIS TERMINAL OPEN**. There will be no output from the final command.
66+
67+
5. **Run the frida script**:
68+
- With Mumu and the frida-server terminal running, open a separate terminal in the project directory, and ensure that the virtual environment is activated.
69+
- Run the following command to start frida with the VeSync app:
70+
71+
```bash
72+
frida -U --codeshare akabe1/frida-multiple-unpinning -f com.etekcity.vesyncplatform
73+
```
74+
75+
- This will start the VeSync app and allow charles to capture the packets. You should see output in the terminal indicating that frida has attached to the process and the app will open in the emulator.
76+
- Login to your VeSync account in the app and check that charles is able to capture and decode the packages. The url should start with `https://smartapi.vesync.com` or `https://smartapi.vesync.eu`. On occasion it may start with `https://smartapi.vesyncapi.com` or `https://smartapi.vesyncapi.eu`.
77+
78+
6. **Run actions in the VeSync app**:
79+
- Perform all of the actions, including timers and schedulers. Ensure that after each action you go back to the device list and then back into the device. This ensures that the status of the device is captured after each action.
80+
- If you have multiple devices, perform actions on each device.
81+
82+
7. **Save the Charles session**:
83+
- Once all actions have been performed, stop the frida process by pressing `CTRL+C` in the frida terminal.
84+
- In Charles, go to `File` > `Save Session As...` and save the session as `vesync_session.chls` in the project directory.
85+
86+
8. **Share the capture**:
87+
- **DO NOT** post the capture in an issue. Please create an issue or comment on an issue to notify the maintainers that you have a capture ready to share.
88+
- Files can be shared via discord or email to webdjoe at gmail.

0 commit comments

Comments
 (0)