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
Metadata
Release files for aiosolax-uart 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| aiosolax_uart-0.1.0.tar.gz | 11.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aiosolax_uart-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 25.2 kB
Release files / aiosolax_uart-0.1.0.tar.gz
| Download URL | aiosolax_uart-0.1.0.tar.gz |
|---|---|
| Size | 11.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
09f9c3b00230c70674d1d4f6c7206370a714dc1ac7349aa07d68f459892a5b66
|
|
BLAKE2b-256 checksum How to use checksums |
4a1d662d909546ee4fffe3b437e037c0fdfcba7361200bae10c226d1608b0459
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 11, 2026.
Transparency logRelease files / aiosolax_uart-0.1.0-py3-none-any.whl
| Download URL | aiosolax_uart-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
238947f30cd0a4ec2e44aa038b0e839e51d4bfe527290598493f1efc06641b71
|
|
BLAKE2b-256 checksum How to use checksums |
d4c9d931751976f0991d2724e61c3e58e62dc0a7598c7b871ec7ac09f0e0ce97
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 11, 2026.
Transparency log