Skip to content

Grafana panel — Circuit Power Over Time (stacked)

Date: 2026-06-22 File touched: grafana/dashboard.json (source of truth, file-provisioned) Deploy path: push to mainci.yml deploy-grafana → scp to provisioned path → Grafana file provider auto-reloads ~30s (no restart)

Problem

The Grafana Home Intelligence dashboard shows whole-home power (panel 24) and an instantaneous per-circuit snapshot (panel 33, "Circuit Power — Now"), but there is no time-series breakdown of per-circuit power. The user wants to select/zoom a time window and see which circuits were drawing power during that window.

Solution

Add one full-width stacked-area timeseries panel to the ⚡ Energy row: one series per branch circuit, stacked so the total height ≈ whole-home draw and each band is one circuit's contribution. Drill-down = Grafana's native zoom + multi-tooltip.

Sensor scope

Mirror the existing "Circuit Power — Now" (panel 33) entity set so the stacked total is meaningful and free of double-counting:

  • em_*_power circuit sensors, excluding the split-phase main legs *_l1_power / *_l2_power
  • plus the summed 240 V appliance loads air_handler_power, stove_power, dryer_power

Queries (InfluxQL)

Two targets (not one OR'd query — avoids InfluxQL AND/OR precedence pitfalls; same pattern panel 33 uses). Data model: measurement "W", tags entity_id (no sensor. prefix) and friendly_name.

  • A: SELECT mean("value") FROM "W" WHERE "entity_id" =~ /^em_/ AND "entity_id" =~ /_power$/ AND "entity_id" !~ /_l[12]_power$/ AND $timeFilter GROUP BY time($__interval), "friendly_name" fill(none)
  • B: SELECT mean("value") FROM "W" WHERE "entity_id" =~ /^(air_handler|stove|dryer)_power$/ AND $timeFilter GROUP BY time($__interval), "friendly_name" fill(none)

alias: $tag_friendly_name, resultFormat: time_series, rawQuery: true.

Visual

  • drawStyle: line, fillOpacity: 25, lineWidth: 1, showPoints: never, spanNulls: true
  • custom.stacking.mode: normal
  • unit: watt, color.mode: palette-classic
  • tooltip mode: multi, sort: desc
  • legend: table, bottom, calcs ["lastNotNull", "max"] (sortable by biggest consumer)
  • datasource: copy the InfluxDB uid used by panels 24/33 (P14502BC03F6B8823) — do not invent

Placement

Full width w:24, h:10, inserted directly above panel 33 (the snapshot it complements). Panel 33 and anything below shift down by 10 rows. New unique panel id (max existing + 1).

Testing / verification

  • make pytest — Grafana guards must pass (no ${DS_INFLUXDB}, no now()-24h, real datasource uids, JSON valid)
  • After deploy, confirm gh run list --workflow=ci.yml --limit 1 succeeded.

Docs

grafana/dashboard.json is a technical artifact; no user-facing MkDocs page documents individual Grafana panels (the household manual covers HA dashboards/alerts, not Grafana). No manual update required.

Out of scope (YAGNI)

  • No per-circuit cost overlay (panel 24 already pairs power with TOU rate).
  • No new InfluxDB retention/recording changes — all sensors already log to the W measurement.