Decode River 2 charge, temperature, power flow, and time estimates. Preserve precise charge readings across packet reordering and omit unavailable time estimates. Require valid PD, EMS, and BMS core heartbeats for diagnostic completion. Report optional packets separately and support raw watch output with reliable disconnect cleanup. Use synthetic regression tests and keep captures, credentials, and external keydata private. Device details come from command-line arguments or discovery. This commit retains Poetry; the separate packaging commit migrates to uv.
118 lines
4.4 KiB
Markdown
118 lines
4.4 KiB
Markdown
# bmspy
|
|
|
|
bmspy is a tool to get information from a [xiaoxiang-type](https://www.lithiumbatterypcb.com/product/4s-or-3s-12v-li-ion-or-lifepo4-battery-smart-bms-with-bluetooth-function-uart-and-rs485-communication-with-60a-to-120a-constant-current/?attribute_specification-selection=4S+Lifepo4+120A+with+UART+and+RS485) BMS system, using some sort of serial connection.
|
|
|
|
It can display the information as text, in JSON, or export the data continuously to InfluxDB or a Prometheus exporter.
|
|
|
|
Multiple BMS/UPS 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 UPS name.
|
|
|
|
To install:
|
|
git clone https://git.treehouse.org.za/tim/bmspy
|
|
cd bmspy
|
|
poetry install
|
|
|
|
Or, to install with influxdb and/or prometheus support:
|
|
poetry install -E influxdb -E prometheus
|
|
|
|
## Running the server
|
|
|
|
The server daemon reads from one or more serial devices and makes the data available over a Unix socket.
|
|
|
|
Single device (defaults to `/dev/ttyUSB0`):
|
|
|
|
poetry run bmspy-server
|
|
|
|
Multiple devices, with optional names (default name is derived from the device path, e.g. `ttyUSB0`):
|
|
|
|
poetry run bmspy-server -d network:/dev/ttyUSB0 -d nas:/dev/ttyUSB1
|
|
|
|
To run via systemd, 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 UPSes:
|
|
|
|
poetry run bmspy
|
|
|
|
To show only a specific UPS:
|
|
|
|
poetry run bmspy --ups network
|
|
|
|
To push data for all UPSes to InfluxDB (each measurement is tagged `ups=<name>`):
|
|
|
|
poetry run bmspy-influxdb --url https://influx.example.com --org myorg --token mytoken
|
|
|
|
To push data for a single UPS only:
|
|
|
|
poetry run 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.
|
|
|
|
## EcoFlow Bluetooth LE devices
|
|
|
|
Install the Bluetooth dependencies:
|
|
|
|
```bash
|
|
poetry install -E ecoflow-bt
|
|
```
|
|
|
|
Close the EcoFlow app and stop other Bluetooth collectors before connecting.
|
|
|
|
### Setup
|
|
|
|
Get your EcoFlow account user ID:
|
|
|
|
```bash
|
|
poetry 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](https://github.com/rabits/ha-ef-ble). From the bmspy repository root, download it:
|
|
|
|
```bash
|
|
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.
|
|
|
|
### Diagnostics
|
|
|
|
Scan and collect reports from nearby supported devices:
|
|
|
|
```bash
|
|
poetry run 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. A timeout reports incomplete collection. Use `--watch` to receive
|
|
later reports.
|
|
|
|
River 2 reports charge, temperature, power, and time estimates. Missing measurements
|
|
stay absent. See the [River 2 measurement reference](docs/ecoflow-river2-fields.md)
|
|
for units, decoding rules, and known limits.
|
|
|
|
Client snapshots include all complete River 2 heartbeat fields under
|
|
`ef_river2_*`, alongside the shared measurements and raw packets.
|
|
Partial reports retain earlier field values. See the
|
|
[River 2 field reference](docs/ecoflow-river2-fields.md#reported-fields-available-to-clients)
|
|
for names, units, and limits.
|