Files
bmspy/docs/ecoflow-river3-fields.md
tim ef7a6b5f92 Simplify wording in the documentation
Put each condition before its statement. Split long sentences. Use one term for each concept. Replace the description of possible checklist changes with a statement of the present behavior.
2026-10-10 10:12:35 +02:00

23 KiB
Raw Permalink Blame History

River 3 diagnostic fields

This reference explains the fields in the reviewed R651 reports. It covers all 110 distinct top-level fields in that watch capture. It does not change the 53-field completion checklist or claim that these are all possible device fields.

The source for field numbers, names, and types is upstream proto/pr705.proto, specifically DisplayPropertyUpload. These messages arrive at source 0x02, command set 0xFE, command 0x15.

A schema describes the message structure. It does not explain every status code, bit flag, physical connector, or unit conversion. The tables distinguish those limits from known field names. Units shown for the current checklist follow the current diagnostic decoder. The live tests do not independently establish every unit or the accuracy of every measurement.

Normal measurements and validation

Support covers serial prefixes R651, R653, R654, and R655. River 3 uses packet version 3 and a separate decoder from River 2. Both models share the snapshot field names, not their decoding rules.

Temperature prefers the maximum cell temperature, with composite battery temperature as a fallback. Signed battery power determines charging or discharging. Total input power alone does not indicate charging. The general remaining-time field selects the estimate for the active battery direction. It stays absent while the direction is idle or unknown.

Time estimates use minutes. River 2's 5999 rule does not apply. A live R651 sample reported 4556 minutes while the display showed 75–76 hours. This supports the time unit, not the accuracy of the prediction. Live checks cover no-load and USB-C-load operation. Charging and further display comparisons still need validation.

Diagnostic collection combines each field's latest value across reports, not one simultaneous measurement. Zero and explicit unavailable values count as received. Malformed messages and required fields with an unexpected encoding do not count. Missing fields do not erase earlier measurements. The normal snapshot omits unusable values. If the diagnostic checklist counts the receipt of such a value, the snapshot still omits it.

Reported fields available to clients

Clients receive all reported fields from DisplayPropertyUpload, beyond the normal measurements and the completion checklist. The decoder knows 296 top-level fields from the pinned schema. It exports only fields that the device sends.

Field names use ef_river3_display_<protocol_name>, such as ef_river3_display_pow_get_typec1 or ef_river3_display_cms_batt_soh. They 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.

Numbers and boolean values use BMSScalarField.raw_value. Enum values are named numeric codes. They retain the code in raw_value. If the schema defines a name, they retain the name in value. Only fields with existing unit annotations carry units. Do not assume that an untranslated code or an unannotated number is a physical measurement.

Strings use BMSInfoField.info without conversion. Nested messages and repeated fields use JSON text in info. Clients can use json.loads(field.info) for those groups. This preserves named children, lists, enum codes and names, and explicit empty groups. Missing children do not become zero values. Statistics retain their reported numbers without an assumed energy unit.

Unknown fields use ef_river3_display_field_<number>. Their info contains a JSON list with each occurrence's wire_type and raw hexadecimal encoding. Integer encodings also include their unsigned value. The decoder does not guess the meaning of unknown fields.

Separate reports update only the fields that they contain. A reported nested group replaces its earlier group, while absent top-level fields retain their earlier values. Each snapshot can therefore combine several reports. Malformed fields, invalid strings, and non-finite numbers reject the extended report without changing earlier extended fields. ef_river3_display_decode_error records the reason until the next accepted report. The normal measurement decoder keeps its separate validation rules.

Raw packet fields remain available as ef_pkt_<src>_<cmdset>_<cmdid>. They retain the latest payload, including rejected and unknown reports. Runtime routing at 0x02/0xFE/0x16 remains unconfirmed. Those reports stay raw-only in client snapshots, although the diagnostic tool can show a tentative schema interpretation. They do not supply normal measurements.

How to read the reports

Protobuf is the binary message format used by River 3. Each field has a numeric identifier. Fields can arrive in separate messages with the same source and command numbers. Missing fields are not zero values.

