The dashboard started with gauges and histories of equal weight, so a power failure and its effect were hard to find. The first rows now show the charge, the power source, the time remaining, and the errors of each device. Below them, one band shows each period on battery power, and one chart shows the charge of the three devices. The charge history adds the pack current of the JBD and the River 2 on a right axis, as dashed lines in the color of each device. The charge limits apply to the charge lines only. A time-remaining panel with no estimate now names the state. The JBD panel shows "On mains" while the pack does not discharge. The River 2 panel shows "Idle" while the device reports 5999 minutes for the two directions. The River 2 errors panel names the module that reports a code and shows the code in hexadecimal. The solar controller reports 4096 with no solar input, and the panel counts that value as zero.
183 lines
8.6 KiB
Markdown
183 lines
8.6 KiB
Markdown
# Three-UPS Grafana dashboard
|
|
|
|
The repository contains the generator for the dashboard, and Git ignores the
|
|
generated file. From the repository root, write `grafana-ups.json`:
|
|
|
|
```bash
|
|
python tools/generate_grafana_ups.py
|
|
```
|
|
|
|
Import `grafana-ups.json` into Grafana. It contains the
|
|
Grafana v2 dashboard model directly. Properties such as `title`, `elements`, and
|
|
`layout` are at the JSON root, not inside the supplied export's `spec` wrapper.
|
|
It uses Flux queries and requires an InfluxDB data source configured for Flux,
|
|
not SQL or InfluxQL.
|
|
Select that source in the `InfluxDB (Flux)` control. The `Bucket` control
|
|
starts at `ups`. Enter the bucket name without quotes. Queries use
|
|
`from(bucket: "${bucket:raw}")` to prevent Grafana from adding a second pair of quotes.
|
|
|
|
The dashboard uses a 24-column grid. The first 23 rows show the present state
|
|
of each device, the power source history, and the charge history. The rows below
|
|
them show detail. Grafana can rearrange panels on small screens.
|
|
The original `grafana-network-ups.json` is unchanged.
|
|
|
|
## Device names
|
|
|
|
The exporter must write these `ups` tag values:
|
|
|
|
| Tag | Display label | Device | Column |
|
|
|---|---|---|---|
|
|
| `network` | Network | JBD serial BMS | Left |
|
|
| `desktop` | Desktop | EcoFlow River 2 | Middle |
|
|
| `nas` | NAS | EcoFlow River 3 | Right |
|
|
|
|
The tags are server-assigned names, not device model selectors. Display labels do
|
|
not change the stored tags. If your server uses different names, update `DEVICES`
|
|
in the generator and regenerate the dashboard. For example:
|
|
|
|
```bash
|
|
uv run --extra ecoflow-bt bmspy-server --socket /tmp/bmspy-ups.sock \
|
|
-d network:/dev/ttyUSB0 \
|
|
-d 'desktop@RIVER2_MAC/RIVER2_SERIAL/YOUR_USER_ID' \
|
|
-d 'nas@RIVER3_MAC/RIVER3_SERIAL/YOUR_USER_ID'
|
|
```
|
|
|
|
Set `INFLUXDB_V2_URL`, `INFLUXDB_V2_ORG`, and `INFLUXDB_V2_TOKEN`.
|
|
In another terminal, export all three devices:
|
|
|
|
```bash
|
|
uv run --extra influxdb bmspy-influxdb --socket /tmp/bmspy-ups.sock --bucket ups
|
|
```
|
|
|
|
Do not add `--ups` to this exporter command. That option restricts export to one device.
|
|
|
|
## What the panels show
|
|
|
|
The top of the dashboard has one column for each device. Each column shows
|
|
these values, from the latest export within five minutes:
|
|
|
|
| Panel | Network (JBD) | Desktop (River 2) and NAS (River 3) |
|
|
|---|---|---|
|
|
| Charge | Reported charge. | Reported charge, and the charge limit of the device. |
|
|
| Source | `On battery` while the pack current is negative. | `Mains` while the total input power is above zero. |
|
|
| Second row | Pack voltage and signed pack current. | Total input power and total output power. |
|
|
| Time remaining | Calculated from remaining capacity and discharge current. | The estimate that the device reports. |
|
|
| Protection or Errors | The name of each protection flag that is set, or `None`. | `OK`, or each reported error code that is not zero. |
|
|
|
|
Two panels below the columns cover all three devices. `Power source` is a state
|
|
timeline, which is a band that shows a state over time. It shows each period on
|
|
battery power. `Charge history` shows the charge of the three devices on the
|
|
left axis. Its dashed lines show the signed pack current of Network and Desktop
|
|
on the right axis, in amps. A dashed line has the color of its device, and a
|
|
negative current means discharge.
|
|
|
|
The next row shows the values that only one model reports:
|
|
|
|
| Panel | Content |
|
|
|---|---|
|
|
| Network · Cell voltage history | Each cell voltage, and signed pack current on the right axis, in amps. |
|
|
| Desktop · Input / output history | Total input and output power, and signed pack current on the right axis, in whole amps. |
|
|
| NAS · Input / output history | Total input and output power, and signed battery power on the watt axis. Positive means charge. |
|
|
|
|
River 3 reports no battery current and no remaining capacity in amp-hours.
|
|
|
|
The last rows show values that change slowly. `Output power` compares the loads
|
|
of the two EcoFlow devices. `Temperature` shows the battery temperature of all
|
|
three devices. Each `Battery` panel shows these values:
|
|
|
|
| Device | Values |
|
|
|---|---|
|
|
| Network | Charge cycles, cell spread, remaining capacity, and nominal capacity. |
|
|
| Desktop | Charge cycles, health, full capacity, and design capacity. |
|
|
| NAS | Health and design capacity. |
|
|
|
|
Cell spread is the highest cell voltage minus the lowest. A value that grows
|
|
over time shows cells that drift apart.
|
|
|
|
## Calculated values and limits
|
|
|
|
The queries calculate two values that no device reports: the Network time
|
|
remaining and the Network cell spread. The Network time remaining is the
|
|
remaining capacity divided by the discharge current. It assumes that the present
|
|
load continues. While the pack does not discharge, there is no load to
|
|
calculate from, and the panel shows `On mains`.
|
|
|
|
The source rule reads power, not the mains connection. A River with solar or car
|
|
input shows `Mains`. An idle River 2 draws no input power on mains, so its rule
|
|
also reads the AC input voltage from the inverter report. A River 3 that draws
|
|
no input power shows `On battery`.
|
|
|
|
A JBD protection flag is an action of the battery management system. For
|
|
example, it ends the charge at the cell voltage limit. A set flag is therefore
|
|
not always a fault.
|
|
|
|
The meanings of the EcoFlow error codes are not known to bmspy, and the panel
|
|
shows `OK` for zero. The River 3 panel shows the highest of its codes.
|
|
|
|
The River 2 panel shows `Device` for the code of the main controller. It shows
|
|
`Modules` and `OK` while the battery, inverter, and solar codes are all zero.
|
|
A module code that is not zero shows in hexadecimal, with the name of its module:
|
|
`Battery`, `Battery fault`, `Inverter`, or `Solar`. The value is orange, because
|
|
a code that bmspy cannot read is not always a fault.
|
|
|
|
The solar controller of a River 2 reports the code 4096 while it has no solar
|
|
input. The panel counts that value as zero. A solar code with a different value
|
|
shows as `Solar`.
|
|
|
|
Current-value panels query the last five minutes, regardless of the history time
|
|
picker. An absent series remains absent, not zero.
|
|
A panel with no current series shows a no-data indication.
|
|
The server can return cached Bluetooth readings, which receive new export timestamps.
|
|
|
|
History panels follow the time picker. The Network cell voltage history plots
|
|
recorded samples without averaging or adding empty intervals, as in
|
|
`grafana-network-ups.json`.
|
|
Lines connect recorded samples, including samples on either side of a period
|
|
without exports. A continuous line does not prove that exports continued throughout
|
|
that period. Explicit null values still break the line. The queries do not replace
|
|
missing readings with zero.
|
|
|
|
The other histories average readings within each display interval. Missing
|
|
intervals remain gaps. Temperature sensors and battery cells remain separate series.
|
|
The power source panel uses the lowest reading of each interval, so a short power
|
|
failure stays visible. It ends a state after five minutes with no reading.
|
|
The dashboard refreshes every 30 seconds.
|
|
|
|
Charge values use ratios from 0 to 1. The dashboard displays them as percentages.
|
|
The colors indicate below 20%, 20% to below 50%, and 50% or higher. These are
|
|
visual thresholds, not device alarms or battery-specific safety limits.
|
|
An EcoFlow charge at the charge limit is a full battery.
|
|
|
|
EcoFlow input/output totals can include AC bypass. They do not establish battery
|
|
charge direction.
|
|
|
|
The EcoFlow time-remaining panels show the device estimate in hours, for the
|
|
direction in use. River 2 reports an estimate for that direction only, so its
|
|
panel shows `To empty` or `To full`. River 3 reports both estimates at all
|
|
times, so its panel uses `ef_remaining_time_minutes`, which holds the estimate
|
|
for the direction of the battery power. If the battery is idle, or the device
|
|
sends no estimate, the River 3 panel shows `No estimate`. A River 3 that supplies
|
|
its own small losses from the battery counts as discharging, and shows a long time
|
|
to empty.
|
|
|
|
River 2 reports 5999 minutes for a direction that has no estimate. If the two
|
|
directions both have that value, the River 2 panel shows `Battery` and `Idle`.
|
|
The dashboard does not apply River 2 state-code meanings to River 3.
|
|
|
|
## Regeneration
|
|
|
|
The generator uses the Python standard library and does not need the original
|
|
Grafana export. It writes `grafana-ups.json` in the repository root, or the
|
|
file that `--output` names.
|
|
|
|
The default output is the bare dashboard model for Grafana's JSON import/editor.
|
|
To include the API resource wrapper, use `--api-resource`:
|
|
|
|
```bash
|
|
python tools/generate_grafana_ups.py --api-resource --output grafana-ups-resource.json
|
|
```
|
|
|
|
This adds `apiVersion`, `kind`, and `metadata`, and places the dashboard under `spec`.
|
|
|
|
To change the layout or device names, edit the generator and run it again.
|