Add a Grafana dashboard generator for the three UPS devices
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.
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user