tim aa9888800e Report EcoFlow power and temperature as floats
River 2 reported total power and temperature as integers. River 3 reported temperature as an integer. InfluxDB keeps one field type for each measurement, so it rejected these points when another device wrote floats to the same measurement.
2026-10-10 09:03:33 +02:00
2026-10-08 14:03:09 +02:00
2026-10-08 14:03:09 +02:00
2026-10-08 14:03:09 +02:00
2026-10-08 14:03:09 +02:00
2021-02-03 11:19:58 +00:00
2026-10-08 14:03:09 +02:00

bmspy

bmspy is a tool to get information from battery management systems and UPS devices. It supports:

  • Xiaoxiang-type BMS devices via serial (USB)
  • EcoFlow power stations via Bluetooth LE

It can display the information as text, in JSON, or export the data continuously to InfluxDB or a Prometheus exporter.

Multiple devices can be connected at once. Each is identified by a name, and data from all of them (or just one) can be pushed to InfluxDB or Prometheus in the same connection, with each measurement tagged with the device name.

Install uv and use Python 3.12 or later, below Python 4. Then create the local environment:

git clone https://git.treehouse.org.za/tim/bmspy
cd bmspy
uv sync --locked

To install with EcoFlow Bluetooth LE support:

uv sync --locked --extra ecoflow-bt

To install with InfluxDB and Prometheus support:

uv sync --locked --extra influxdb --extra prometheus

These optional dependency sets are called extras. Select the required extras with each uv run command, or use --all-extras to enable all of them. uv sync also installs development dependencies by default. Use --no-dev for a deployment that does not need the test tools.

Running the server

The server daemon reads from one or more devices and makes the data available over a Unix socket.

Single JBD BMS device (defaults to /dev/ttyUSB0):

uv run bmspy-server

Multiple JBD BMS devices, with optional names (default name is derived from the device path, e.g. ttyUSB0):

uv run bmspy-server -d network:/dev/ttyUSB0 -d nas:/dev/ttyUSB1

EcoFlow Bluetooth LE devices

Install the ecoflow-bt extra as shown above. Close the EcoFlow app and stop other Bluetooth collectors before connecting to a device.

Setup

Get your EcoFlow account user ID:

uv run bmspy-ecoflow-login you@example.com

The command prompts for your password. Add --region EU or --region US if needed. Use the diagnostic scan below to find device addresses and serial numbers.

Type 7 authentication also needs an external lookup table from ha-ef-ble. From the bmspy repository root, download it:

curl --fail --location --output bmspy/ecoflow_keydata.py \
  https://raw.githubusercontent.com/rabits/ha-ef-ble/main/custom_components/ef_ble/eflib/keydata.py

This file is ignored by Git and excluded from packages. Type 1 devices do not need it.

Dump both Rivers

Device arguments use name@ADDRESS/SERIAL/USERID. Replace the placeholders below with each device's Bluetooth address, serial number, and your account user ID:

uv run --extra ecoflow-bt bmspy-server --socket /tmp/bmspy-rivers.sock \
  -d 'river2@RIVER2_MAC/RIVER2_SERIAL/YOUR_USER_ID' \
  -d 'river3@RIVER3_MAC/RIVER3_SERIAL/YOUR_USER_ID'

Leave the server running. In another terminal, print both snapshots:

uv run bmspy --socket /tmp/bmspy-rivers.sock

Omit --ups for all devices. Add --ups river2 to select one. --ups all means a device named all, not all devices. To include a serial BMS, add a server argument such as -d network:/dev/ttyUSB0.

The server caches Bluetooth data for 60 seconds. Failed reads wait 60 seconds before retrying. Unavailable devices are omitted from the response.

Diagnostics

Stop the server before connecting directly. Scan and collect reports from both Rivers:

uv run --extra ecoflow-bt python -u tools/ecoflow-bt.py --user-id YOUR_USER_ID --scan --timeout 30

Add --watch to print every packet until Ctrl+C. Watch mode ignores the telemetry timeout, but stops on a lost connection. Its payloads are already decrypted. Keep diagnostic output private because it can contain device and account identifiers.

The scan detects encryption automatically. To select one discovered device, add --device ADDRESS. Without scanning, replace --scan with --device ADDRESS --serial-number SERIAL. Direct connections default to Type 7. Session keys stay internal. The script has no encryption override or key-export option.

River 2 collection waits for three valid core reports, not optional inverter or solar reports. River 3 waits for 53 baseline fields across several reports. These checks do not guarantee every possible field. A timeout reports incomplete collection. Use --watch to receive later reports.

Both models report charge, temperature, power, and time estimates through separate decoders. Missing measurements stay absent. See the River 2 measurement reference and River 3 field reference for units, decoding rules, and known limits.

Client snapshots also include reported protocol fields under ef_river2_* and ef_river3_display_*, alongside the shared measurements and raw packets. Partial reports retain earlier field values. Nested River 3 groups use JSON text in their info fields. The references above describe names, units, and limits.

Running via systemd

Before you start a service, install its dependencies in the service's working directory with uv sync --locked --no-dev. Add --extra ecoflow-bt for Bluetooth, --extra influxdb for InfluxDB, or both if needed.

The service files use uv run --no-sync. This keeps services from changing the shared environment when they start. Set the uv executable to an absolute path if it is not on systemd's search path.

Copy bmspy-server.service to /etc/systemd/system, adjust WorkingDirectory and the ExecStart line as needed, then enable and start it:

cp bmspy-server.service /etc/systemd/system
$EDITOR /etc/systemd/system/bmspy-server.service
systemctl daemon-reload
systemctl enable bmspy-server
systemctl start bmspy-server

Running a client

To print a summary of all connected devices:

uv run bmspy

To show only a specific device:

uv run bmspy --ups network

To push data for all devices to InfluxDB (each measurement is tagged ups=<name>):

uv run --extra influxdb bmspy-influxdb --url https://influx.example.com --org myorg --token mytoken

To push data for a single device only:

uv run --extra influxdb bmspy-influxdb --ups network --url ...

InfluxDB connection details can also be supplied via environment variables (INFLUXDB_V2_URL, INFLUXDB_V2_ORG, INFLUXDB_V2_TOKEN) instead of command-line flags.

Development

Install all extras and run the tests:

uv sync --locked --all-extras
uv run --locked --all-extras pytest

To build a source archive and a wheel, which is an installable Python package:

uv build

uv.lock records the resolved dependency versions. After you change dependencies in pyproject.toml, run uv lock and include the updated lock file with the change.

S
Description
bmspy can be used to get information from a xiaoxiang-type BMS system.
Readme CC-BY-SA-4.0
530 KiB
Languages
Python 100%