Skip to main content
Version: 2026.11

Reference cases

Some of what the engine reports is plain arithmetic. Some of it is a modelling choice — a place where more than one answer is defensible, and Power Insight picks one.

Each reference case is a small, deliberately-chosen home: one wiring and a few snapshots of its readings. Every page shows what the engine computes for those readings — every property it publishes, in every layer — so you can see the model at work, and disagree with it, without reading a line of Python.

Every value on these pages comes from the engine. The readings are fixed; the results are recomputed whenever the engine changes, and frozen with each version of these docs. An older version of the docs therefore shows what the engine did at that version, and comparing two versions shows exactly what changed.

Whether the engine's answers are right is checked elsewhere: every modelling decision has a small test worked out by hand, and every property's formula is checked against the engine over hundreds of generated homes. A decision that changes shows up here as moved numbers, and there as a failing test.

The cases​

The cases form a ladder. It starts at a house with one meter in it and adds exactly one device — or flips exactly one configuration flag — per rung, so a diagram is always the previous diagram plus one thing. Read it in order and nothing arrives unexplained.

The last three cases break the one-thing-at-a-time growth deliberately. They are specialists: Hall's condition quantifies over subsets of sinks and cannot be shown with fewer than two sources and two restricted sinks; its mirror image, one sink allowed a group of sources, needs a competitor for that group and a source only the competitor may use; and unequal export permissions mean nothing without two dischargers that differ. They are allowed to be large because what they show cannot be shown in anything smaller.

What each case shows​

RungCaseShows
0Grid only
  • With no local device, the whole gross power is the unmetered home base load.
  • A sink with one available source has a provenance row of exactly one.
  • Marginal and levelized cost agree while the grid is the only source.
  • An unavailable meter collapses everything derived from it to nothing, while a total over an empty device set (no PV, no battery) stays zero.
1PV self-consumption
  • An unrestricted sink's provenance row is the raw source mix.
  • PV standby is a sink drawing from the mix, not negative production.
  • Marginal cost and levelized cost diverge as soon as a local source runs.
  • A source that only draws standby makes the saving rate negative.
2PV export
  • An exporting grid is a sink, not a source with a negative reading.
  • Export compensation is earned by the sources the export was drawn from.
  • Zero gross power guards to zero rather than dividing by zero.
3Metered load
  • A metered consumer gets its own provenance row; the remainder is the home base load.
  • A metered draw larger than what the sources supply is balanced by meeting in the middle: the sources move up, the load moves down, and the base load is exactly zero.
  • A zeroed base load still publishes a share row, of zeros.
4Captive load
  • A restricted sink is served from its allowed sources before anything unrestricted shares them.
  • Serving the captive sink first pushes the unrestricted base load onto the grid.
  • A draw the allowed sources cannot cover is still attributed, and the shortfall is reported as a restriction deficit.
5Battery basics
  • A charging battery is a sink and takes the same raw mix as any other.
  • A discharging battery is a source priced at its flat levelized cost of storage.
  • Its marginal price is zero — the mix it charged on happened earlier, where a snapshot cannot see it.
  • An adapter reading exactly 0 W belongs to neither flow group.
6Captive battery
  • A captive sink is served from its allowed source before flexible sinks share it.
  • When every allowed source is idle the restriction is relaxed as a last resort: the sink is booked for what it actually drew.
  • The unservable draw is reported as a restriction deficit.
7Group captivity
  • Feasibility is a property of groups of sinks, not of single sinks.
  • A flexible sink must not take local power a tight group needs.
  • When restrictions cannot all be honoured, the sink with the fewest permitted alternatives is served first and the deficit falls on the sinks that had somewhere else to go.
8Two PV systems
  • A restriction naming several PV systems is honoured jointly: a load allowed two systems is served from them whenever together they can cover it, even though it needs neither in particular.
  • A sink spreads its draw over the systems it may use in proportion to what each has left, so two equal systems each carry half of it.
9Mixed export house
  • A device that cannot export is excluded from the export mix, even while discharging.
  • Standby draw is routed through the provenance allocation, not by gross share.
  • Two dischargers with different levelized costs price the mix between them.

How to read a chart​

Each snapshot of a case gets its own section on the case page, and its own chart. The chart reads left to right in three columns:

  • Sources — every device delivering power this snapshot. A device is a source or a sink by its reading's sign, so the same grid is a source while importing and a sink while exporting: the columns change between snapshots.
  • Channels — the four things gross power is used for: grid export, home consumption, battery charging and system standby. Every link from a source into a channel is one of that device's sensors, such as Production to grid.
  • Sinks — every device drawing power, plus the home base load (the dashed bar): everything consumed without a sensor on it. It has no device behind it and is derived rather than measured.

Ribbons keep the colour of the source they come from, so the bundle arriving at a sink is that sink's provenance. Their width is watts, always. The switch at the top only changes the labels:

SwitchThe ribbon labels show
WWatts.
% of sourceThe fraction of the source's output — the … ratio sensors.
% of sinkThe fraction of the channel or sink it feeds — the Share of … sensors and the provenance shares.
€/hThe engine's cost rates, read as published. Market and Levelized switch between the two price families; nothing is priced in the browser.

Hover, focus or tap a ribbon or a bar to light up its path and see the Home Assistant sensor that shows it, with the exact fraction next to each figure. A figure marked as derived is not a sensor: the chart computed it from stored values (the home base load has no per-source sensor, for instance).

Some snapshots exist to show the edges:

  • A hatched part of a bar is a reading the other meters do not explain — the metering imbalance. The engine balances the readings, and the ribbons follow its balanced flows.
  • ▲ restriction relaxed marks a sink drawing from a source its configuration rules out, because the readings cannot be met otherwise.
  • When a reading is unavailable, the engine publishes no flows at all, and the chart says so instead of drawing any.

The table under each chart​

TabWhat it lists
Readings and totalsWhat each meter read, and what those readings add up to.
Source × sinkEvery flow from a source to a sink — and which ones the configuration rules out.
Per-source channelsEach source's power into each channel, with its ratio or share.
Every engine valueEverything the engine computed for the snapshot, in the engine's four layers, each with its exact fraction. Hover a name for its definition.

A value shown as unavailable is the engine publishing nothing at all, usually because a reading it needs has dropped out.

How a value gets here​

Each case is a small class in tests/engine/reference/: the wiring, the readings, and the prose you are reading, and nothing else.

class GridOnly(ReferenceCase):
"""One meter and nothing else. ...

Shows:

* With no local device, the whole gross power is the home base load.
"""

case_id = "grid-only"
title = "Grid only"

grid = Grid()

class ImportOnly(Snapshot):
"""The house runs on the grid alone; every watt is base load."""

grid = 1200
price = F(3, 10)

The summary at the top of a case page is the class docstring, the caption on each snapshot's chart is its Snapshot docstring, and every value in the tables is what the engine returns for those readings. A tool passes each snapshot through the engine and writes the results next to these pages; CI fails any change to the engine that moves a published number without re-publishing it, so the numbers here are always the engine's own for this version of the docs.

Open questions​

A snapshot carrying an open question is one where the engine produces an answer but which answer is right has not been settled. Each one is spelled out in its snapshot's section on the case page. If you have a view, the issue tracker is the place for it — that is exactly what publishing these cases is meant to invite.