tools/generate_grafana_ups.py writes grafana-ups.json, which shows the JBD network UPS, the River 2 desktop UPS, and the River 3 NAS UPS in three columns. Git ignores the generated file. Each EcoFlow column shows one time-remaining panel in hours, for the direction in use. The River 2 histories add pack current and remaining capacity. The River 3 reports neither, so its histories add battery power and charge.
123 lines
5.5 KiB
Markdown
123 lines
5.5 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 three columns within a 24-column, 24-row grid. This matches
|
|
the original dashboard's grid height. 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
|
|
|
|
All three columns show battery charge and temperature history.
|
|
The Network column also shows pack voltage, signed current, capacity in amp-hours,
|
|
and individual cell voltages. Its cell voltage history includes current on the
|
|
right axis, in amps. Its temperature history includes remaining capacity on the
|
|
right axis, in amp-hours. The EcoFlow columns show total input/output power,
|
|
the time remaining, and battery power-flow flags.
|
|
|
|
The EcoFlow histories also show battery values. Each model reports different
|
|
values:
|
|
|
|
| Panel | Desktop (River 2) | NAS (River 3) |
|
|
|---|---|---|
|
|
| Input / output history | Signed pack current on the right axis, in whole amps. | Signed battery power on the watt axis. Positive means charge. |
|
|
| Temperature history | Remaining capacity on the right axis, in amp-hours. | Charge on the right axis, in percent. |
|
|
|
|
River 3 reports no battery current and no remaining capacity in amp-hours.
|
|
|
|
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. Network histories plot 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.
|
|
|
|
EcoFlow histories average readings within each display interval. Missing intervals
|
|
remain gaps. Temperature sensors and battery cells remain separate series.
|
|
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.
|
|
|
|
EcoFlow input/output totals can include AC bypass. They do not establish battery
|
|
charge direction. The flow flags come from battery-side measurements. Small idle
|
|
losses can count as discharge. JBD charge-control bits describe switches rather
|
|
than power flow, so the dashboard does not compare them with the EcoFlow flags.
|
|
|
|
The 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 in the flow flags. If the battery is idle, or the device sends no
|
|
estimate, the 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.
|
|
The dashboard does not invent a runtime estimate for the JBD or 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.
|