Async library to read SolaX inverters over UART using the Pocket USB protocol
Project description
aiosolax-uart
Async Python library to read SolaX inverters over the Pocket USB protocol — the byte-level protocol that the SolaX Pocket WiFi / Pocket USB dongle speaks. Any inverter that accepts a Pocket dongle should be reachable with this library, whether the user connects a real dongle or replaces it with a USB-to-TTL adapter (CP2102, CH340, FT232, …) or an ESPHome serial proxy.
The wire protocol is AA 55 framing at 9600 baud, 8N1. Originally reverse-engineered by xdubx; hybrid-inverter extensions contributed by 70p4z.
Install
pip install aiosolax-uart
Quickstart
import asyncio
from aiosolax_uart import SolaxClient
async def main() -> None:
async with SolaxClient("/dev/ttyUSB0") as client:
info = await client.get_device_info()
print(f"Connected: {info.model.name} (serial {info.inverter_serial})")
live = await client.get_live_data()
print(f"AC power: {live.grid_power} W, today: {live.energy_today} kWh")
if live.import_power is not None:
print(
f"House grid: imp={live.import_power}W "
f"exp={live.export_power}W self={live.self_consumption_power}W"
)
if live.battery_soc is not None:
print(f"Battery: {live.battery_soc}% @ {live.battery_voltage}V")
asyncio.run(main())
The library also works against an ESPHome serial proxy — pass an esphome://host[:port]/?port_name=...&noise_psk=... URL in place of /dev/ttyUSB0.
Supported inverters
The library handles two payload families. Which fields are populated on a given inverter depends on what that inverter actually reports.
| Family | Models | Status |
|---|---|---|
| X1 grid-tie | X1 Mini (G2/G3), X1 Air, X1 Boost (G3.3/G4), X1 Smart | Verified (X1 with CT clamp, May 2026) |
| X1 Hybrid | X1 Hybrid G3 / G4.1+ | Decoder present, unverified — needs hardware testers |
| X3 grid-tie | X3 Mega G2, X3 Mic/Pro G2, X3 Forth | Same wire protocol, unverified |
| X3 Hybrid | X3 Hybrid G2 / G4.2+ | Decoder present, unverified — needs hardware testers |
If you can run await client.get_device_info() against your inverter and get a sensible response, please open an issue with the output so the model code can be added to the MODELS registry.
API
SolaxClient
SolaxClient(port: str, *, dongle_serial: str = "AIOSOLAX01", baudrate: int = 9600)async connect() -> None— open serial, register with the inverterasync close() -> Noneasync get_device_info() -> DeviceInfo— inverter serial, model code, dongle serial. Cached for use byget_live_data().async get_live_data() -> LiveData— instantaneous values + lifetime energy totals. Dispatches to the right decoder using the cached model code.- Use as
async with SolaxClient(...) as client:to handle setup/teardown.
Data models
DeviceInfo— static device info plus a.modelproperty that looks up the entry inMODELS.LiveData— every field that any inverter family can report. Common fields (AC, PV, temperature, energy_total, energy_today, runtime) are always populated; CT, battery, EPS and RTC fields areNonewhen not available.
Model registry
from aiosolax_uart import MODELS, lookup_model
MODELS[5000] # InverterModel(code=5000, name='X1 (5kW)', family=InverterFamily.X1_GRID_TIE)
lookup_model(0xFFFF) # InverterModel(code=65535, name='Unknown (65535)', family=InverterFamily.UNKNOWN)
Protocol reference
Frame layout: AA 55 [total_size] [ctrl] [func] [payload...] [chk_lo chk_hi] with a 16-bit little-endian additive checksum over all preceding bytes.
| Direction | ctrl | func | Description |
|---|---|---|---|
| Host → | 0x02 | 0x01 | Register dongle (10-char ASCII serial) |
| Host → | 0x01 | 0x05 | Read inverter serial / model code |
| Inv ← | 0x01 | 0x85 | Serial response (40-byte payload) |
| Host → | 0x01 | 0x0C | Read live data |
| Inv ← | 0x01 | 0x8C | Live-data response (200 / 210+ bytes depending on family) |
The handshake is: open serial → broadcast register frame → wait for the inverter to echo it back → poll live data on a cadence.
Development
uv sync
uv run pytest
Contributing
If your inverter isn't in the MODELS registry yet:
- Run a small script that prints
await client.get_device_info()against your inverter. - Open an issue with the model code and the inverter's name (from the sticker).
If you have a hybrid inverter, the offsets in _decode_hybrid_extras() need verification. A 220-byte capture of await client.get_live_data() plus your battery's known voltage/SoC right when you took the capture would let us validate the offsets.
License
Apache 2.0
Project details
Release history Release notifications | RSS feed
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 aiosolax_uart-0.1.0.tar.gz.
File metadata
- Download URL: aiosolax_uart-0.1.0.tar.gz
- Upload date:
- Size: 11.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
09f9c3b00230c70674d1d4f6c7206370a714dc1ac7349aa07d68f459892a5b66
|
|
| MD5 |
0cc377c7282a1d410d9fa0c18f60d62c
|
|
| BLAKE2b-256 |
4a1d662d909546ee4fffe3b437e037c0fdfcba7361200bae10c226d1608b0459
|
Provenance
The following attestation bundles were made for aiosolax_uart-0.1.0.tar.gz:
Publisher:
publish.yml on jesserockz/aiosolax-uart
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aiosolax_uart-0.1.0.tar.gz -
Subject digest:
09f9c3b00230c70674d1d4f6c7206370a714dc1ac7349aa07d68f459892a5b66 - Sigstore transparency entry: 1506312111
- Sigstore integration time:
-
Permalink:
jesserockz/aiosolax-uart@ed65468f4100bee4221b07b428ac40c147593bb2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/jesserockz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ed65468f4100bee4221b07b428ac40c147593bb2 -
Trigger Event:
release
-
Statement type:
File details
Details for the file aiosolax_uart-0.1.0-py3-none-any.whl.
File metadata
- Download URL: aiosolax_uart-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
238947f30cd0a4ec2e44aa038b0e839e51d4bfe527290598493f1efc06641b71
|
|
| MD5 |
3cb010e5f850d825d88967d6533511ab
|
|
| BLAKE2b-256 |
d4c9d931751976f0991d2724e61c3e58e62dc0a7598c7b871ec7ac09f0e0ce97
|
Provenance
The following attestation bundles were made for aiosolax_uart-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on jesserockz/aiosolax-uart
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aiosolax_uart-0.1.0-py3-none-any.whl -
Subject digest:
238947f30cd0a4ec2e44aa038b0e839e51d4bfe527290598493f1efc06641b71 - Sigstore transparency entry: 1506312307
- Sigstore integration time:
-
Permalink:
jesserockz/aiosolax-uart@ed65468f4100bee4221b07b428ac40c147593bb2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/jesserockz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ed65468f4100bee4221b07b428ac40c147593bb2 -
Trigger Event:
release
-
Statement type: