Python SDK for AVE DominaPlus home automation systems
Project description
pyavedominaplus
A Python SDK and Home Assistant custom integration for AVE DominaPlus home automation systems. Communicates with the DominaPlus server over WebSocket using the native binary protocol.
AI Disclaimer: This project was built using the assistance of Claude Code
Features
- Async WebSocket client with automatic ping/pong keepalive
- Full binary protocol implementation (STX/ETX framing, CRC validation)
- Push-based real-time device status updates
- Home Assistant integration with config flow UI
Supported devices
| Device type | HA platform | Controls |
|---|---|---|
| Light (type 1, 22) | light |
On/off, toggle |
| Dimmer (type 2) | light |
On/off, toggle, brightness (0-31) |
| Shutter (type 3, 16, 19) | cover |
Open, close, stop |
| Thermostat (type 4) | climate |
Temperature setpoint, season mode, on/off, keyboard lock |
| Scenario (type 6) | switch |
Activate |
| Energy meter (type 9) | — | Read-only |
Requirements
- Python >= 3.13
- aiohttp >= 3.9
Installation
Python SDK
pip install -e .
# With dev dependencies
pip install -e ".[dev]"
SDK usage
import asyncio
from pyavedominaplus import AVEDominaClient
async def main():
client = AVEDominaClient(host="192.168.1.100", port=14001)
await client.connect()
await client.initialize()
await client.wait_for_initialization(timeout=30.0)
# List discovered devices
for device_id, device in client.devices.items():
print(f"{device.name}: {device.device_type}")
# Control lights (EBI command)
await client.turn_on_light("100")
await client.turn_off_light("100")
await client.toggle_light("100")
# Control dimmers (SIL command for level, EBI for step)
await client.set_dimmer_level("101", 16) # 0-31
await client.step_dimmer("101") # toggle on/off
# Control shutters (EAI command)
await client.open_shutter("102")
await client.close_shutter("102")
await client.stop_shutter("102") # re-sends current direction to stop motor
# Control thermostats (STS command)
await client.set_thermostat_set_point("103", 21.5)
await client.set_thermostat_season("103", season=1) # 0=summer, 1=winter
await client.set_thermostat_mode("103", mode=1) # 0=auto, 1=manual
await client.turn_on_thermostat("103")
await client.turn_off_thermostat("103")
await client.toggle_thermostat_keyboard_lock("103")
# Activate scenario (ES command via map lookup)
await client.activate_scenario("104")
# Register for real-time updates
def on_update(event_type, data):
print(f"Update: {event_type} - {data}")
client.register_update_callback(on_update)
await asyncio.sleep(60)
await client.disconnect()
asyncio.run(main())
Project structure
pyavedominaplus/ Python SDK
client.py Async WebSocket client
protocol.py Message encoding/decoding, CRC
models.py DominaDevice, DominaThermostat, DominaArea
const.py Protocol constants and device types
tests/ SDK unit tests (227 tests)
scripts/ Utility scripts for hardware testing
test_hardware.py Interactive hardware test runner
monitor_device.py Live device state monitor
extract_pcap.py PCAP extractor with WebSocket frame parsing
wireshark/ Wireshark protocol dissector
ave_dominaplus.lua Lua dissector for AVE DominaPlus (TCP + WebSocket)
Wireshark dissector
A Lua dissector for analyzing AVE DominaPlus traffic in Wireshark. Handles both raw TCP (port 14001) and WebSocket framing, including XOR-unmasking of client-to-server frames per RFC 6455. Decodes all protocol messages including device commands, thermostat operations, status updates, and more. See wireshark/README.md for installation and usage details.
PCAP extractor
Extracts and decodes AVE DominaPlus messages from packet captures. Handles WebSocket frame parsing with automatic unmasking of client-to-server frames, HTTP 101 handshake detection, and falls back to raw AVE protocol for non-WebSocket captures. Requires scapy.
python extract_pcap.py capture.pcap -v
python extract_pcap.py capture.pcap -o output.json
Running tests
# All tests
pytest
# With coverage
coverage run -m pytest tests
coverage report
# Specific module
pytest tests/test_client.py -v
Scripts
Hardware test
Interactive test runner for manual testing against real DominaPlus hardware. Connects to a device, discovers all devices, lets you pick one per category (light, dimmer, shutter, thermostat, scenario), and walks through each operation with human confirmation (e.g. "Did the light turn on? [y/n/skip]").
python scripts/test_hardware.py <host> [port]
# Example:
python scripts/test_hardware.py 192.168.1.100
Device monitor
Live device state monitor. Connects to hardware, lets you pick a device, then displays its full state with real-time updates from the WebSocket. Supports all device types including detailed thermostat info (temperature, setpoint, season, mode, fan level, humidity).
python scripts/monitor_device.py <host> [port] [--device-id ID]
# Examples:
python scripts/monitor_device.py 192.168.1.100
python scripts/monitor_device.py 192.168.1.100 --device-id 68
Protocol notes
The SDK implements AVE's custom binary WebSocket protocol:
- Framing: STX (0x02) marks message start, ETX (0x03) end, EOT (0x04) end of transmission
- Fields: Separated by GS (0x1D) within a section, RS (0x1E) between sections (records)
- CRC: XOR-based checksum (0xFF minus XOR of all payload bytes)
- Port: Default 14001
- Special devices: RGBW names prefixed with
$, DALI names suffixed with$, VMC Daikin thermostats have IDs offset by 10000000
Initialization sequence
The client follows the same initialization sequence as the original AVE webapp:
- Send
LM(list areas) andLDI(list devices) - For each area, request
LMC(map commands) andLML(map labels) - For each thermostat, request
WTS(full thermostat status) - After all
LMCresponses arrive, subscribe to updates (SU2,SU3) and request device statuses viaWSFfor each device family - WSF commands are staggered with ~300ms delays between each — sending them all at once overwhelms the hardware and causes dropped responses
- Initialization is complete once all devices have received their status via
UPD WSorWTSresponses
Shutter status values
| Value | Status | Description |
|---|---|---|
| 0 | Unknown | No status received yet (not a valid operational state) |
| 1 | Open | Fully open |
| 2 | Opening | Motor running upward |
| 3 | Closed | Fully closed |
| 4 | Closing | Motor running downward |
| 5 | Stopped | Stopped mid-movement (partially open) |
Stopping a shutter is done by re-sending the current direction command (open while opening, close while closing). The hardware then reports status 5.
Thermostat modes
| Mode | Value | Description |
|---|---|---|
| Auto | 0 | Follows the built-in schedule on the thermostat |
| Manual | 1 | User-set temperature, held until changed |
| Antifreeze | 0x1F | Protection mode, set by system |
The TOO/TUU commands use inverted logic: sending "1" turns the thermostat ON (local_off=0), sending "0" turns it OFF (local_off=1). TUU is used for TS01/VMC Daikin types.
Command reference
| Command | Direction | Purpose |
|---|---|---|
LM |
→ | List areas/maps |
LMC |
→ | List map commands for an area |
LML |
→ | List map labels for an area |
LDI |
→ | List all devices |
LI2 |
→ | List device AVEbus addresses |
WSF <family> |
→ | Request device statuses for a family (1=light, 2=dimmer, 3=shutter…) |
SU2 / SU3 |
→ | Subscribe to real-time status updates |
WTS <id> |
→ | Request thermostat full status |
GTM |
→ | Request thermostat IR mode list |
GMA |
→ | Request start/stop device list |
GNA |
→ | Request no-action device list |
GSF <family> |
→ | Request sensor family status |
EBI <id>,<cmd> |
→ | Light/energy command: 10=toggle, 11=on, 12=off, 2=dimmer step |
EAI <id>,<cmd> |
→ | Shutter command: 8=open, 9=close (re-send to stop) |
SIL <id>,<level> |
→ | Set dimmer brightness (0-31) |
STS <id> + record |
→ | Set thermostat (season, mode, setpoint×10) |
ES <cmdId> |
→ | Execute scenario (map command ID) |
TOO <id>,<state> |
→ | Toggle thermostat local off (standard, inverted: send 1→ON, 0→OFF) |
TUU <id>,<state> |
→ | Toggle thermostat local off (TS01/VMC Daikin, same inversion) |
TTK <id> |
→ | Toggle thermostat keyboard lock |
PONG |
→ | Reply to server ping |
upd WS <type> <id> <val> |
← | Device status update |
upd WT <sub> <id> <val> |
← | Thermostat sub-update (T=temp, S=season, O=offset, L=fan, Z=localOFF) |
upd TP <id> <val> |
← | Thermostat setpoint update |
upd TM <id> <mode> |
← | Thermostat mode update |
upd TK <id> <lock> |
← | Thermostat keyboard lock update |
upd TW <id> <state> |
← | Thermostat window state update |
upd UMI <id> … |
← | Humidity probe update |
upd D <cmdId> <icon> |
← | Map command icon update |
upd GRP … |
← | Group dimmer update |
upd RGB … |
← | RGBW update |
upd epv … |
← | Economizer update |
wts <id> + record |
← | Full thermostat status response |
lm + records |
← | Area list response |
ldi + records |
← | Device list response |
lmc <areaId> + records |
← | Map commands response |
ack |
← | Command acknowledgement |
ping |
← | Keepalive ping |
License
See LICENSE for details.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyavedominaplus-0.1.8.tar.gz.
File metadata
- Download URL: pyavedominaplus-0.1.8.tar.gz
- Upload date:
- Size: 49.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
950100943329a430a6bbec8e0740a21935fe38b593be598262ab509273996ffa
|
|
| MD5 |
92acc97886da5094d1fb66facb629774
|
|
| BLAKE2b-256 |
c3b71f7482e19723e1ddf6fe6a243d8d1c5beaba190df56c559308d7d30caebb
|
Provenance
The following attestation bundles were made for pyavedominaplus-0.1.8.tar.gz:
Publisher:
release.yml on pyavedominaplus/pyavedominaplus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyavedominaplus-0.1.8.tar.gz -
Subject digest:
950100943329a430a6bbec8e0740a21935fe38b593be598262ab509273996ffa - Sigstore transparency entry: 1059824035
- Sigstore integration time:
-
Permalink:
pyavedominaplus/pyavedominaplus@5ba99bf4d1cb7b350af28565db1ab7dc0e05ba40 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/pyavedominaplus
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5ba99bf4d1cb7b350af28565db1ab7dc0e05ba40 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file pyavedominaplus-0.1.8-py3-none-any.whl.
File metadata
- Download URL: pyavedominaplus-0.1.8-py3-none-any.whl
- Upload date:
- Size: 32.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0e51f27ca00eba0685e3ded5e6700df051afa593e99dc63e1116d4fa8f7a3384
|
|
| MD5 |
7f0680fef9cbe8369415c667b0cad5eb
|
|
| BLAKE2b-256 |
1142adb225addb9a773cd7aa4de24ff1bef7d0ec5be666bc18f3e77d66014e97
|
Provenance
The following attestation bundles were made for pyavedominaplus-0.1.8-py3-none-any.whl:
Publisher:
release.yml on pyavedominaplus/pyavedominaplus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyavedominaplus-0.1.8-py3-none-any.whl -
Subject digest:
0e51f27ca00eba0685e3ded5e6700df051afa593e99dc63e1116d4fa8f7a3384 - Sigstore transparency entry: 1059824037
- Sigstore integration time:
-
Permalink:
pyavedominaplus/pyavedominaplus@5ba99bf4d1cb7b350af28565db1ab7dc0e05ba40 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/pyavedominaplus
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5ba99bf4d1cb7b350af28565db1ab7dc0e05ba40 -
Trigger Event:
workflow_dispatch
-
Statement type: