voltkeeper
CLI tool for Bluetti power stations — scan, connect, and read battery data over BLE.
Install
Quick run (no clone required)
uvx --from git+https://github.com/mikemccllstr/voltkeeper voltkeeper --help
This downloads and runs the tool in an isolated environment. Replace --help with any
command or subcommand.
From source
git clone https://github.com/mikemccllstr/voltkeeper
cd voltkeeper
uv run voltkeeper --help
Usage
Scan for devices
voltkeeper scan
Displays all nearby Bluetti devices and shows the exact command to connect to each one.
Options:
-t, --timeout FLOATScan timeout in seconds (default: 10.0)
Read battery status
voltkeeper status # auto-scan for devices, then pick one
voltkeeper status AA:BB:CC:DD:EE:FF # connect directly
Output:
- Battery SOC (%)
- Pack voltage
- Charging status
- Time to full / time to empty (context-dependent)
- DC load, AC load, and total load (watts)
Options:
-t, --timeout FLOATScan timeout in seconds (default: 10.0, used only when no address given)-v, --verboseDisplay all available device information (power meters, energy totals, PV strings, grid, loads, temperatures, software versions, writable controls, and device capabilities)
Probe a device (register sweep)
voltkeeper probe AA:BB:CC:DD:EE:FF -o device.yaml
Connects to the device, sweeps all known register blocks, and writes a YAML profile. Useful for device reverse-engineering and new-model support.
Validate a profile
voltkeeper validate-profile device.yaml
Parses the register blocks in a probe YAML and flags fields with suspect values (stuck-at-zero, all-0xFFFF, out of range).
Annotate changing registers (interactive)
voltkeeper annotate AA:BB:CC:DD:EE:FF -o draft.yaml
Live-polls the device and highlights byte-level changes in real time. Prompts for field names at each changed offset, saving annotations incrementally to a YAML draft. Press Ctrl-C to stop.
Write device settings
voltkeeper write AA:BB:CC:DD:EE:FF ac_output on
voltkeeper write AA:BB:CC:DD:EE:FF dc_output off
voltkeeper write AA:BB:CC:DD:EE:FF charging_mode turbo
Writable fields (see --verbose output for current values):
- switches:
ac_output,dc_output,power_off,dc_eco_mode,ac_eco_mode,power_lifting,alarm_sound—on/off charging_mode—standard/turbo/silent- numeric:
battery_range_start,battery_range_end,lcd_timeout,led_color,soc_low,soc_high,inv_voltage,inv_freq,working_mode
MQTT publish
voltkeeper mqtt-publish AA:BB:CC:DD:EE:FF --broker 192.168.1.100
Continuously polls the device over BLE and publishes state to an MQTT broker. Supports Home Assistant MQTT auto-discovery (on by default).
Options:
--serial TEXTDevice serial number (overrides BLE lookup for MQTT topic)--broker TEXTMQTT broker hostname (required)--port INTEGERMQTT broker port (default: 1883)--username TEXTMQTT broker username--password TEXTMQTT broker password--interval INTEGERSeconds between polling cycles (default: 0 = as fast as possible)--ha-config MODEHome Assistant discovery mode:normal,none,advanced(default: normal)--restart-on-source-changeExit cleanly when source code changes, so systemd restarts the process
MQTT listen — shutdown watchdog
voltkeeper mqtt-listen --serial 2409000123456 --broker 192.168.1.100
Subscribes to the device's MQTT topic and watches battery SOC. When SOC
drops below the threshold, initiates a system shutdown after a grace period.
The shutdown is latched — once triggered, it cannot be cancelled by SOC
recovery (use systemctl stop to abort before the grace period expires).
Options:
--serial TEXTDevice serial number (or provide ADDRESS for BLE lookup)--broker TEXTMQTT broker hostname (required)--port INTEGERMQTT broker port (default: 1883)--username TEXTMQTT broker username--password TEXTMQTT broker password--shutdown-at INTEGERSOC % threshold for shutdown (default: 10)--grace-period INTEGERSeconds below threshold before shutdown (default: 60)--restart-on-source-changeExit cleanly when source code changes
ADDRESS may be omitted if --serial is provided (useful when running on a
different machine without BLE).
Generate systemd service
voltkeeper load-test [OPTIONS] ADDRESS
Runs a controlled battery discharge test. Coaches you through setup, then logs device stats every N seconds to a CSV file until the battery reaches 0%.
Options:
-o, --output PATHCSV output file (default:ac2a_load_test_YYYYMMDD_HHMMSS.csv)-i, --interval SECONDSSample interval, minimum 15s (default: 60)-l, --expected-load WKnown load wattage for analysis reference-p, --phase TEXTLabel for this test phase (useful for multi-phase testing)
Example:
voltkeeper load-test AA:BB:CC:DD:EE:FF -l 500 -p "500W heater on AC"
The test will:
- Prompt you to fully charge, connect a load, and disconnect charging
- Verify prerequisites (SOC ≥ 95%, no grid/PV input)
- Poll every N seconds — logging SOC, voltage, current, AC/DC/PV/grid power,
temperatures, device time estimate, and two energy measurements:
- Computed — trapezoidal integration of measured power × time
- Register — the device's own
totalDCEnergyregister (for validation)
- Warn if grid or PV charging is detected (> 10 W)
- End when SOC reaches 0%, BLE connection drops, or you press Ctrl-C
- Print a summary with capacity, average load, min voltage, and max temp
The CSV has 17 columns with a comment header block; empty cells for failed BLE reads are Excel-friendly.
Generate systemd services
MQTT publish service
voltkeeper mqtt-publish-service AA:BB:CC:DD:EE:FF --broker 192.168.1.100
Generates a systemd unit file for mqtt-publish.
Options mirror the mqtt-publish command plus:
--user NAMESystem user to run as (default: current user)--exec PATHPath tovoltkeeperexecutable (default: auto-detect)-o, --output PATHWrite to file instead of stdout
MQTT listen service
voltkeeper mqtt-listen-service --serial 2409000123456 --broker 192.168.1.100
Generates a systemd unit file for mqtt-listen.
Options mirror the mqtt-listen command plus:
--user NAMESystem user to run as (default: root, needed for shutdown)--exec PATHPath tovoltkeeperexecutable (default: auto-detect)-o, --output PATHWrite to file instead of stdout
Installing a generated service
sudo cp voltkeeper-*.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now voltkeeper-*.service
-o, --output PATHWrite to file instead of stdout
Install the generated file:
sudo cp voltkeeper-mqtt-*.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now voltkeeper-mqtt-*.service
Help
voltkeeper --help
voltkeeper status --help
voltkeeper scan --help
voltkeeper probe --help
voltkeeper mqtt-publish --help
voltkeeper mqtt-listen --help
voltkeeper load-test --help
voltkeeper --version
Requirements
- Python 3.13+
- Linux with BlueZ, macOS 11+, or Windows 10 build 19041+ (BLE support)
- Bluetooth adapter with scan capability
On Linux, the BLE adapter may require elevated privileges (CAP_NET_ADMIN or
sudo). On macOS, the device's BLE MAC address may be reported as a UUID
rather than a hardware address — use the UUID directly with voltkeeper.
The tool reads plain Modbus RTU over BLE from Bluetti power stations. Encrypted devices (AES-CBC over BLE) are supported; the handshake is handled automatically.
Testing
uv run pytest # unit tests (fast, no BLE required)
uv run pytest -m integration # integration tests (requires BLE adapter)
Development
See docs/FINDINGS.md for reverse-engineering notes and protocol details helpful when enhancing this tool.
Contributing a new device
See docs/CONTRIBUTING_DEVICES.md for the step-by-step guide to capturing the data needed to add support for a new Bluetti device model. Maintainers receiving such a submission should follow docs/MAINTAINING.md.
Metadata
Release files for voltkeeper 2026.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| voltkeeper-2026.5.tar.gz | 356.5 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| voltkeeper-2026.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 425.9 kB
Release files / voltkeeper-2026.5.tar.gz
| Download URL | voltkeeper-2026.5.tar.gz |
|---|---|
| Size | 356.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b849a5b2cfcfae86e17fcd463b5f50ab0a3f0c97ce77ff7d00d337f554b07251
|
|
BLAKE2b-256 checksum How to use checksums |
4dcf580bfbfee5fd98635e102e2020c3529eab6f9ae60a5f93555eae6133dc43
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 24, 2026.
Transparency logRelease files / voltkeeper-2026.5-py3-none-any.whl
| Download URL | voltkeeper-2026.5-py3-none-any.whl |
|---|---|
| Size | 69.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
aabc9201c3674e2dc08e4c877fe02bb0841c6375e094dd90d0ae4e34ae156bc0
|
|
BLAKE2b-256 checksum How to use checksums |
d5f65b4f083ed022c91a0fba7ff5aec86f8601e87328849963c9425a561c7c15
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 24, 2026.
Transparency logSecurity for voltkeeper 2026.5
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for voltkeeper-2026.5.tar.gz
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 24, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.