Skip to main content

Python library for direct TCP control of Duosida EV wall chargers

Project description

duosida-ev

Python library for direct TCP control of Duosida EV wall chargers, bypassing the cloud API for local control and monitoring.

Features

  • Network Discovery: Find Duosida chargers on your local network
  • Real-time Telemetry: Read voltage, current, power, temperature, and energy consumption
  • Current Control: Set maximum charging current (6-32A)
  • Start/Stop Charging: Remote control to start or stop charging sessions
  • Configuration Settings: Connection timeout, max/min voltage, max temperature, direct work mode
  • JSON Export: Get telemetry data as JSON for integration with other tools
  • No Cloud Required: Direct TCP communication with the charger

Installation

pip install duosida-ev

Or install from source:

git clone https://github.com/americodias/duosida-ev.git
cd duosida-ev
pip install -e .

Quick Start

Discover Chargers

from duosida_ev import discover_chargers

devices = discover_chargers()
for device in devices:
    print(f"Found: {device['ip']}")
    print(f"  Device ID: {device['device_id']}")
    print(f"  MAC: {device['mac']}")

Get Status

from duosida_ev import DuosidaCharger

charger = DuosidaCharger(
    host="192.168.1.100",
    device_id="YOUR_DEVICE_ID"
)

charger.connect()
status = charger.get_status()
print(f"Voltage: {status.voltage}V")
print(f"Current: {status.current}A")
print(f"Power: {status.power}W")
print(f"State: {status.state}")
charger.disconnect()

Set Maximum Current

charger.connect()
charger.set_max_current(16)  # Set to 16A
charger.disconnect()

Configure Charger Settings

charger.connect()

# Connection timeout (30-900 seconds)
charger.set_connection_timeout(120)

# Temperature limits (85-95°C)
charger.set_max_temperature(90)

# Voltage limits
charger.set_max_voltage(280)    # 265-290V
charger.set_min_voltage(90)     # 70-110V

# Direct work mode (plug and charge)
charger.set_direct_work_mode(True)   # Enable
charger.set_direct_work_mode(False)  # Disable

# LED brightness (0=off, 1=low, 3=high)
charger.set_led_brightness(3)

# Generic config (any key/value)
charger.set_config("VendorMaxWorkCurrent", "16")

charger.disconnect()

Start/Stop Charging

charger.connect()

# Start charging
charger.start_charging()

# Stop charging
charger.stop_charging()

charger.disconnect()

Get Telemetry as JSON

import json

charger.connect()
status = charger.get_status()

# Convert to dictionary
data = status.to_dict()
print(json.dumps(data, indent=2))

# Access individual fields
print(f"CP Voltage: {status.cp_voltage}V")
print(f"State: {status.state}")

charger.disconnect()

Monitor Continuously

def on_status(status):
    print(f"Power: {status.power}W")

charger.connect()
charger.monitor(interval=2.0, callback=on_status)
charger.disconnect()

Command Line Interface

# Discover chargers on the network
duosida discover

# Get charger status
duosida status --host 192.168.1.100 --device-id YOUR_DEVICE_ID

# Get status in JSON format
duosida status --host 192.168.1.100 --device-id YOUR_DEVICE_ID --json

# Set maximum current
duosida set-current --host 192.168.1.100 --device-id YOUR_DEVICE_ID 16

# Start charging
duosida start --host 192.168.1.100 --device-id YOUR_DEVICE_ID

# Stop charging
duosida stop --host 192.168.1.100 --device-id YOUR_DEVICE_ID

# Monitor continuously
duosida monitor --host 192.168.1.100 --device-id YOUR_DEVICE_ID

# Configuration commands (host only - device ID auto-discovered)
duosida set-timeout --host 192.168.1.100 120          # 30-900 seconds
duosida set-max-temp --host 192.168.1.100 90          # 85-95°C
duosida set-max-voltage --host 192.168.1.100 280      # 265-290V
duosida set-min-voltage --host 192.168.1.100 90       # 70-110V
duosida set-direct-mode --host 192.168.1.100 on       # on/off
duosida set-led-brightness --host 192.168.1.100 3     # 0=off, 1=low, 3=high

Telemetry Fields