The bms_ prefix identifies battery-management data. The cms_ prefix identifies device-level battery data. Similar fields belong to different reporting layers. They do not necessarily describe separate batteries or independent measurements.

SOC means state of charge, the reported charge percentage. SOH means state of health, a reported battery health estimate. Neither is a direct capacity test. AC means alternating current. DC means direct current. PV identifies the solar/DC input in these messages. MPPT identifies the solar-input charging controller.

A boolean field is a yes/no flag. A raw state code is a number whose individual meanings remain unverified. In particular, River 2 and River 3 do not share a verified charge-state code mapping.

The measurements and configuration names below are local checklist groups. They are not message types or exact boundaries between the device's reports. Several configuration fields arrive in the first report.

Current measurement and status checklist: 31 fields

Every row below is required by the current diagnostic checklist. Receipt does not guarantee a usable exported measurement. Zero and explicit unavailable values still establish that a field arrived.

Field Protocol name Information represented
1 errcode Overall device error code. Individual code meanings remain unverified.
3 pow_in_sum_w Total device input power, W. This is not necessarily battery charging power.
4 pow_out_sum_w Total device output power, W.
9 pow_get_qcusb1 Power at USB-A/QC channel 1, W.
10 pow_get_qcusb2 Power at USB-A/QC channel 2, W.
11 pow_get_typec1 Signed power at USB-C channel 1, W. A discharge sample reported a negative value.
12 pow_get_typec2 Power at USB-C channel 2, W. A reported slot does not prove that a physical port exists.
37 pow_get_12v Power on the 12 V DC channel, W.
54 pow_get_ac_in AC input power, W.
148 pv_chg_type Solar/DC charging mode code. The value mapping remains unverified.
158 pow_get_bms Signed battery power, W. Positive means charging and negative means discharging in the current mapping.
212 dev_sleep_state Device sleep-state code. The value mapping remains unverified.
242 bms_batt_soc Battery-management charge estimate, %.
243 bms_batt_soh Battery-management health estimate, %.
248 bms_design_cap Battery design capacity. The current diagnostic label is mAh.
254 bms_dsg_rem_time Battery-management estimate of remaining discharge time, minutes.
255 bms_chg_rem_time Battery-management estimate of remaining charge time, minutes.
258 bms_min_cell_temp Minimum battery-cell temperature, degrees Celsius.
259 bms_max_cell_temp Maximum battery-cell temperature, degrees Celsius. If present, this supplies the normal snapshot temperature.
260 bms_min_mos_temp Minimum temperature at battery switching transistors, degrees Celsius. This is not a cell temperature.
261 bms_max_mos_temp Maximum temperature at battery switching transistors, degrees Celsius.
262 cms_batt_soc Device-level charge estimate, %. This supplies the normal snapshot charge ratio.
263 cms_batt_soh Device-level battery health estimate, %.
268 cms_dsg_rem_time Device-level estimate of remaining discharge time, minutes.
269 cms_chg_rem_time Device-level estimate of remaining charge time, minutes.
275 cms_bms_run_state Battery-system operating-state code. The value mapping remains unverified.
281 bms_chg_dsg_state Battery-management charge/discharge state code. It is not decoded using River 2 meanings.
282 cms_chg_dsg_state Device-level charge/discharge state code. Exported separately from power-based direction.
355 ups_alarm Alarm flag associated with uninterruptible power supply operation. Upstream spells this field ups_alram. bmspy corrects the spelling. Exact trigger conditions remain unverified.
361 pow_get_pv Solar/DC input power, W.
368 pow_get_ac_out AC output power, W.

If aggregate output power is positive, individual channel power can still be signed. Do not apply one sign convention to every power field. The current snapshot uses battery power, not an untranslated state code, to select direction.

The two time estimates can both be present while only one direction is active. Their presence does not mean simultaneous charging and discharging. A value of 4294967295 is treated as unavailable for the normal River 3 time measurements.

Current configuration checklist: 22 fields

These values describe configuration, limits, and connection state. A configured power limit is not a measurement of current power. A charger flag alone does not prove that the battery is receiving power.

