Skip to main content

bluetti-bt-connect-lib

This is a fork of bluetti-bt-lib by Patrick762, extended with additional device support, register corrections, and new writable fields for the Bluetti EP2000. All credit for the original protocol reverse-engineering, architecture, and core library design goes to Patrick762 and the project's other contributors. This fork exists to track device-specific fixes and additions on a faster iteration cycle; where possible, improvements are intended to be contributed back upstream.

Original repository: https://github.com/Patrick762/bluetti-bt-lib

Additional credit to atiweb/hassio-bluetti-bt, a separate fork of the original project, cross-referenced for two specific fixes: correcting consumption_power_all, pv_input_power_all, and grid_power_all from incorrectly-assumed 32-bit fields to plain 16-bit fields (validated against real captured data), and the pattern for proper Modbus response validation (CRC checking and exception-response detection) now used in device_reader.py.

Inofficial Library for basic communication to bluetti powerstations. Core functions based on https://github.com/warhammerkid/bluetti_mqtt

Disclaimer

This library is provided without any warranty or support by Bluetti. I do not take responsibility for any problems it may cause in all cases. Use it at your own risk.

✅ EP2000: full local write control (v2.0)

Earlier versions of this fork carried a long warning that grid and working-mode writes were accepted by the device and then silently reverted, and speculated it was a cloud/authentication or "Pro Mode" gate. That is solved as of v2.0, and the cause turned out to be mundane: this is a 2nd-generation IoT device whose authoritative settings controller sits on Modbus slave 0, while the inverter answers on slave 1. The fork was writing to slave 1 - the inverter echoed the write and then overwrote it within a few seconds from the slave-0 setpoint. Writing to slave 0 makes the change persist. This matches the official Bluetti app, which sends settings to slave 0 on this device class; the few-second delay you may notice before a change shows up is the value propagating back to the slave-1 reading (the same delay the app shows before it opens its settings screen).

What this means on the EP2000 now:

  • Grid export power/current, grid import power/current, working mode, AC output, charge-from-grid and grid-export enables all write and persist over local BLE. Give a write a few seconds to settle before trusting the read-back.
  • A new AI Control Mode switch exposes register 2241. When Bluetti's AI/EMS is on it actively manages the system and will override your manual settings (the old "accept-then-revert" you would then see). Leave it off for manual control; the switch lets you see and change that state from Home Assistant.

Still worth knowing:

  • Grid export and grid-protection parameters are regulated for interconnection safety in most jurisdictions (anti-islanding, voltage/frequency ride-through). Whether or not a write persists, changing them may carry real compliance implications depending on where you live and how your system is connected.
  • Reliability can still vary by firmware version and by unit. This is confirmed on an EP2000 + EBOX; if a control misbehaves on your setup, the standalone BLE diagnostics below will show you exactly what the device is doing.

Full technical detail - the investigation and the register-level evidence - is in the v2.0 release notes (RELEASE_NOTES_2.0.0.md).

Projects using this library

Supported Powerstations and data

Validated

Device Name total_battery_percent dc_input_power ac_input_power dc_output_power ac_output_power
AC70 ✅ ✅ ✅ ✅ ✅
AC180 ✅ ✅ ✅ ✅ ✅
EB3A ✅ ✅ ✅ ✅ ✅
EP600 ✅ PV Grid ❌ AC Phases
EP2000 ✅ PV Grid ❌ AC Phases; writable grid import/export + working mode, persist via slave 0 (see v2.0 notes)
Handsfree 1 ✅ ✅ ✅ ✅ ✅

