duosida-ev 0.1.1__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.
- duosida_ev-0.1.1/.gitignore +53 -0
- duosida_ev-0.1.1/CHANGELOG.md +45 -0
- duosida_ev-0.1.1/CLAUDE.md +120 -0
- duosida_ev-0.1.1/LICENSE +21 -0
- duosida_ev-0.1.1/PKG-INFO +340 -0
- duosida_ev-0.1.1/README.md +312 -0
- duosida_ev-0.1.1/docs/SETTINGS.md +81 -0
- duosida_ev-0.1.1/pyproject.toml +43 -0
- duosida_ev-0.1.1/requirements.txt +1 -0
- duosida_ev-0.1.1/src/duosida_ev/__init__.py +47 -0
- duosida_ev-0.1.1/src/duosida_ev/charger.py +718 -0
- duosida_ev-0.1.1/src/duosida_ev/cli.py +389 -0
- duosida_ev-0.1.1/src/duosida_ev/discovery.py +153 -0
- duosida_ev-0.1.1/src/duosida_ev/exceptions.py +38 -0
- duosida_ev-0.1.1/tests/__init__.py +1 -0
- duosida_ev-0.1.1/tests/test_charger.py +336 -0
- duosida_ev-0.1.1/tests/test_discovery.py +157 -0
- duosida_ev-0.1.1/tests/test_protobuf.py +97 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual environments
|
|
24
|
+
.venv/
|
|
25
|
+
venv/
|
|
26
|
+
ENV/
|
|
27
|
+
env/
|
|
28
|
+
|
|
29
|
+
# IDE
|
|
30
|
+
.idea/
|
|
31
|
+
.vscode/
|
|
32
|
+
*.swp
|
|
33
|
+
*.swo
|
|
34
|
+
*~
|
|
35
|
+
|
|
36
|
+
# OS
|
|
37
|
+
.DS_Store
|
|
38
|
+
Thumbs.db
|
|
39
|
+
|
|
40
|
+
# Testing
|
|
41
|
+
.coverage
|
|
42
|
+
.pytest_cache/
|
|
43
|
+
htmlcov/
|
|
44
|
+
|
|
45
|
+
# Build
|
|
46
|
+
*.manifest
|
|
47
|
+
*.spec
|
|
48
|
+
|
|
49
|
+
# Claude Code
|
|
50
|
+
.claude/
|
|
51
|
+
|
|
52
|
+
# uv
|
|
53
|
+
uv.lock
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.1] - 2024-11-19
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Updated README.md to use GitHub repository URL instead of git.dias.pt
|
|
13
|
+
|
|
14
|
+
## [0.1.0] - 2024-11-18
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **Network Discovery**: UDP broadcast discovery of Duosida chargers on local network
|
|
19
|
+
- **Direct TCP Communication**: Bypass cloud API for local control
|
|
20
|
+
- **Real-time Telemetry**: Read voltage, current, power, temperature, energy consumption
|
|
21
|
+
- **Charging Control**:
|
|
22
|
+
- Start/stop charging sessions
|
|
23
|
+
- Set maximum charging current (6-32A)
|
|
24
|
+
- **Configuration Settings**:
|
|
25
|
+
- Connection timeout (30-900s)
|
|
26
|
+
- Max/min voltage limits (265-290V / 70-110V)
|
|
27
|
+
- Max temperature (85-95°C)
|
|
28
|
+
- Direct work mode (plug and charge)
|
|
29
|
+
- LED brightness (0=off, 1=low, 3=high)
|
|
30
|
+
- **JSON Export**: Get telemetry data as JSON for integration
|
|
31
|
+
- **CLI Tool**: Full-featured command-line interface with auto-discovery
|
|
32
|
+
- **Proper Logging**: Python logging module with verbose mode
|
|
33
|
+
- **Custom Exceptions**: DuosidaError hierarchy for error handling
|
|
34
|
+
- **3-Phase Support**: Read voltage/current for all phases
|
|
35
|
+
|
|
36
|
+
### Technical Details
|
|
37
|
+
|
|
38
|
+
- Protocol: Protobuf over TCP port 9988
|
|
39
|
+
- Discovery: UDP broadcast on port 48890/48899
|
|
40
|
+
- 46 unit tests
|
|
41
|
+
- Python 3.6+ compatible
|
|
42
|
+
- No external dependencies (stdlib only)
|
|
43
|
+
|
|
44
|
+
[0.1.1]: https://github.com/americodias/duosida-ev/releases/tag/v0.1.1
|
|
45
|
+
[0.1.0]: https://github.com/americodias/duosida-ev/releases/tag/v0.1.0
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Duosida EV Charger - Direct TCP Control
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
Python library for direct TCP communication with Duosida EV wall chargers, bypassing the cloud API. Provides real-time telemetry and control via the charger's native protobuf protocol.
|
|
6
|
+
|
|
7
|
+
## Package Structure
|
|
8
|
+
|
|
9
|
+
- **src/duosida_ev/charger.py** - Main `DuosidaCharger` class
|
|
10
|
+
- **src/duosida_ev/cli.py** - Command-line interface
|
|
11
|
+
- **src/duosida_ev/discovery.py** - Network discovery
|
|
12
|
+
- **src/duosida_ev/exceptions.py** - Custom exceptions
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from duosida_ev import DuosidaCharger, discover_chargers
|
|
18
|
+
|
|
19
|
+
# Discover chargers
|
|
20
|
+
devices = discover_chargers()
|
|
21
|
+
for device in devices:
|
|
22
|
+
print(f"Found: {device['ip']} - {device['device_id']}")
|
|
23
|
+
|
|
24
|
+
# Connect and get status
|
|
25
|
+
charger = DuosidaCharger(
|
|
26
|
+
host="192.168.1.100",
|
|
27
|
+
device_id="YOUR_DEVICE_ID"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
charger.connect()
|
|
31
|
+
status = charger.get_status()
|
|
32
|
+
print(status)
|
|
33
|
+
charger.disconnect()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### CLI Commands
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Auto-discover and get status
|
|
40
|
+
duosida status
|
|
41
|
+
|
|
42
|
+
# Get status with JSON output
|
|
43
|
+
duosida status --json
|
|
44
|
+
|
|
45
|
+
# Set max current (6-32A)
|
|
46
|
+
duosida set-current 16
|
|
47
|
+
|
|
48
|
+
# Start/stop charging
|
|
49
|
+
duosida start
|
|
50
|
+
duosida stop
|
|
51
|
+
|
|
52
|
+
# Monitor continuously
|
|
53
|
+
duosida monitor
|
|
54
|
+
|
|
55
|
+
# Configuration settings
|
|
56
|
+
duosida set-timeout 120 # 30-900 seconds
|
|
57
|
+
duosida set-max-temp 90 # 85-95°C
|
|
58
|
+
duosida set-max-voltage 280 # 265-290V
|
|
59
|
+
duosida set-min-voltage 90 # 70-110V
|
|
60
|
+
duosida set-direct-mode on # on/off
|
|
61
|
+
duosida set-led-brightness 3 # 0=off, 1=low, 3=high
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Telemetry Fields
|
|
65
|
+
|
|
66
|
+
| Field | Source | Description |
|
|
67
|
+
|-------|--------|-------------|
|
|
68
|
+
| voltage | Field 1 | Line voltage (V) |
|
|
69
|
+
| current | Field 2 | Charging current (A) |
|
|
70
|
+
| current2 | Field 15 | Secondary/average current (A) |
|
|
71
|
+
| temperature_station | Field 8 | Station temperature (°C) |
|
|
72
|
+
| temperature_internal | Field 7 | Internal temperature (°C) |
|
|
73
|
+
| conn_status | Field 17 | Connection status (0-6) |
|
|
74
|
+
| today_consumption | Field 20 | Daily energy (kWh) |
|
|
75
|
+
| session_energy | Field 9 | Session energy (kWh) |
|
|
76
|
+
| timestamp | Field 18 | Reading timestamp |
|
|
77
|
+
| power | Calculated | V × I (W) |
|
|
78
|
+
|
|
79
|
+
## Status Codes
|
|
80
|
+
|
|
81
|
+
Based on [official HA integration](https://github.com/jello1974/duosidaEV-home-assistant):
|
|
82
|
+
|
|
83
|
+
- 0: Available
|
|
84
|
+
- 1: Preparing
|
|
85
|
+
- 2: Charging
|
|
86
|
+
- 3: Cooling
|
|
87
|
+
- 4: SuspendedEV
|
|
88
|
+
- 5: Finished
|
|
89
|
+
- 6: Holiday
|
|
90
|
+
|
|
91
|
+
## Protocol Details
|
|
92
|
+
|
|
93
|
+
- **Port**: 9988 (TCP)
|
|
94
|
+
- **Discovery**: UDP broadcast on port 48890/48899
|
|
95
|
+
- **Message format**: Protobuf with nested fields
|
|
96
|
+
- **Telemetry path**: Field 16 → Field 10 (DataVendorStatusReq)
|
|
97
|
+
|
|
98
|
+
## Dependencies
|
|
99
|
+
|
|
100
|
+
- Python 3.6+
|
|
101
|
+
- No external dependencies (uses only stdlib)
|
|
102
|
+
|
|
103
|
+
## Development Environment
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Activate the virtual environment
|
|
107
|
+
source .venv/bin/activate
|
|
108
|
+
|
|
109
|
+
# Run tests
|
|
110
|
+
python -m pytest tests/
|
|
111
|
+
|
|
112
|
+
# Install in development mode
|
|
113
|
+
pip install -e .
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Notes
|
|
117
|
+
|
|
118
|
+
- Device ID can be found via discovery or in the official Duosida app
|
|
119
|
+
- CLI auto-discovers charger if --host/--device-id not provided
|
|
120
|
+
- Use -v/--verbose for debug output
|
duosida_ev-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Americo Dias
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: duosida-ev
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Python library for direct TCP control of Duosida EV wall chargers
|
|
5
|
+
Project-URL: Homepage, https://github.com/americodias/duosida-ev
|
|
6
|
+
Project-URL: Repository, https://github.com/americodias/duosida-ev
|
|
7
|
+
Project-URL: Issues, https://github.com/americodias/duosida-ev/issues
|
|
8
|
+
Author-email: Americo Dias <americo.dias@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: charger,duosida,electric-vehicle,ev,iot,smart-home
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Topic :: Home Automation
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
+
Requires-Python: >=3.6
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# duosida-ev
|
|
30
|
+
|
|
31
|
+
Python library for direct TCP control of Duosida EV wall chargers, bypassing the cloud API for local control and monitoring.
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
- **Network Discovery**: Find Duosida chargers on your local network
|
|
36
|
+
- **Real-time Telemetry**: Read voltage, current, power, temperature, and energy consumption
|
|
37
|
+
- **Current Control**: Set maximum charging current (6-32A)
|
|
38
|
+
- **Start/Stop Charging**: Remote control to start or stop charging sessions
|
|
39
|
+
- **Configuration Settings**: Connection timeout, max/min voltage, max temperature, direct work mode
|
|
40
|
+
- **JSON Export**: Get telemetry data as JSON for integration with other tools
|
|
41
|
+
- **No Cloud Required**: Direct TCP communication with the charger
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install duosida-ev
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or install from source:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
git clone https://github.com/americodias/duosida-ev.git
|
|
53
|
+
cd duosida-ev
|
|
54
|
+
pip install -e .
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Quick Start
|
|
58
|
+
|
|
59
|
+
### Discover Chargers
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from duosida_ev import discover_chargers
|
|
63
|
+
|
|
64
|
+
devices = discover_chargers()
|
|
65
|
+
for device in devices:
|
|
66
|
+
print(f"Found: {device['ip']}")
|
|
67
|
+
print(f" Device ID: {device['device_id']}")
|
|
68
|
+
print(f" MAC: {device['mac']}")
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Get Status
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from duosida_ev import DuosidaCharger
|
|
75
|
+
|
|
76
|
+
charger = DuosidaCharger(
|
|
77
|
+
host="192.168.1.100",
|
|
78
|
+
device_id="YOUR_DEVICE_ID"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
charger.connect()
|
|
82
|
+
status = charger.get_status()
|
|
83
|
+
print(f"Voltage: {status.voltage}V")
|
|
84
|
+
print(f"Current: {status.current}A")
|
|
85
|
+
print(f"Power: {status.power}W")
|
|
86
|
+
print(f"State: {status.state}")
|
|
87
|
+
charger.disconnect()
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Set Maximum Current
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
charger.connect()
|
|
94
|
+
charger.set_max_current(16) # Set to 16A
|
|
95
|
+
charger.disconnect()
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Configure Charger Settings
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
charger.connect()
|
|
102
|
+
|
|
103
|
+
# Connection timeout (30-900 seconds)
|
|
104
|
+
charger.set_connection_timeout(120)
|
|
105
|
+
|
|
106
|
+
# Temperature limits (85-95°C)
|
|
107
|
+
charger.set_max_temperature(90)
|
|
108
|
+
|
|
109
|
+
# Voltage limits
|
|
110
|
+
charger.set_max_voltage(280) # 265-290V
|
|
111
|
+
charger.set_min_voltage(90) # 70-110V
|
|
112
|
+
|
|
113
|
+
# Direct work mode (plug and charge)
|
|
114
|
+
charger.set_direct_work_mode(True) # Enable
|
|
115
|
+
charger.set_direct_work_mode(False) # Disable
|
|
116
|
+
|
|
117
|
+
# LED brightness (0=off, 1=low, 3=high)
|
|
118
|
+
charger.set_led_brightness(3)
|
|
119
|
+
|
|
120
|
+
# Generic config (any key/value)
|
|
121
|
+
charger.set_config("VendorMaxWorkCurrent", "16")
|
|
122
|
+
|
|
123
|
+
charger.disconnect()
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Start/Stop Charging
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
charger.connect()
|
|
130
|
+
|
|
131
|
+
# Start charging
|
|
132
|
+
charger.start_charging()
|
|
133
|
+
|
|
134
|
+
# Stop charging
|
|
135
|
+
charger.stop_charging()
|
|
136
|
+
|
|
137
|
+
charger.disconnect()
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Get Telemetry as JSON
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
import json
|
|
144
|
+
|
|
145
|
+
charger.connect()
|
|
146
|
+
status = charger.get_status()
|
|
147
|
+
|
|
148
|
+
# Convert to dictionary
|
|
149
|
+
data = status.to_dict()
|
|
150
|
+
print(json.dumps(data, indent=2))
|
|
151
|
+
|
|
152
|
+
# Access individual fields
|
|
153
|
+
print(f"CP Voltage: {status.cp_voltage}V")
|
|
154
|
+
print(f"State: {status.state}")
|
|
155
|
+
|
|
156
|
+
charger.disconnect()
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Monitor Continuously
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
def on_status(status):
|
|
163
|
+
print(f"Power: {status.power}W")
|
|
164
|
+
|
|
165
|
+
charger.connect()
|
|
166
|
+
charger.monitor(interval=2.0, callback=on_status)
|
|
167
|
+
charger.disconnect()
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Command Line Interface
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# Discover chargers on the network
|
|
174
|
+
duosida discover
|
|
175
|
+
|
|
176
|
+
# Get charger status
|
|
177
|
+
duosida status --host 192.168.1.100 --device-id YOUR_DEVICE_ID
|
|
178
|
+
|
|
179
|
+
# Get status in JSON format
|
|
180
|
+
duosida status --host 192.168.1.100 --device-id YOUR_DEVICE_ID --json
|
|
181
|
+
|
|
182
|
+
# Set maximum current
|
|
183
|
+
duosida set-current --host 192.168.1.100 --device-id YOUR_DEVICE_ID 16
|
|
184
|
+
|
|
185
|
+
# Start charging
|
|
186
|
+
duosida start --host 192.168.1.100 --device-id YOUR_DEVICE_ID
|
|
187
|
+
|
|
188
|
+
# Stop charging
|
|
189
|
+
duosida stop --host 192.168.1.100 --device-id YOUR_DEVICE_ID
|
|
190
|
+
|
|
191
|
+
# Monitor continuously
|
|
192
|
+
duosida monitor --host 192.168.1.100 --device-id YOUR_DEVICE_ID
|
|
193
|
+
|
|
194
|
+
# Configuration commands (host only - device ID auto-discovered)
|
|
195
|
+
duosida set-timeout --host 192.168.1.100 120 # 30-900 seconds
|
|
196
|
+
duosida set-max-temp --host 192.168.1.100 90 # 85-95°C
|
|
197
|
+
duosida set-max-voltage --host 192.168.1.100 280 # 265-290V
|
|
198
|
+
duosida set-min-voltage --host 192.168.1.100 90 # 70-110V
|
|
199
|
+
duosida set-direct-mode --host 192.168.1.100 on # on/off
|
|
200
|
+
duosida set-led-brightness --host 192.168.1.100 3 # 0=off, 1=low, 3=high
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Telemetry Fields
|
|
204
|
+
|
|
205
|
+
| Field | Description |
|
|
206
|
+
|-------|-------------|
|
|
207
|
+
| `voltage` | Line voltage (V) |
|
|
208
|
+
| `current` | Charging current (A) |
|
|
209
|
+
| `power` | Power consumption (W) |
|
|
210
|
+
| `temperature_station` | Station temperature (°C) |
|
|
211
|
+
| `state` | Connection status (Available, Charging, Finished, etc.) |
|
|
212
|
+
| `today_consumption` | Daily energy consumption (kWh) |
|
|
213
|
+
| `session_energy` | Current session energy (kWh) |
|
|
214
|
+
|
|
215
|
+
## Status Codes
|
|
216
|
+
|
|
217
|
+
| Code | State |
|
|
218
|
+
|------|-------|
|
|
219
|
+
| 0 | Available |
|
|
220
|
+
| 1 | Preparing |
|
|
221
|
+
| 2 | Charging |
|
|
222
|
+
| 3 | Cooling |
|
|
223
|
+
| 4 | SuspendedEV |
|
|
224
|
+
| 5 | Finished |
|
|
225
|
+
| 6 | Holiday |
|
|
226
|
+
|
|
227
|
+
## Finding Your Device ID
|
|
228
|
+
|
|
229
|
+
The device ID can be found:
|
|
230
|
+
- On the QR code label on the left side of the charger
|
|
231
|
+
- Using the `duosida discover` command (when on the same network)
|
|
232
|
+
- In the official Duosida mobile app
|
|
233
|
+
- In Home Assistant integration settings
|
|
234
|
+
|
|
235
|
+
## Requirements
|
|
236
|
+
|
|
237
|
+
- Python 3.6+
|
|
238
|
+
- No external dependencies (uses only standard library)
|
|
239
|
+
|
|
240
|
+
## Protocol Details
|
|
241
|
+
|
|
242
|
+
- **Port**: 9988 (TCP)
|
|
243
|
+
- **Message Format**: Protobuf
|
|
244
|
+
- **Discovery**: UDP broadcast on port 48890/48899
|
|
245
|
+
|
|
246
|
+
See [Settings Reference](docs/SETTINGS.md) for detailed documentation on charger configuration options (Direct Work Mode, Level Detection, etc.).
|
|
247
|
+
|
|
248
|
+
## Capturing Network Traffic
|
|
249
|
+
|
|
250
|
+
To capture traffic between the Duosida app and charger for reverse engineering, you can use Wireshark on a computer connected to the same network, or use tcpdump on your router if it supports SSH access.
|
|
251
|
+
|
|
252
|
+
### Using Wireshark
|
|
253
|
+
|
|
254
|
+
1. Install [Wireshark](https://www.wireshark.org/)
|
|
255
|
+
2. Connect your computer to the same network as the charger
|
|
256
|
+
3. Start capture with filter: `host <charger-ip> and tcp port 9988`
|
|
257
|
+
4. Use the Duosida app to interact with the charger
|
|
258
|
+
5. Stop capture and save the `.pcap` file
|
|
259
|
+
|
|
260
|
+
### Using tcpdump on Router
|
|
261
|
+
|
|
262
|
+
If your router supports SSH (OpenWrt, DD-WRT, etc.):
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
ssh root@<router-ip>
|
|
266
|
+
|
|
267
|
+
# Capture traffic to/from charger
|
|
268
|
+
tcpdump -i br-lan -w /tmp/charger_capture.pcap \
|
|
269
|
+
'host <charger-ip> and tcp port 9988'
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Download the capture:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
scp root@<router-ip>:/tmp/charger_capture.pcap ./charger_capture.pcap
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
<details>
|
|
279
|
+
<summary>UniFi Dream Machine Pro specific instructions</summary>
|
|
280
|
+
|
|
281
|
+
For UDM Pro with separate access points, you need to SSH into the Access Point where the phone or charger is connected (not the UDM Pro itself, since local traffic may not pass through the router):
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
# SSH into the Access Point (not the UDM Pro)
|
|
285
|
+
ssh root@<access-point-ip>
|
|
286
|
+
|
|
287
|
+
# Capture on the wireless interface (ra2) for your IoT VLAN
|
|
288
|
+
tcpdump -i ra2 -w /tmp/charger_capture.pcap \
|
|
289
|
+
'host 192.168.1.100 and host 192.168.1.50 and tcp port 9988'
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Options:
|
|
293
|
+
- `-i ra2` - Interface for 2.4GHz/5GHz AP (wireless)
|
|
294
|
+
- `host 192.168.1.100` - Charger IP
|
|
295
|
+
- `host 192.168.1.50` - Phone IP (update as needed)
|
|
296
|
+
|
|
297
|
+
Alternative - capture everything for 30 seconds:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
timeout 30 tcpdump -i ra2 -w /tmp/charger_full.pcap \
|
|
301
|
+
'host 192.168.1.100 and tcp port 9988'
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Download the capture from the AP:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
scp root@<access-point-ip>:/tmp/charger_capture.pcap ./charger_capture.pcap
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
</details>
|
|
311
|
+
|
|
312
|
+
## TODO
|
|
313
|
+
|
|
314
|
+
Features available in the [cloud API](https://github.com/jello1974/duosidaEV-home-assistant) but not yet implemented:
|
|
315
|
+
|
|
316
|
+
- [x] **Start/Stop Charging** - Remote control to start or stop charging session
|
|
317
|
+
- [x] **Level Detection** - CP voltage display based on charging state (IEC 61851-1)
|
|
318
|
+
- [x] **Direct Work Mode** - Toggle VendorDirectWorkMode setting (plug and charge)
|
|
319
|
+
- [x] **3-Phase Support** - Read voltage/current for L2 and L3 phases (voltage2, voltage3, current2, current3)
|
|
320
|
+
- [x] **Configuration Settings** - Connection timeout, max/min voltage, max temperature
|
|
321
|
+
- [x] **LED Brightness** - Adjust display brightness (0=off, 1=low, 3=high)
|
|
322
|
+
- [ ] **Charging Records** - Retrieve historical charging sessions
|
|
323
|
+
- [ ] **Accumulated Energy** - Total lifetime energy consumption (may be cloud-only)
|
|
324
|
+
|
|
325
|
+
## License
|
|
326
|
+
|
|
327
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
328
|
+
|
|
329
|
+
## Contributing
|
|
330
|
+
|
|
331
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
332
|
+
|
|
333
|
+
## Acknowledgments
|
|
334
|
+
|
|
335
|
+
This library was created by reverse-engineering the TCP communication between the official Duosida app (orange icon, local control) and the charger. Note that Duosida has two apps - the orange one uses direct local communication while the blue one uses the cloud API.
|
|
336
|
+
|
|
337
|
+
The reverse engineering and code development was mostly done using [Claude Code](https://claude.ai/claude-code) and [Genspark](https://www.genspark.ai/).
|
|
338
|
+
|
|
339
|
+
**References:**
|
|
340
|
+
- [Home Assistant Duosida integration](https://github.com/jello1974/duosidaEV-home-assistant) - Cloud API integration, used as reference for status codes and feature identification
|