Field Protocol name Information represented
7 energy_backup_en Whether the energy-backup feature is enabled.
8 energy_backup_start_soc Charge threshold for the energy-backup feature, %. Exact transition behavior remains unverified.
17 dev_standby_time Device standby timeout setting, seconds in the current decoder.
18 screen_off_time Display-off timeout setting, seconds in the current decoder.
19 ac_standby_time AC standby timeout setting, seconds in the current decoder.
25 xboost_en Whether X-Boost is enabled. This is a setting, not proof that it is active under a load.
33 flow_info_12v Encoded flow/status information for the 12 V channel. The bits remain unverified.
74 dc_out_open DC output enabled flag.
195 en_beep Audible signal enabled flag.
202 plug_in_info_ac_charger_flag AC charger flag. Its exact relationship to cable presence and active charging remains unverified.
209 plug_in_info_ac_in_chg_pow_max Reported AC input charging-power limit, W.
211 ac_out_freq AC output frequency setting, Hz. This is separate from runtime frequency measurements.
270 cms_max_chg_soc Maximum charge setting, %.
271 cms_min_dsg_soc Minimum charge setting for discharge, %.
356 plug_in_info_pv_dc_amp_max Solar/DC input current-limit setting, A in the current decoder.
358 low_power_alarm Low-battery alarm setting, % in the current decoder. The special meaning of zero remains unverified.
360 flow_info_pv Encoded flow/status information for the solar/DC input. The bits remain unverified.
364 plug_in_info_pv_charger_flag Solar/DC charger flag. It is not a power measurement.
365 plug_in_info_pv_chg_amp_max Reported maximum solar/DC charging current, A in the current decoder.
366 plug_in_info_pv_chg_vol_max Reported maximum solar/DC charging voltage, V in the current decoder.
367 flow_info_ac_out Encoded AC output flow/status information. The bits remain unverified.
458 plug_in_info_ac_in_chg_hal_pow_max Hardware-layer AC charging-power limit, W. Its exact relationship to field 209 needs device testing.

Information supplied by the third report: 20 fields

The reviewed capture contained three distinct report payloads, each repeated 68 times. The third payload contained the following 20 additional fields. None belongs to the current 53-field checklist.

DCP and DCP2 are connector/interface slot names in the schema. Their physical mapping on R651 remains unverified. Zero or empty values for a slot do not prove that the device has another physical connector.

PCS identifies power-conversion equipment in the fan field. PD identifies the main device controller here, not a USB charging port. LLC identifies a power-converter module in the schema.

Field Protocol name Information represented Value in the reviewed capture
30 pcs_fan_level Power-conversion fan level. Not a verified speed in revolutions per minute or a percentage. 0
83 plug_in_info_dcp2_in_flag DCP2 input/connection flag. Exact physical meaning remains unverified. false
84 plug_in_info_dcp2_dsg_chg_type DCP2 charge/discharge mode code. 0
85 plug_in_info_dcp2_charger_flag DCP2 charger flag. false
86 plug_in_info_dcp2_type DCP2 connected-device/interface type code. 0
87 plug_in_info_dcp2_detail DCP2 type/detail code. 0
88 plug_in_info_dcp2_sn DCP2 associated serial-number string. Treat populated values as private. Empty string
89 plug_in_info_dcp2_run_state DCP2 operating-state code. 0
90 plug_in_info_dcp2_firm_ver DCP2 firmware-version number. Version packing remains unverified. 0
91 plug_in_info_dcp2_resv DCP2 reserved information. Empty message
140 bms_err_code Battery-management error code. Specific nonzero codes remain unverified. 0
141 err_code_record_list List of error records, each with optional error code and timestamp. Timestamp units and epoch remain unverified. Ten empty records
213 pd_err_code Main device-controller error code. 0
215 mppt_err_code Solar/DC charging-controller error code. 0
232 llc_inv_err_code Power-converter/inverter error code. 0
432 plug_in_info_dcp_resv DCP reserved information. Empty message
434 plug_in_info_dcp_firm_ver DCP firmware-version number. Version packing remains unverified. 0
436 plug_in_info_dcp_run_state DCP operating-state code. 0
438 plug_in_info_dcp_err_code DCP error code. 0
439 plug_in_info_dcp2_err_code DCP2 error code. 0