Added and mostly validated by contributors (some are moved here from the HA Integration https://github.com/Patrick762/hassio-bluetti-bt):

Device Name Contributor total_battery_percent dc_input_power ac_input_power dc_output_power ac_output_power
AC2A @ruanmed ✅ ✅ ✅ ✅ ✅
AC50B @goetzc ✅ ❌ ✅ ✅ ✅
AC60 @mzpwr ✅ ✅ ✅ ✅ ✅
AC60P @mzpwr ✅ ✅ ✅ ✅ ✅
AC70P @matthewpucc ✅ ✅ ✅ ✅ ✅
AC180P @Patrick762 ✅ ✅ ✅ ✅ ✅
AC200L bluetti-mqtt ✅ ✅ ✅ ✅ ✅
AC200M bluetti-mqtt ✅ ✅ ✅ ✅ ✅
AC200PL @0x4E4448 ✅ ✅ ✅ ✅ ✅
AC300 bluetti-mqtt ✅ ✅ ✅ ✅ ✅
AC500 bluetti-mqtt ✅ ✅ ✅ ✅ ✅
AP300 @seaburger, @sidieje ✅ ✅ ✅ ✅ ✅
EL30V2 @dgudim ✅ ✅ ✅ ✅ ✅
EL100V2 @seaburger ✅ ✅ ✅ ✅ ✅
EP500 bluetti-mqtt ✅ ✅ ✅ ✅ ✅
EP500P bluetti-mqtt ✅ ✅ ✅ ✅ ✅
EP760 @Apfuntimes ✅ PV Grid ❌ AC Phases
EP800 @jhagenk ✅ ❌ ❌ ❌ ❌
PR30V2 @gentoo90 ✅ ✅ ✅ ✅ ✅
PR100V2 shares PR30V2 register layout (pending validation) ✅ ✅ ✅ ✅ ✅

Controls

Validated:

Device Name ctrl_ac ctrl_dc
EB3A ✅ ✅

Added and mostly validated by contributors:

Device Name Contributor ctrl_ac ctrl_dc ctrl_ups_mode soc_range_start soc_range_end
AC200L bluetti-mqtt, @seaburger ✅ ✅ ✅ ❌ ❌
EL30V2 @x3ccd4828 ✅ ✅ ❌ ❌ ❌

Battery pack data

Device Name voltage battery_soc cell_voltages
AC300 ✅ ✅ ✅

Installation

pip install bluetti-bt-connect-lib

Commands for testing

Commands included in this library should only be used for testing.

Scan for supported devices

usage: bluetti-scan [-h] [-r REGEX] [-s SCAN_TIME]

Detect bluetti devices by bluetooth name

options:
  -h, --help            show this help message and exit
  -r REGEX, --regex REGEX
                        Custom regex to match device name
  -s SCAN_TIME, --scan-time SCAN_TIME
                        How long to scan for devices (seconds)

Example output: ['EB3A', '00:00:00:00:00:00']

Detect device type by mac address

usage: bluetti-detect [-h] mac

Detect bluetti devices

positional arguments:
  mac         Mac-address of the powerstation

options:
  -h, --help  show this help message and exit

Example:

bluetti-detect 00:00:00:00:00:00

Example output: Device type is 'EB3A' with iot version 1 and serial 0000000000000. Full name: EB3A0000000000000

Read device data for supported devices

usage: bluetti-read [-h] [-m MAC] [-t TYPE] [-e ENCRYPTION]

Detect bluetti devices

options:
  -h, --help            show this help message and exit
  -m MAC, --mac MAC     Mac-address of the powerstation
  -t TYPE, --type TYPE  Type of the powerstation (AC70 f.ex.)
  -e ENCRYPTION, --encryption ENCRYPTION
                        Add this if encryption is needed

Example:

bluetti-read -m 00:00:00:00:00:00 -t EB3A

Example output:

FieldName.DEVICE_TYPE: EB3A
FieldName.DEVICE_SN: 0000000000000
FieldName.BATTERY_SOC: 92%
FieldName.DC_INPUT_POWER: 0W
FieldName.AC_INPUT_POWER: 0W
FieldName.AC_OUTPUT_POWER: 0W
FieldName.DC_OUTPUT_POWER: 0W
FieldName.CTRL_AC: False
FieldName.CTRL_DC: True
FieldName.CTRL_LED_MODE: LedMode.OFF
FieldName.CTRL_POWER_OFF: False
FieldName.CTRL_ECO: False
FieldName.CTRL_ECO_TIME_MODE: EcoMode.HOURS1
FieldName.CTRL_CHARGING_MODE: ChargingMode.STANDARD
FieldName.CTRL_POWER_LIFTING: False

Write to supported device

INFO: Devices with encryption are currently not supported!

usage: bluetti-write [-h] [-m MAC] [-t TYPE] [--on ON] [--off OFF] [-v VALUE] [-e ENCRYPTION] field

Write to bluetti device

positional arguments:
  field                 Field name (ctrl_dc f.ex.)

options:
  -h, --help            show this help message and exit
  -m MAC, --mac MAC     Mac-address of the powerstation
  -t TYPE, --type TYPE  Type of the powerstation (AC70 f.ex.)
  --on ON               Value to write
  --off OFF             Value to write
  -v VALUE, --value VALUE
                        Value to write (integer, see enum for value)
  -e ENCRYPTION, --encryption ENCRYPTION
                        Add this if encryption is needed

Example:

bluetti-write -m 00:00:00:00:00:00 -t EB3A --on on ctrl_ac

Standalone BLE diagnostics (repo scripts)

These live at the repo root and are self-contained (raw Modbus over the GATT write characteristic - no library import needed). They were written while diagnosing the slave-0 write behaviour and are kept for future debugging. Run them from a venv that has bleak, bleak-retry-connector and crcmod installed, with the device free (turn off any "Hold Bluetooth connection" switch in Home Assistant first so the station is not already connected).

  • scan_addr.py - list nearby BLE devices and their addresses (on macOS the address is a CoreBluetooth UUID).
  • probe_grid.py - dump the grid import/export registers at both slaves, sweep nearby, and optionally test that an import write persists (--test-import N).
  • probe_slave.py - A/B a write at slave 0 vs slave 1 with read-back (this is the one that pinned down the fix).
  • probe_writepath.py - test write strategies (EMS on/off, slave, commit pulse).
  • probe_commit.py - write a value, then watch it for ~45s to catch a slow revert and test commit pulses.
python probe_grid.py --mac <address>
python probe_slave.py --mac <address> --reg 2215 --value 1500

Get <address> from scan_addr.py or bluetti-scan.

Adding fields

To add new fields, you can use the bluetti-detect command to first find out which version of iot protocol is used and if it uses encryption.

After you got this information, you can use the bluetti-readall command to read every registry and save the data to a json file. You should also note all values you see in the app to later compare the data.

Here's how to use the bluetti-readall command:

usage: bluetti-readall [-h] [-m MAC] [-v VERSION] [-e ENCRYPTION]

Detect bluetti devices

options:
  -h, --help            show this help message and exit
  -m MAC, --mac MAC     Mac-address of the powerstation
  -v VERSION, --version VERSION
                        IoT protocol version
  -e ENCRYPTION, --encryption ENCRYPTION
                        Add this if encryption is needed

With the separate tool at bluetti-bt-raw-reader you can view those values in a more understandable way.

You can also share the output with me using this form

To test added fields with the created json file, use bluetti-parse:

usage: bluetti-parse [-h] file

Parse readall output files

positional arguments:
  file        JSON file of the powerstation readall output

options:
  -h, --help  show this help message and exit

Metadata

Release files for bluetti-bt-connect-lib 2.0.8

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

Source distribution (sdist)

Source distribution for bluetti-bt-connect-lib 2.0.8
File Size Uploaded
bluetti_bt_connect_lib-2.0.8.tar.gz 57.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for bluetti-bt-connect-lib 2.0.8
File Interpreter ABI Platform
bluetti_bt_connect_lib-2.0.8-py3-none-any.whl Python 3 none any Details

Total release size: 144.5 kB

Release files / bluetti_bt_connect_lib-2.0.8.tar.gz

Download URL bluetti_bt_connect_lib-2.0.8.tar.gz
Size 57.3 kB
Tags Source
SHA-256 checksum
How to use checksums
1724e6fa5bdf7defb22dacb2485e617459d93020e7a092782394a081f484fa16
BLAKE2b-256 checksum
How to use checksums
e71665f5b71a4a5bb5df92be8bbc909f260742bb3e21f9cc099b4f52faa50cb6
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 Oct 5, 2026.

Transparency log

Release files / bluetti_bt_connect_lib-2.0.8-py3-none-any.whl

Download URL bluetti_bt_connect_lib-2.0.8-py3-none-any.whl
Size 87.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
92fed3dcd1a5607b0eed6470c23110a49b0ae40e4dfe84dec872d73eed6c87c1
BLAKE2b-256 checksum
How to use checksums
3702de9a9156df940b32a4d338f3a3f22fd2078fdad665b31a8d8fcbab741143
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 Oct 5, 2026.

Transparency log

Release history Release notifications | RSS feed

2.0.9

2 release files

This release

2.0.8 This release

2 release files

2.0.7

2 release files

2.0.6

2 release files

2.0.5

2 release files

2.0.4

2 release files

2.0.3

2 release files

2.0.2

2 release files

2.0.1

2 release files

2.0.0

2 release files

1.9.2

2 release files

1.9.1

2 release files

1.9.0

2 release files

1.8.0

2 release files

1.7.0

2 release files

1.6.0

2 release files

1.5.0

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