Files
bmspy/docs/ecoflow-river2-fields.md
T
tim 886991caf3 Add River 2 Bluetooth telemetry and diagnostics
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.
2026-10-08 14:02:45 +02:00

5.2 KiB

River 2 measurements

River 2 models with serial prefixes R601 and R603 use packet version 2. Encryption is separate from the packet version. The tested River 2 uses Type 7 encryption, not Type 1. River 3 uses a separate decoder.

bmspy/ecoflow_river2.py contains the binary layouts, numeric decoder, and measurement rules. bmspy/ecoflow_bt.py handles Bluetooth transport and resets the decoder's source priorities before each connection. bmspy/ecoflow_snapshot.py defines the shared EcoFlow snapshot.

Normal snapshot

A snapshot contains the latest received measurements. Missing measurements stay absent. These field names are also used by River 3, but each model has its own rules for interpreting the device reports.

Field Meaning
ef_input_power_watts Total device input power, W.
ef_output_power_watts Total device output power, W.
bms_temperature_celcius Battery temperature at sensor 1, °C. The spelling preserves the existing field name.
bms_capacity_charge_ratio Battery charge as a ratio from 0 to 1.
ef_remaining_time_minutes General remaining-time estimate, minutes.
ef_charge_remaining_time_minutes Charging-time estimate from the energy management module, minutes.
ef_discharge_remaining_time_minutes Discharging-time estimate from the energy management module, minutes.
bms_charge_is_charging Whether battery-side power flows into the battery.
bms_charge_is_discharging Whether battery-side power flows out of the battery.
ef_charge_state Numeric device state code. Observed R601 values are 0 for idle, 1 for charging, and 2 for discharging.

Input power alone does not indicate battery charging. The device can supply an AC load without charging its battery. Do not apply River 2 state-code meanings to River 3.

Reported fields available to clients

Clients also receive every complete field from the five known heartbeat layouts. A heartbeat is a periodic report from a device module. The field names use these prefixes:

Report Prefix Example
Device (PD) ef_river2_pd_ ef_river2_pd_usb1_watts
Energy management (EMS) ef_river2_ems_ ef_river2_ems_max_charge_soc
Battery management (BMS) ef_river2_bms_ ef_river2_bms_cycles
Inverter (INV) ef_river2_inv_ ef_river2_inv_inv_out_vol
Solar controller (MPPT) ef_river2_mppt_ ef_river2_mppt_in_watts

These fields appear in EcoFlowSnapshot.items(), socket responses, and client snapshots. InfluxDB and Prometheus export them alongside the normal measurements. Prometheus adds fields that first arrive after the exporter starts.

Numeric fields use BMSScalarField.raw_value and the units from the layout. They retain reported state codes, zero values, and unavailable-time codes such as 5999. They do not replace the normal measurements or their interpretation rules. For example, ef_river2_pd_soc uses percent, while bms_capacity_charge_ratio uses a ratio from 0 to 1.

Byte fields use BMSInfoField.info with a 0x hexadecimal string. This includes version, reserved, and other byte fields omitted by the text decoder. Bytes beyond the last complete field use the same format under <prefix>trailing_bytes. Their meanings remain unknown.

Each field retains its latest received value for the snapshot. Shorter firmware reports do not erase earlier trailing fields or create zero values for missing fields. A snapshot can therefore combine values from different reports. A rejected report leaves the earlier decoded fields unchanged and adds <prefix>decode_error. The next accepted report removes that error. The ef_pkt_<src>_<cmdset>_<cmdid> field always retains the latest raw payload.

Source priority and units

Within each connection, charge percentage prefers the precise battery-management reading, then the precise energy-management reading, then an integer reading. Later integer packets cannot overwrite a precise reading. New readings from the preferred source still update the snapshot.

R601 pack voltage and current use volts and signed amps. Cell voltages and current limits use millivolts and milliamps. Unverified inverter configuration fields have no unit labels in diagnostics.

The normal snapshot omits negative, all-ones, and 5999 time estimates. R601 samples report 5999 for inactive directions, but it can also mean an unknown or capped estimate. Diagnostics retain these raw values. Other estimates remain unchanged. This rule does not apply to River 3.

Diagnostic collection

The diagnostic script waits for valid PD, EMS, and BMS reports. These are periodic reports from the device, energy management, and battery management modules. Empty or truncated reports do not count. Inverter (INV) and solar-controller (MPPT) reports are optional and do not delay completion.

Raw packet keys include the source module: ef_pkt_<src>_<cmdset>_<cmdid>. This keeps reports from different modules separate, even when they share a command number. Watch mode also shows optional reports and unclassified packets.

Live R601 checks cover idle, charging, and discharging operation. Automated tests use synthetic packets. These results do not validate River 3 operation.

See the README for setup and commands.