Skip to content

Energy Tracking

Track electricity consumed by every print and across the whole lifetime of a printer, then multiply by your kWh rate to get cost. The numbers come straight from a smart plug's energy register — not from estimates.


What It Is

BamDude reads two values from each smart plug:

  1. Live wattage — how many watts the printer is drawing right now.
  2. Lifetime energy counter — total kWh the plug has measured since it was reset.

When a print starts, the lifetime counter is captured on the archive row as energy_start_kwh. When the print finishes, BamDude reads the counter again and stores the delta as energy_kwh. The starting value lives on the archive row, not in memory — so a backend restart mid-print does not lose the baseline, and the delta is still computed when the print completes. (If the print ends during the outage, see "If the print ends while BamDude is down" below.)

Figures recorded before 0.5.3 understate prints started outside BamDude

"At print start" has always been the intent, and for prints BamDude dispatched itself it was also the fact. For a print started from the printer's screen or sent straight from a slicer, the baseline used to be read once the archive row existed — and that row was only created after BamDude had fetched the print's 3MF back off the printer, which on a P1S measured 8m40s. Everything the printer drew in the meantime, bed heating included, was left out. The error was always in the same direction, so it never averaged out. Historical rows are not recalculated; there is nothing to recalculate them from.

For lifetime / date-range views, an hourly background loop snapshots each plug's lifetime counter into smart_plug_energy_snapshots. Date-range totals are then computed as last_snapshot_in_range − last_snapshot_before_range per plug.

Permission Required

Reading energy data requires stats:read. Tracking starts automatically once a smart plug is bound to a printer — there is no separate "enable energy tracking" toggle.


Requirements

Energy tracking needs a smart plug with kWh metering wired between the wall outlet and the printer. The plug type, power monitoring details, and configuration steps are covered in Smart Plugs.

Plug Type kWh Metering Notes
Tasmota Native HTTP energy endpoint
Home Assistant Bind a HA energy sensor entity
REST / Webhook Configure JSON path to extract kWh
MQTT Configure MQTT topic + JSON path

Plugs without an energy register (basic on/off plugs) still work for power control, but their archive rows will have NULL energy_kwh and won't contribute to lifetime totals.


Per-Print kWh

Captured on PrintArchive:

Column Captured When Meaning
energy_start_kwh At print start Plug's lifetime counter at the moment the print began
energy_kwh At print complete (end_counter − energy_start_kwh), the kWh this single print consumed
energy_cost At print complete energy_kwh × cost_per_kwh (denominated in your configured currency)

Restart-resilient. Because energy_start_kwh is persisted to the archive row inside the same transaction that records started_at, a backend crash or container restart mid-print does not lose the baseline — the next on_print_complete will compute the delta correctly.

If the print ends while BamDude is down, there is no on_print_complete to run: the printer finishes alone and BamDude only learns about it on the next start. The startup sweep closes that print and reads the counter then, so the archive still gets a figure — but the meter kept counting through however long the printer sat idle in between, so that idle draw is inside the number. Such archives carry extra_data.energy_is_approximate = true, and the log line says (approximate — recovered print). The alternative was leaving the field empty, which reads as "this print used no power" — further from the truth than a modest over-count.

Failed and cancelled prints still record energy. A 6-hour print that fails at hour 4 still consumed 4 hours of electricity — the delta is still meaningful and is still written.


Lifetime kWh and Date Ranges

The hourly snapshot loop (SmartPlugManager._snapshot_loop) records one row per plug into smart_plug_energy_snapshots. A snapshot is also written at the start of every print, from the same reading that seeds the archive's baseline — so a print's own start is a real boundary in the history rather than whichever hour the loop last happened to fire:

Column Meaning
plug_id FK to the smart plug
recorded_at UTC timestamp of the snapshot
lifetime_kwh Plug's lifetime energy register at that moment

For a date range [date_from, date_to], BamDude computes per plug:

range_total = max(0, last_snapshot_in_range − last_snapshot_before_range)

The max(0, …) clamps to zero when the lifetime counter has been reset (e.g. after a plug factory-reset) so you never get negative energy.

Which day is "today". Dates you pick, and "energy used today", are resolved in your timezone -- the browser tells BamDude which one you are in. Snapshots are stored in UTC, as above, and the day boundary is converted before the query. Work BamDude does on its own schedule -- nightly backups, digests -- keeps using the server's timezone, which is what those should follow. Callers that cannot send a timezone (the Telegram bot, API keys, webhooks) are answered in the server's.


Cost Calculation

Cost is a single-rate calculation against the lifetime / per-print delta:

cost = energy_kwh × energy_cost_per_kwh

Configure the rate in Settings → System → Energy:

Setting Description
energy_cost_per_kwh Your electricity price per kWh (default 0.15)

The numeric rate is dimensionless — display the cost in whatever currency matches your real tariff. BamDude doesn't convert currencies; it just multiplies.


Energy Tracking Mode