The decoder now names all 20 fields using the pinned schema. Earlier versions named only fields 30, 140, 213, 215, and 232. The 53-field completion checklist still does not require this report.

Field 141 contains a nested list, not one error number. Its outer field 1 is a repeated ErrcodeRecordItem. Each item can contain error code in field 1 and timestamp in field 2. The ten empty entries in this capture contain neither value. They do not represent ten detected faults.

Fields 91 and 432 use ResvInfo, a message containing repeated unsigned integers in field 1. Both messages are empty in this capture. Reserved information has no verified operational meaning.

Other fields already present in the first two reports: 37 fields

These fields appeared in the earlier short run as well as the watch capture. They are outside the current checklist. Earlier versions printed numeric labels for these fields. The decoder now uses the schema names below.

Together, these 37 fields, the 53 required fields, and the third report's 20 fields account for all 110 observed top-level fields. This is a capture inventory, not a universal River 3 field list.

Field Protocol name Information represented
13 flow_info_qcusb1 USB-A/QC channel 1 flow/status code. Bit meanings remain unverified.
14 flow_info_qcusb2 USB-A/QC channel 2 flow/status code.
15 flow_info_typec1 USB-C channel 1 flow/status code.
16 flow_info_typec2 USB-C channel 2 flow/status code.
22 ac_always_on_flag AC always-on feature flag.
23 ac_always_on_mini_soc Minimum charge threshold associated with AC always-on operation.
45 flow_info_ac2dc AC-to-DC conversion flow/status code.
46 flow_info_dc2ac DC-to-AC conversion flow/status code.
47 flow_info_ac_in AC input flow/status code.
53 pow_get_ac AC-side power field. Its exact relationship to separate input/output totals needs testing.
61 plug_in_info_ac_in_flag AC input connection/status code.
62 plug_in_info_ac_in_feq AC input frequency field. The protocol spelling is retained.
77 pow_get_dcp2 DCP2 power field. Physical slot mapping and sign convention remain unverified.
78 flow_info_dcp2_in DCP2 input flow/status code.
79 flow_info_dcp2_out DCP2 output flow/status code.
147 output_power_off_memory Setting for retaining output-state information across power-off. Exact restore behavior needs testing.
152 flow_info_bms_dsg Battery discharge flow/status code. It is not a time estimate or charge percentage.
153 flow_info_bms_chg Battery charge flow/status code. It is not a time estimate or charge percentage.
219 time_task_current Current scheduled-task message. Empty in the reviewed capture.
227 llc_hv_lv_flag Converter high/low-voltage mode indicator. Despite the observed value 230, do not treat it as a measured voltage.
238 plug_in_info_ac_out_dsg_pow_max Maximum AC output power field, not current output power.
285 time_task_conflict_flag Scheduled-task conflict status.
286 time_task_change_cnt Scheduled-task change counter.
357 led_mode Light/display mode code. Exact modes remain unverified.
359 silence_chg_watt Quiet-mode charging-power setting. It is not an AC frequency field.
362 plug_in_info_pv_flag Solar/DC input flag.
363 plug_in_info_pv_type Solar/DC input type code.
423 flow_info_dcp_in DCP input flow/status code.
424 flow_info_dcp_out DCP output flow/status code.
425 pow_get_dcp DCP power field. Physical slot mapping and sign convention remain unverified.
426 plug_in_info_dcp_in_flag DCP input/connection flag.
427 plug_in_info_dcp_type DCP connected-device/interface type code.
428 plug_in_info_dcp_detail DCP type/detail code.
431 plug_in_info_dcp_dsg_chg_type DCP charge/discharge mode code.
433 plug_in_info_dcp_sn DCP associated serial-number string. Empty here, but populated values are private.
435 plug_in_info_dcp_charger_flag DCP charger flag.
463 display_statistics_sum List of accumulated statistics. This is not a list of instantaneous power readings.

