Energy and cost report: what the lights actually used this season #153

Closed
opened 2026-09-26 05:01:10 +00:00 by claude-bot · 2 comments
Collaborator

Idea

"What did the lights cost this year?" is a question everyone with a big display asks, and WLED already knows most of the answer. Report it per night, per event and per season, in kWh and in money.

What WLED provides

/json/info → leds.pwr is the estimated current draw in mA, computed by WLED's automatic brightness limiter (ABL) from the pixel values and brightness. leds.maxpwr is the configured limit.

  • #21 already sampled leds.pwr on the 16.0.0 controller during a fade and found it smooth and responsive (about 95 mA per 2 s).
  • It is an estimate, not a measurement. It is only as good as the ABL's per-LED current setting, and it assumes the configured LED type.
  • WLED does not report the supply voltage. Converting mA to watts needs the voltage from the user: 5 V, 12 V or 24 V.
  • Controller overhead (the ESP32 itself, PSU efficiency) is not included. A PSU efficiency factor, defaulting to around 0.85, makes the number honest.

Verified against main: WLEDInfo doesn't parse pwr or maxpwr today (services/wled_controller.py), and nothing samples it.

Design

  • Sample leds.pwr every 5 minutes while the lights are on. This can share the watchdog's /json/info read if that lands first (#148), with no extra request.
  • Integrate into a small power_samples → energy_daily rollup: Wh per night, attributed to the event and scheme that ran. Keep the raw samples for about 30 days and the dailies forever. It's a few hundred rows a year.
  • Settings: led_voltage (required for the report; the report says so when it's unset rather than guessing), psu_efficiency (0.85), energy_price_per_kwh, and currency.
  • UI: a season summary with total kWh and cost, a per-night bar chart, cost per event, and "most expensive scheme". Label everything as an estimate from WLED's power limiter.
  • Metrics: iris_wled_current_milliamps (gauge) and iris_energy_wh_total (counter), so it also works in Grafana.
  • Export: CSV.

Relationship to #55

#55 (power-draw estimation and PSU budget warning) is the before: predict a scheme's draw and warn if it exceeds the PSU. This is the after: record what was actually drawn. They share the voltage and efficiency settings, and the measured data can validate #55's estimator: predicted versus observed per scheme. Build whichever comes first so that the settings are shared.

Acceptance

  • leds.pwr and leds.maxpwr are parsed. Fixtures updated for each supported firmware version (#62), and older firmware without pwr degrades to "not available".
  • Samples are taken only while on, and attributed to the event and scheme. Nightly and seasonal totals are correct in a test with synthetic samples.
  • The report states that it's an estimate and refuses to invent a voltage.
  • Metrics and CSV export. CHANGELOG entry.
  • Sanity-checked once against a plug-in power meter on the real PSU, with the ratio recorded in the docs.
## Idea "What did the lights cost this year?" is a question everyone with a big display asks, and WLED already knows most of the answer. Report it per night, per event and per season, in kWh and in money. ## What WLED provides `/json/info` → `leds.pwr` is the **estimated current draw in mA**, computed by WLED's automatic brightness limiter (ABL) from the pixel values and brightness. `leds.maxpwr` is the configured limit. - #21 already sampled `leds.pwr` on the 16.0.0 controller during a fade and found it smooth and responsive (about 95 mA per 2 s). - **It is an estimate, not a measurement.** It is only as good as the ABL's per-LED current setting, and it assumes the configured LED type. - **WLED does not report the supply voltage.** Converting mA to watts needs the voltage from the user: 5 V, 12 V or 24 V. - Controller overhead (the ESP32 itself, PSU efficiency) is not included. A PSU efficiency factor, defaulting to around 0.85, makes the number honest. Verified against `main`: `WLEDInfo` doesn't parse `pwr` or `maxpwr` today (`services/wled_controller.py`), and nothing samples it. ## Design - **Sample** `leds.pwr` every 5 minutes while the lights are on. This can share the watchdog's `/json/info` read if that lands first (#148), with no extra request. - **Integrate** into a small `power_samples` → `energy_daily` rollup: Wh per night, attributed to the event and scheme that ran. Keep the raw samples for about 30 days and the dailies forever. It's a few hundred rows a year. - **Settings:** `led_voltage` (required for the report; the report says so when it's unset rather than guessing), `psu_efficiency` (0.85), `energy_price_per_kwh`, and `currency`. - **UI:** a season summary with total kWh and cost, a per-night bar chart, cost per event, and "most expensive scheme". Label everything as an **estimate from WLED's power limiter**. - **Metrics:** `iris_wled_current_milliamps` (gauge) and `iris_energy_wh_total` (counter), so it also works in Grafana. - **Export:** CSV. ## Relationship to #55 #55 (power-draw estimation and PSU budget warning) is the *before*: predict a scheme's draw and warn if it exceeds the PSU. This is the *after*: record what was actually drawn. They share the voltage and efficiency settings, and the measured data can validate #55's estimator: predicted versus observed per scheme. Build whichever comes first so that the settings are shared. ## Acceptance - [ ] `leds.pwr` and `leds.maxpwr` are parsed. Fixtures updated for each supported firmware version (#62), and older firmware without `pwr` degrades to "not available". - [ ] Samples are taken only while on, and attributed to the event and scheme. Nightly and seasonal totals are correct in a test with synthetic samples. - [ ] The report states that it's an estimate and refuses to invent a voltage. - [ ] Metrics and CSV export. CHANGELOG entry. - [ ] Sanity-checked once against a plug-in power meter on the real PSU, with the ratio recorded in the docs.
claude-bot added this to the v1.2.0 milestone 2026-09-26 05:02:37 +00:00
Author
Collaborator

Picking this up now that #148's watchdog is merged. The power sample piggybacks on the watchdog's /json/info read, so there's no second poll of the controller.

Can't be done from here: the sanity check against a plug-in power meter on the real PSU. It stays a manual acceptance item, with the method written into the docs.

Picking this up now that #148's watchdog is merged. The power sample piggybacks on the watchdog's `/json/info` read, so there's no second poll of the controller. **Can't be done from here:** the sanity check against a plug-in power meter on the real PSU. It stays a manual acceptance item, with the method written into the docs.
Author
Collaborator

Done in #180 (squash-merged, CI green).

Delivered:

  • Sampling reuses the watchdog's /json/info read. An energy_sampler job takes over when the watchdog is off, so exactly one job reads the controller.
  • Only lit readings count, with a closing 0 mA sample when the lights go off.
  • Trapezoid integration with a 3× interval gap cap.
  • energy_daily in mAh, so the voltage can be set later.
  • The report refuses to invent a voltage.
  • Also: an /energy page and shortcut, the CSV export, the metrics, and migration 0012.

Deviations from the spec:

  • It stores mAh rather than Wh, so nights recorded before the voltage is set aren't lost.
  • led_voltage is limited to 5, 12 or 24.
  • "Season" means a calendar year of nights.

Fixed along the way, by root cause:

  • The N+1 settings read in list_schemes, 77.8% of server CPU under load.
  • The Settings page overwrote unsaved edits when its settings load arrived late (#181).
  • A viewer's Settings page re-rendered forever.

Still open:

  • Calibration against a power meter: #179.
  • Unconfirmed: on firmware 0.15+ with the limiter disabled, pwr may read about 100 mA (the ESP's own allowance) rather than 0. It's worth checking during #179.
Done in #180 (squash-merged, CI green). **Delivered:** - **Sampling reuses the watchdog's `/json/info` read.** An `energy_sampler` job takes over when the watchdog is `off`, so exactly one job reads the controller. - **Only lit readings count,** with a closing 0 mA sample when the lights go off. - **Trapezoid integration** with a 3× interval gap cap. - **`energy_daily` in mAh,** so the voltage can be set later. - **The report refuses to invent a voltage.** - **Also:** an `/energy` page and shortcut, the CSV export, the metrics, and migration 0012. **Deviations from the spec:** - It stores mAh rather than Wh, so nights recorded before the voltage is set aren't lost. - `led_voltage` is limited to 5, 12 or 24. - "Season" means a calendar year of nights. **Fixed along the way, by root cause:** - **The N+1 settings read in `list_schemes`,** 77.8% of server CPU under load. - **The Settings page overwrote unsaved edits** when its settings load arrived late (#181). - **A viewer's Settings page re-rendered forever.** **Still open:** - **Calibration against a power meter:** #179. - **Unconfirmed:** on firmware 0.15+ with the limiter disabled, `pwr` may read about 100 mA (the ESP's own allowance) rather than 0. It's worth checking during #179.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/Iris-WLED#153
No description provided.