energykit.diagnose

One-call financial audit for any smart-meter time series.

energykit.diagnose

One-call energy financial diagnosis.

diagnose() is the showcase function of energykit. Feed it a meter series and get back a complete financial audit — demand charges, forecast value, anomaly costs, battery ROI — printed as a terminal dashboard and returned as a structured DiagnosisReport object.

The “before / after” story

Before energykit:

“I have a 7% MAPE forecast and I spent $25,000 on electricity last year.”

After energykit (one call):

import energykit as ek
report = ek.diagnose(meter_data)
╔══════════════════════════════════════════════════════════════════╗
║    ⚡  ENERGYKIT  |  ENERGY FINANCIAL DIAGNOSIS  ⚡             ║
╠══════════════════════════════════════════════════════════════════╣
║  Period : Jan 2025 → Dec 2025   (8 760 hourly readings)         ║
║  Total  : 26 456 kWh   Avg: 3.02 kW   Peak: 5.86 kW            ║
╠══════════════════════════════════════════════════════════════════╣
║  💡 DEMAND CHARGE RISK                                          ║
║  Peak event : May 14 @ 14:00 → 5.86 kW                         ║
║  Est. annual demand charge : $879  (@$12.50/kW)                 ║
║  Battery [10 kWh / 5 kW]   : save $219/yr  (25%)               ║
╠══════════════════════════════════════════════════════════════════╣
║  🔍 ANOMALY DETECTION                                           ║
║  Anomalies: 23 events  (0.26% of readings)                      ║
║  Estimated waste : 312 kWh  →  $47  over the period             ║
║  Top anomaly : Mar 12 @ 14:00 — spike  +450 kWh   ($68)         ║
╠══════════════════════════════════════════════════════════════════╣
║  🔋 DER OPPORTUNITY  (battery dispatch optimisation)            ║
║  Battery [13.5 kWh / 5 kW] annual savings : $729                ║
║  Estimated payback (@$8 000 install)       : 11.0 yr            ║
╠══════════════════════════════════════════════════════════════════╣
║  📊 TOTAL ADDRESSABLE SAVINGS                                   ║
║  Anomaly correction     :   $47/yr                              ║
║  Demand charge opt.     :  $219/yr  [10 kWh battery]            ║
║  DER dispatch           :  $729/yr  [13.5 kWh]                  ║
║  ──────────────────────────────────────────────────────         ║
║  TOTAL POTENTIAL        :  $995/yr  (25% of spend)              ║
╚══════════════════════════════════════════════════════════════════╝

Usage

>>> import energykit as ek
>>> report = ek.diagnose(meter_data)              # minimal — uses defaults
>>> report = ek.diagnose(                          # full config
...     meter_data,
...     energy_price=0.15,
...     demand_rate=12.50,
...     battery_cost_usd=8_000,
...     currency="USD",
...     silent=False,
... )
>>> report.total_addressable_savings_usd
994.8
class energykit.diagnose.DiagnosisReport(total_kwh: float = 0.0, avg_kw: float = 0.0, peak_kw: float = 0.0, peak_timestamp: Timestamp | None = None, n_readings: int = 0, data_start: str | None = None, data_end: str | None = None, demand_charge_annual_usd: float = 0.0, demand_peak_kw: float = 0.0, demand_peak_timestamp: Timestamp | None = None, demand_best_battery_kwh: float = 0.0, demand_best_battery_savings_usd: float = 0.0, anomaly_count: int = 0, anomaly_rate_pct: float = 0.0, anomaly_waste_kwh: float = 0.0, anomaly_cost_usd: float = 0.0, der_battery_kwh: float = 13.5, der_annual_savings_usd: float = 0.0, der_payback_years: float = inf, total_addressable_savings_usd: float = 0.0, pct_of_spend: float = 0.0, raw: dict = <factory>)[source]

Bases: object

Structured output of diagnose().

total_kwh

Total consumption over the input period.

Type:

float

avg_kw

Average power demand.

Type:

float

peak_kw

Maximum peak power observed.

Type:

float

peak_timestamp
Type:

pd.Timestamp or None

demand_charge_annual_usd

Estimated annual demand charge at the given rate.

Type:

float

demand_peak_kw
Type:

float

demand_peak_timestamp
Type:

pd.Timestamp or None

demand_best_battery_kwh

Battery capacity (kWh) that gives best $/year savings.

Type:

float

demand_best_battery_savings_usd
Type:

float

anomaly_count
Type:

int

anomaly_rate_pct
Type:

float

anomaly_waste_kwh
Type:

float

anomaly_cost_usd

Dollar value of all anomalous energy waste.

Type:

float

der_battery_kwh

Battery size used in the DER dispatch simulation.

Type:

float

der_annual_savings_usd
Type:

float

der_payback_years
Type:

float

total_addressable_savings_usd

Sum of all identified savings opportunities.

Type:

float

pct_of_spend

Savings as a percentage of estimated annual energy spend.

Type:

float

raw

Raw outputs from each sub-module for further analysis.

Type:

dict

anomaly_cost_usd: float = 0.0
anomaly_count: int = 0
anomaly_rate_pct: float = 0.0
anomaly_waste_kwh: float = 0.0
avg_kw: float = 0.0
data_end: str | None = None
data_start: str | None = None
demand_best_battery_kwh: float = 0.0
demand_best_battery_savings_usd: float = 0.0
demand_charge_annual_usd: float = 0.0
demand_peak_kw: float = 0.0
demand_peak_timestamp: Timestamp | None = None
der_annual_savings_usd: float = 0.0
der_battery_kwh: float = 13.5
der_payback_years: float = inf
n_readings: int = 0
pct_of_spend: float = 0.0
peak_kw: float = 0.0
peak_timestamp: Timestamp | None = None
raw: dict
total_addressable_savings_usd: float = 0.0
total_kwh: float = 0.0
energykit.diagnose.diagnose(meter_data: Series, energy_price: float = 0.15, demand_rate: float = 12.5, peak_hours: list | None = None, battery_cost_usd: float = 8000.0, currency: str = '$', silent: bool = False) DiagnosisReport[source]

Run a complete energy financial diagnosis on a meter series.

Parameters:
  • meter_data (pd.Series) – Electricity meter readings (kW or kWh) with a pd.DatetimeIndex. Hourly or 15-minute resolution recommended.

  • energy_price (float, default 0.15) – Retail energy price in $/kWh. Used for anomaly cost estimation and DER savings valuation.

  • demand_rate (float, default 12.50) – Demand charge rate in $/kW/month. A common commercial rate in the US. Set to 0 to skip demand charge analysis.

  • peak_hours (list of int or None) – Hours (0–23) when demand charges apply. None = all hours.

  • battery_cost_usd (float, default 8_000) – All-in installed cost of a residential/small-commercial battery (USD). Used only to compute the payback period estimate.

  • currency (str, default "USD") – Currency symbol for the report. Does not perform conversion.

  • silent (bool, default False) – If True, suppress the printed ASCII dashboard.

Returns:

Structured report with all financials. Access report.raw for the full outputs of each sub-module.

Return type:

DiagnosisReport

Examples

>>> from energykit.datasets import load_synthetic_load
>>> data = load_synthetic_load(periods=8_760, freq="h")["load_kw"]
>>> report = diagnose(data)