Field Description
conn_status Connection status code (0-6)
cp_voltage Control Pilot voltage (V)
state Human-readable status (Available, Charging, Finished, etc.)
voltage Line voltage L1 (V)
voltage_l2 Line voltage L2 (V)
voltage_l3 Line voltage L3 (V)
current Charging current L1 (A)
current_l2 Charging current L2 (A)
current_l3 Charging current L3 (A)
power Power consumption (W)
temperature_station Station temperature (°C)
session_energy Current session energy (kWh)
session_time Session duration (minutes)
device_id Device identifier
model Device model
manufacturer Manufacturer
firmware Firmware version

Status Codes

Code State
0 Available
1 Preparing
2 Charging
3 Cooling
4 SuspendedEV
5 Finished
6 Holiday

Finding Your Device ID

The device ID can be found:

  • On the QR code label on the left side of the charger
  • Using the duosida discover command (when on the same network)
  • In the official Duosida mobile app
  • In Home Assistant integration settings

Requirements

  • Python 3.6+
  • No external dependencies (uses only standard library)

Protocol Details

  • Port: 9988 (TCP)
  • Message Format: Protobuf
  • Discovery: UDP broadcast on port 48890/48899

See Settings Reference for detailed documentation on charger configuration options (Direct Work Mode, Level Detection, etc.).

Capturing Network Traffic

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.

Using Wireshark

  1. Install Wireshark
  2. Connect your computer to the same network as the charger
  3. Start capture with filter: host <charger-ip> and tcp port 9988
  4. Use the Duosida app to interact with the charger
  5. Stop capture and save the .pcap file

Using tcpdump on Router

If your router supports SSH (OpenWrt, DD-WRT, etc.):

ssh root@<router-ip>

# Capture traffic to/from charger
tcpdump -i br-lan -w /tmp/charger_capture.pcap \
  'host <charger-ip> and tcp port 9988'

Download the capture:

scp root@<router-ip>:/tmp/charger_capture.pcap ./charger_capture.pcap
UniFi Dream Machine Pro specific instructions

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):

# SSH into the Access Point (not the UDM Pro)
ssh root@<access-point-ip>

# Capture on the wireless interface (ra2) for your IoT VLAN
tcpdump -i ra2 -w /tmp/charger_capture.pcap \
  'host 192.168.1.100 and host 192.168.1.50 and tcp port 9988'

Options:

  • -i ra2 - Interface for 2.4GHz/5GHz AP (wireless)
  • host 192.168.1.100 - Charger IP
  • host 192.168.1.50 - Phone IP (update as needed)

Alternative - capture everything for 30 seconds:

timeout 30 tcpdump -i ra2 -w /tmp/charger_full.pcap \
  'host 192.168.1.100 and tcp port 9988'

Download the capture from the AP:

scp root@<access-point-ip>:/tmp/charger_capture.pcap ./charger_capture.pcap

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Acknowledgments

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.

The reverse engineering and code development was mostly done using Claude Code and Genspark.

References:

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

duosida_ev-0.1.2.tar.gz (25.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

duosida_ev-0.1.2-py3-none-any.whl (18.3 kB view details)

Uploaded Python 3

File details

Details for the file duosida_ev-0.1.2.tar.gz.

File metadata

  • Download URL: duosida_ev-0.1.2.tar.gz
  • Upload date:
  • Size: 25.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for duosida_ev-0.1.2.tar.gz
Algorithm Hash digest
SHA256 f439016d070f40c7407ecc530ee36f0be69d370e6403f4ade0f288902b706c2b
MD5 f456c19dea008a75bfc648be47c9c49e
BLAKE2b-256 b115db5a77399f628b340c28d956ca994ac4bd63918ba7fd76950202411842ea

See more details on using hashes here.

File details

Details for the file duosida_ev-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: duosida_ev-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 18.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for duosida_ev-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 5cf13e63c8f5f953f3b8667b9a7f70ba3855bf9ee134640b905180fd85360387
MD5 6a8d3221d2a3e2d5444c800b169b4b98
BLAKE2b-256 719aaf1182ab97fb89c645661af9111b7218193a2be18fee300c8ac648788cd4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page