System map / Engine / Hourly energy balance

Engine · hourly energy balance

The hourly energy balance: solar, battery and the time-of-use bill

Monthly totals can't tell you whether noon sunshine covers a 7 pm dinner, or what a battery is worth. For that the engine zooms in on one representative day per month: the home's electric load and the solar output hour by hour, a battery in between, and the grid covering the rest, priced on your time-of-use tariff.

Resolution
24 clock hours × 12 months, × days in month
Battery
2 modes, cheaper one chosen each month
Export credit
NEM 3.0: hourly avoided cost (ACC)
Runs for
Your journey, from the solar install year

The flow

data flowcontrol: run both modes, keep the cheaper

Run it: one day in your month

This is the model's dispatch algorithm (src/dispatch.py, ported line for line) running in your browser on an illustrative all-electric home: heat pump, heat-pump water heater, induction, heat-pump dryer, lights, and optionally an EV. It uses your zone's real climate, NREL load shapes, PVWatts sun and PG&E's default time-of-use plan (E-TOU-C).

Bill · no solar
this month
Solar only
Solar + battery
Grid at peak
of the month's grid kWh

Where the home's electricity comes from, each hour

solar → homebattery → homegrid → home (off-peak)grid → home (peak)grid → battery— home load

Where the sunshine goes, and the battery's charge

solar → homesolar → batteryexported— battery charge (kWh, right axis)
Mode 1

Self-powered

Solar serves the home first; any surplus charges the battery, then exports. The battery covers any shortfall, at any hour, until it's empty. Then the grid.

Mode 2

Cost-saving

Keeps just enough charge (the reserve) to cover the 4–9 pm peak, and discharges only then. If solar leaves it short and grid power is cheap enough (efficiency × peak price > off-peak price), it tops up from the grid in the hours before the peak.

Illustrative home: 1,800 sq ft, average insulation, 3 bedrooms, the app's default appliance settings (lights & plugs 1,910 kWh/yr; EV 12,000 mi, 85% charged at home), 2026 tariff (no escalation). Month bill = tiered TOU energy + $0.79/day fixed − export credit.

Energy is conserved, every hour

Each mode's result satisfies these balances exactly (the model's tests check them), and the check line above recomputes them live. The day is run repeatedly until the battery ends the day at the same charge it started with (steady state), so no energy comes from an arbitrary starting charge. Round-trip losses are split evenly between charging and discharging (√η each way).

solar G = solar→home + solar→battery + export load L = solar→home + battery→home + grid→home grid = grid→home + grid→battery battery (solar→battery + grid→battery) × η = battery→home (steady state)

From one day to a year's saving

Each month's day is multiplied by the days in the month. The saving is the month's bill without solar or battery, minus the bill with them (which already subtracts the export credit), summed over 12 months. The year's total saving is capped at that year's electric bill, like an annual NEM true-up: summer credits can offset winter, but a year can't go below zero. That saving is subtracted from your journey's energy cost for the year (see the year loop).

What's modeled, what's simplified

  • Real hourly shapes for load (NREL, per zone and month) and sun (PVWatts), on one shared clock with the tariff.
  • Real tariff structure: tiers on the home total, the peak window and the fixed charge.
  • Two standard battery settings, the ones home batteries ship with; the cheaper one is chosen each month.
  • NEM 3.0 export value by hour and calendar year from the CPUC avoided-cost calculator.
  • One average day per month: no cloudy streaks or heat waves, so battery value on extreme days is averaged away.
  • Perfect foresight within the day: Cost-saving mode knows the day's load and sun when it sets its reserve.
  • No battery wear or capacity loss over the years, and no backup-power value.
  • No demand charges, and the ACC "plus" adder for early NEM 3.0 customers isn't included.
Code
src/dispatch.py · run_day · dispatch_month · month_billsrc/journey.py · JourneyHome.step (solar block) src/urdb_rates.py · price_monthsrc/nbt_export.pydata/rates/nbt_export_acc.json src/battery_defaults.pytests/test_battery.py