Field 463 contains repeated StatisticsRecordItem messages in outer field 1. Each item uses field 1 for the statistic category and field 2 for its numeric content. Categories 2 through 7 identify AC output, 12 V output, USB-C output, USB-A output, AC input, and solar input energy, respectively.

Those six categories occur in the reviewed capture, along with empty entries. The schema does not establish the scaling of the recorded energy values. Do not label the raw numbers as Wh without further evidence. An absent content field is also distinct from an explicitly received zero.

The earlier generic decoder displayed both empty strings and empty nested messages as ''. The schema-based decoder now distinguishes them. Fields 88 and 433 are strings and retain ''. Empty messages in fields 91, 219, and 432 print as {}.

Why normal collection can omit the third report

The three observed payloads have the same route, 0x02/0xFE/0x15. They are not three separately requested message types. Their sizes and checklist coverage in this capture were:

Observed report Payload size Top-level fields Current required fields supplied
First 300 bytes 56 43: all 31 measurement/status fields and 12 configuration fields
Second 102 bytes 34 10: the remaining configuration fields
Third 80 bytes 20 None

The second report completes the current checklist. The collector can therefore exit before the third report arrives. If the third report arrives before the next completion check, its fields still appear in the accumulated final view.

There is no separate, shorter wait period assigned to the second report. Collection checks progress every half second. If the required information is present, it stops. It does not stop at a selected report count or idle period. The watch output does not timestamp each packet, so it cannot establish the exact interval between these reports.

The checklist requires 53 fields, and the first two reports supply all of them. With this report layout, use --watch to receive the third report.

Information that remains unresolved

The watch capture also contains eight-byte messages at 0x35/0x35/0x20. There are 17 such messages with seven distinct payloads. Their structure and meaning remain unverified. They must not be assigned field meanings from the protobuf schema merely because some bytes resemble protobuf tags.

This capture contains no known 0x02/0xFE/0x16 runtime report. It therefore does not establish runtime voltage/current fields from that route. The schema also contains many fields that this device did not report during the capture.

Naming a field is separate from interpreting its values or exporting it as a normal measurement. Verified names and nested structures are now decoded. State codes, physical slot mappings, units, and error causes still need independent evidence where this reference marks them as unverified.

Schema coverage and maintenance

bmspy/ecoflow_river3.py contains the curated units, numeric decoder, and measurement rules. bmspy/ecoflow_proto.py provides shared parsing and diagnostic formatting. Its format_* functions return readable text, not measurement values. The older diagnostic decode_* names remain aliases. Bluetooth transport stays in bmspy/ecoflow_bt.py. The shared snapshot stays in bmspy/ecoflow_snapshot.py.

bmspy/ecoflow_river3_schema.py contains generated descriptors for all 296 DisplayPropertyUpload fields and all 98 RuntimePropertyUpload fields in the pinned upstream schema. It also includes the 15 reachable message definitions and ten enum definitions. No network access or protobuf package is needed at runtime.

The decoder uses declared types for strings, nested messages, booleans, signed integers, floats, enums, and repeated values. It accepts packed and unpacked repeated integers. Known fields with an unexpected encoding retain their names and raw bytes, with an error rather than a misleading interpreted value.

Unknown future field numbers remain numeric/raw. The eight-byte 0x35/0x35/0x20 message is still unclassified. Full schema coverage does not establish the meaning of that separate message or runtime message routing.

The descriptor source is upstream commit 511e04702c83ddcc90cdcd575a1bbeffe2f061ad. Only protocol declarations are retained, not upstream decoder code or authentication keydata.

To reproduce the descriptors, run this command from the repository root:

python tools/generate_ecoflow_river3_schema.py --ref 511e04702c83ddcc90cdcd575a1bbeffe2f061ad

The generator retrieves public source files through the GitHub API. Without --ref, it resolves the current upstream main commit. Review the generated diff before accepting a schema update. Unsupported reachable types cause generation to fail rather than silently omit fields.