Skip to main content

solarflow-ble

Unofficial asynchronous Python library for communicating with Zendure SolarFlow controllers over Bluetooth Low Energy.

The protocol implementation is based on esphome-solarflow-ble. The library has been tested with a SolarFlow 2400AC through a Home Assistant Connect AUX-2 acting as a Bluetooth proxy. Traffic probing and debugging use bleak-esphome.

All protocol credits and reverse-engineering efforts belong to the esphome-solarflow-ble project. This library builds on that work in Python.

Requires Python >= 3.14.

Install

uv add solarflow-ble

Usage

SolarFlowClient uses an injected transport, so applications can choose their own Bluetooth adapter and tests can use a fake transport without Bluetooth hardware.

import asyncio

from bleak.backends.device import BLEDevice

from solarflow_ble import BleakTransport, SolarFlowClient


async def main() -> None:
    # Replace these values with a device discovered by your BLE adapter.
    device = BLEDevice("AA:BB:CC:DD:EE:FF", "SolarFlow", {})
    client = SolarFlowClient(BleakTransport(device))

    try:
        await client.connect()
        print(client.state)
        print(client.status)
    finally:
        await client.disconnect()


asyncio.run(main())

The client connects, completes the BLESPP handshake, reads the initial getAll state, and keeps the session updated. Always call disconnect() when the session ends.

Control methods are disabled by default. Enable them explicitly when the application is intended to change device settings:

client = SolarFlowClient(BleakTransport(device), allow_control=True)
try:
    await client.connect()
    await client.set_output_limit(800)
finally:
    await client.disconnect()

Probe

The developer-only probe captures SolarFlow GATT traffic through an ESPHome Bluetooth proxy (e.g. the Home Assistant Connect AUX-2). It does not send device-setting writes by default. It sends the BLESPP handshake, getInfo, and getAll protocol requests.

# Discover a SolarFlow device and capture its traffic.
uv run scripts/probe_solarflow.py \
  --proxy "192.168.1.157" \
  --noise-psk "your-esphome-noise-psk" \
  --output /tmp/solarflow.jsonl

List advertisements without connecting to a SolarFlow device:

uv run scripts/probe_solarflow.py \
  --proxy "192.168.1.157" \
  --noise-psk "your-esphome-noise-psk" \
  --list-advertisements \
  --scan-seconds 30

Advertisement addresses and parsed SolarFlow identifiers are redacted by default. Add --show-identities when selecting values for --address or --identifier; capture files remain redacted.

Target a specific SolarFlow device by Bluetooth address:

uv run scripts/probe_solarflow.py \
  --proxy "192.168.1.157" \
  --noise-psk "your-esphome-noise-psk" \
  --address "AA:BB:CC:DD:EE:FF" \
  --scan-seconds 60 \
  --capture-seconds 30 \
  --output /tmp/solarflow-target.jsonl

Alternatively, target a device by its SolarFlow manufacturer-advertisement identifier:

uv run scripts/probe_solarflow.py \
  --proxy "192.168.1.157" \
  --noise-psk "your-esphome-noise-psk" \
  --identifier "DEVICE_IDENTIFIER" \
  --scan-seconds 60 \
  --capture-seconds 30 \
  --output /tmp/solarflow-target.jsonl

Connect to a device and capture notifications without sending the BLESPP handshake or the initial getInfo and getAll requests:

uv run scripts/probe_solarflow.py \
  --proxy "192.168.1.157" \
  --noise-psk "your-esphome-noise-psk" \
  --address "AA:BB:CC:DD:EE:FF" \
  --no-handshake \
  --capture-seconds 30 \
  --output /tmp/solarflow-passive.jsonl

Development

This project uses uv and targets Python 3.14+.

uv sync
uv run python -m scripts.check

The development gate stops at the first failure in this order: format check, Ruff lint, mypy, branch-covered tests, coverage report, then package build.

Run one test file or test:

uv run pytest tests/test_solarflow.py
uv run pytest tests/test_solarflow.py -k connect_handshake

Standalone library client test

Use the standalone diagnostic to exercise SolarFlowClient through an ESPHome Bluetooth proxy. It discovers exactly one target by address or SolarFlow advertisement identifier and is read-only unless controls are explicitly confirmed.

uv run scripts/test_solarflow_client.py \
  --proxy "192.168.1.157" \
  --noise-psk "your-esphome-noise-psk" \
  --identifier "DEVICE_IDENTIFIER" \
  --duration 30 \
  --output /tmp/solarflow-library-test.jsonl

The script prints device identities and decoded state to stdout for local diagnostics. The optional JSONL file is always recursively redacted. Controls require both --controls and --confirm-controls; they also require explicit --min-soc and --soc values because those original wire values are not available safely for restoration.

The connection settings can be kept in the ignored local config file scripts/test_solarflow_client.local.json. The file may contain proxy, noise_psk, and exactly one of address or identifier:

{
  "proxy": "192.168.1.157",
  "noise_psk": "your-esphome-noise-psk",
  "identifier": "DEVICE_IDENTIFIER"
}

Run the diagnostic with the default local file:

uv run scripts/test_solarflow_client.py --duration 30

Use --config path/to/config.json for another local file. Command-line values override values from the config file, so individual settings can be replaced without editing it:

uv run scripts/test_solarflow_client.py \
  --config scripts/test_solarflow_client.local.json \
  --identifier "OTHER_DEVICE_IDENTIFIER"

Do not commit this file or paste a real noise_psk into documentation, fixtures, logs, or shell history. The default local filename is ignored by Git; use a file with equivalent local-only handling when choosing another config path. The script never prints or writes noise_psk.

License

This project is licensed under the MIT License. See LICENSE.

Metadata

Release files for solarflow-ble 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for solarflow-ble 0.1.1
File Size Uploaded
solarflow_ble-0.1.1.tar.gz 9.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for solarflow-ble 0.1.1
File Interpreter ABI Platform
solarflow_ble-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 20.9 kB

Release files / solarflow_ble-0.1.1.tar.gz

Download URL solarflow_ble-0.1.1.tar.gz
Size 9.3 kB
Tags Source
SHA-256 checksum
How to use checksums
c4ced8c0fdd455345b09ad3dc3e1e572eeef447fa2da118d6609daaf4eef95db
BLAKE2b-256 checksum
How to use checksums
86677174934c6503e53aaa24526081cb15d4654d9b6ca3a859d7ebd55005ed51
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 21, 2026.

Transparency log

Release files / solarflow_ble-0.1.1-py3-none-any.whl

Download URL solarflow_ble-0.1.1-py3-none-any.whl
Size 11.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
729481aa2e19d3e2fb572cfbe1fb112fc095df17bd8939aa384510f98af265a9
BLAKE2b-256 checksum
How to use checksums
aa97b27de1986a03c428555a58dfb0206127e161c09a82ddb1b21e716dfee86a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 21, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

This release

0.1.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page