Settings → System → Energy → Energy Tracking Mode (energy_tracking_mode):

Mode What "Energy used" Means on Stats
print Sum of per-archive energy_kwh values over the date range. Excludes idle, standby, chamber-only heating. Pure printing cost.
total (default) Lifetime plug counter via snapshot range — last_in_range − baseline_before_range. Includes idle / standby / chamber heating / firmware-update sessions / anything the printer drew while plugged in.

Pick print if you bill customers per job. Pick total if you want to know what your printer farm actually costs to keep running.


"Warming-Up" Indicator

The total mode needs at least one snapshot before the start of your selected range to compute a baseline. On a fresh install, immediately after upgrading to a build that ships snapshot support, or right after Last 7 days is shifted into a window with no prior snapshot, that baseline doesn't exist yet.

When this happens, the Stats page shows a yellow warning icon next to Energy Used and Energy Cost:

Still warming up — at least one plug doesn't have a snapshot from before the start of your range.

The icon disappears as soon as enough snapshots exist. No configuration needed; the system is just collecting data. Backend flag: energy_data_warming_up=True on the stats response.


Tibber / Octopus / Dynamic Tariff Integration

If you're on a dynamic electricity tariff (Tibber, Octopus, Nordpool, …), push the live rate into BamDude from Home Assistant — every cost calculation will then use the current rate instead of a static value.

1. Create an API key

Settings → API Keys → Create, and flip the Update electricity price toggle on the key's row. This is a narrowly-scoped opt-in for POST /settings/electricity-price — it does not grant general settings-write capability (the wider PATCH /settings route is unchanged). Copy the key.

Older docs referenced PATCH /settings

The general PATCH /settings endpoint still works for API keys, but it exposes the entire settings payload (SMTP / LDAP / MQTT credentials, HA token, every UI rendering knob) — a much wider surface than the dynamic-tariff use case needs. The new POST /settings/electricity-price endpoint accepts only {energy_cost_per_kwh}, returns the full settings response so HA can confirm the new value applied, and is gated by the per-key Update electricity price toggle so admins explicitly opt in. Configs pointing at the legacy URL keep working; switch to the narrow URL on your next config refresh.

2. Add a REST command in HA

Add to your configuration.yaml:

rest_command:
  bamdude_electricity_price:
    url: "http://YOUR_BAMDUDE_IP:8000/api/v1/settings/electricity-price"
    method: POST
    headers:
      X-API-Key: "YOUR_API_KEY"
    content_type: "application/json"
    payload: '{"energy_cost_per_kwh": {{ states("sensor.electricity_price") }}}'

3. Trigger the REST command on price change

automation:
  - id: bamdude_push_electricity_price
    alias: "Update BamDude electricity price"
    mode: restart
    trigger:
      - platform: state
        entity_id: sensor.electricity_price
        for: "00:00:05"
    condition:
      - condition: template
        value_template: >
          {{ states('sensor.electricity_price')|float(none) is not none }}
    action:
      - service: rest_command.bamdude_electricity_price
Provider Typical sensor entity
Tibber sensor.tibber_prices (current price attribute)
Octopus Energy sensor.octopus_energy_electricity_current_rate
Nordpool sensor.nordpool_kwh_*

Verify the sensor returns a number

BamDude expects a numeric value for energy_cost_per_kwh. If your sensor returns a string with a currency symbol, adjust the template ({{ states('sensor.x')|float }}) before pushing.

For more on the Home Assistant integration architecture see Smart Plugs → Home Assistant.


Stats-Page Widgets

The Statistics page surfaces energy in three places:

  • Energy used (kWh) for the selected date range, respecting energy_tracking_mode
  • Energy cost in your configured currency
  • Per-printer breakdown so you can see which machine is drawing most

Charts and totals are kept in sync with the print vs total switch — toggling rebuilds them server-side. See Statistics for the full widget tour.


  • Smart Plugs — plug types, configuration, HA / Tasmota / REST / MQTT setup
  • Archiving — energy_kwh / energy_cost fields on each archive row
  • Statistics — energy widget, cost charts, date-range filters
  • Print Queue — auto-power-off after print + smart-plug-driven queue automation
  • Export — CSV/XLSX with per-print energy + cost columns

Tips

Use your real tariff

Pull the all-in rate from your last electricity bill (energy + delivery + taxes + fees). A "headline" rate from your supplier's website usually understates the true cost.

Failed prints still cost

energy_kwh is recorded for failed and cancelled archives too — that's another data point arguing for Failure Analysis and Obico. Every fail is real money on the meter.

Snapshot baselines need uptime

The hourly snapshot loop only runs while BamDude is running. If you stop the container for two days and ask for a 7-day total, the missing 48h shows up as a flat baseline — the warming-up icon will surface this.

Print mode for invoicing, total mode for ROI

Switch to print mode when exporting customer invoices — they shouldn't pay for your standby. Switch to total mode when calculating whether the farm is paying for itself.