plant/2¶
A plant's topology and parameters as plain data: what PlantConfig.from_mapping
reads and PlantConfig.to_mapping writes back exactly. The microgrid command reads it
from TOML (plant.toml); a Python client may build the mapping from anything. It is
the only plant schema. Describe your plant shows how to
write one for each topology.
Validation names every problem with its path (battery.capacity_kwh: must be
positive), all of them at once: each field's and each part's first, then the rules
across parts once the parts are sound. microgrid config check prints them. A key
given as null is a key left out; a key the schema does not have is an error.
Units: power kW, energy kWh, SOC a fraction 0-1, wear in the prices' currency per
kWh (Currency).
Times of day are local, in the plant's zone, written "HH:MM:SS" without an offset.
The top level¶
| Key | Required | Meaning |
|---|---|---|
schema |
yes | "plant/2" |
timezone |
yes | the plant's zone, an IANA name ("Europe/Berlin"); windows are local times in it |
pv |
no | a list of arrays; none: a plant without PV |
battery |
no | the battery and where it connects; none: a plant without one |
hybrid |
no | the hybrid inverter, where the plant has a DC bus |
grid |
no | the grid connection's limits |
loads |
no | the loads by connection point; default one AC load, house |
dispatch |
no | what the plant does on its own beyond self-consumption |
meters |
no | the meters the plant reads; default the set below |
[[pv]]: an array¶
| Key | Default | Meaning |
|---|---|---|
name |
required | the array's name; unique, and not a load's |
coupling |
required | "ac": its own inverters (micro-inverters, a string inverter) on the AC bus; "dc": strings on a hybrid's DC bus |
dc_rating_kw |
none | the MPPT limit, DC kW: it caps the array's DC power |
ac_rating_kw |
none | an AC-coupled array's own inverter's rating, AC kW; a DC-coupled array has none |
An array's forecast is in its coupling's terms: AC kW for an AC-coupled array, DC kW for
a DC-coupled one. A DC-coupled array needs a hybrid.
[battery]¶
The battery's parameters and its connection, in one table.
| Key | Default | Meaning |
|---|---|---|
capacity_kwh |
required | usable capacity, stored kWh |
charge_kw |
required | the charge limit, kW |
discharge_kw |
required | the discharge limit, kW |
eta_charge |
0.94 | AC to stored, at low power; in (0.5, 1] |
eta_discharge |
0.94 | stored to AC, at low power; in (0.5, 1] |
reserve_soc |
0.0 | the floor the plant keeps (a backup reserve) |
saturation_soc |
1.0 | where charging counts as full (a BMS that tapers near the top) |
wear_charge_per_kwh |
0.0 | the battery's wear per AC kWh charged; 0 prices cycling as free, so set it (how to estimate) |
wear_discharge_per_kwh |
0.0 | the battery's wear per AC kWh discharged |
loss_charge_per_kw |
0.0 | how the conversion's loss grows with power, charging: kW of loss per (DC kW)², so its unit is 1/kW. At 0.003, charging at 4 kW DC loses 0.003 × 16 = 0.048 kW more than the low-power efficiency says |
loss_discharge_per_kw |
0.0 | the same, discharging |
meter_charge |
1.0 | stored kWh per kWh the battery's meter reads charging; in (0.5, 1.5] |
meter_discharge |
1.0 | stored kWh drawn per kWh the meter reads discharging; in (0.5, 1.5] |
connection |
required | "ac": on the AC bus behind its own inverter; "dc_bus": on a hybrid's DC bus |
form |
"folded" |
on a DC bus: "folded", its conversion one path from the AC bus to stored energy, metered at the DC bus; "split", its conversion the DC bus to stored energy alone, with the hybrid's conversion from the DC bus to AC |
inverter |
none | a battery on the AC bus: its own inverter ([battery.inverter], below), required there |
dc_charge_kw, dc_discharge_kw |
none | a battery on a DC bus: its own DC limits; a folded battery with anything else on its bus needs them |
0 <= reserve_soc < saturation_soc <= 1. With the defaults (no loss growth, a meter
that reads stored energy) the conversion is one efficiency each way.
microgrid fit-battery fits the efficiencies, the loss growth, the meter factors and
the inverter's draws from the meters.
[hybrid] and [battery.inverter]: an inverter¶
| Key | Default | Meaning |
|---|---|---|
ac_rating_kw |
none | its AC rating, on the net power crossing it |
standby_kw |
0.0 | its own draw, always |
working_kw |
0.0 | its extra draw while the battery works through it |
working_threshold_kw |
0.05 | the battery works above this, kW either way |
conversion |
none | the hybrid's DC bus to AC ([hybrid.conversion]): required where no folded battery holds it, refused where one does; never on a battery's own inverter |
[hybrid.conversion]:
| Key | Default | Meaning |
|---|---|---|
eta_in |
required | AC to DC bus, at low power; in (0, 1] |
eta_out |
required | DC bus to AC, at low power; in (0, 1] |
loss_in_per_kw, loss_out_per_kw |
0.0 | loss growth each way, kW of loss per (DC kW)² (unit 1/kW) |
A folded battery with anything else on its DC bus (DC PV, a DC load) needs the hybrid's
ac_rating_kw and its own dc_charge_kw and dc_discharge_kw, and must not store
more per DC kWh than it draws (meter_charge <= meter_discharge).
[grid]¶
| Key | Default | Meaning |
|---|---|---|
import_limit_kw |
none | the most the site can import |
export_limit_kw |
none | the most it may export; 0: it may not export |
[[loads]]¶
| Key | Default | Meaning |
|---|---|---|
name |
required | the load's name, unique |
connection |
"ac" |
"ac", or "dc_bus": on a hybrid's DC bus |
At least one load is on the AC bus: the house. A DC-bus load needs a hybrid. The load
forecast owns every load's kW; the plant only says where each connects. The names are
labels: the engine takes the loads by connection point, all the AC loads' forecast as
one series (Inputs.load) and the DC-bus loads' as another (Inputs.dc_load), never by
name (the plant model knows connection points, not load names). A name is
checked unique and read by nothing else; it says, for a reader of the file, which load
is which.
[dispatch]¶
| Key | Default | Meaning |
|---|---|---|
grid_charge |
none | the grid-charge windows (below) |
export_windows |
none | the battery-export windows (below) |
charge_order |
"pv_first" |
in a grid-charge window, "pv_first": the grid tops up only what the PV still to come in the window will not; "target_first": the grid tops up as the target needs, not counting that PV. PV still charges first within a slot either way |
hold_rules |
none | when the plant holds its battery through a DC-bus load's session (below) |
[[dispatch.grid_charge]]: a grid-charge window¶
Inside the window the grid tops the battery up to a target that PV alone would not
reach by end.
| Key | Default | Meaning |
|---|---|---|
start, end |
required | local times; the window lies within one local day (start before end) |
target_soc |
1.0 | the target; above the battery's reserve |
cover_until |
none | a target from need: what the house will draw from end until this time (net of PV and of discharge losses), when that is lower than target_soc; at or before end means the next day; not inside the window |
timing |
"early" |
"early": from the window's start, as soon as PV will fall short; "late": only what the rest of the window could no longer add at the charge limit, so the top-up comes as late as it can |
No two windows overlap, grid-charge or export.
[[dispatch.export_windows]]: a battery-export window¶
The plant discharging the battery to the grid.
| Key | Default | Meaning |
|---|---|---|
start, end |
required | local times, within one day |
power_kw |
required | AC kW, held through the window; within the battery's discharge limit, its inverter's rating and the grid's export limit |
floor_soc |
required | the window stops at this SOC, at or above the reserve and below saturation |
yields |
"pv" |
which yields at the export limit: "pv" or "battery" |
[[dispatch.hold_rules]]: holding through a DC-bus load's session¶
While the DC-bus loads draw more than dc_load_above_kw, a session that starts with the
SOC below start_below_soc keeps the battery from discharging until it ends.
| Key | Meaning |
|---|---|
dc_load_above_kw |
a session is the DC-bus loads drawing more than this, DC kW |
start_below_soc |
the SOC a session must start below to hold the battery; above the reserve |
A hold rule needs a battery and a DC-bus load.
[[meters]]¶
The meters the plant reads, each by name. A live reading and a dataset key each meter's kW by its name.
| Key | Default | Meaning |
|---|---|---|
name |
required | unique |
measures |
required | "pv", "grid", "battery", "consumption" or "dc_load". consumption is the AC loads and the inverters' draw, metered in place of the grid; it is not the dataset's house load |
array |
none | a PV meter: the array it meters; none: every array together (only where they share one coupling) |
at |
none | a battery meter: "dc" (its DC side, the default) or "ac" (its own inverter's AC side, for a battery on the AC bus only). fit-battery reads the battery's meter as DC |
sign |
1 | 1 where positive is PV made, importing, charging or drawing; -1 where it is the opposite |
The set must close the plant's balance: the grid or the consumption metered (one gives the other), the battery where there is one, the DC-bus loads where there are any, and every array's PV, each or together.
The default set, without meters: pv for every array together (with arrays of
both couplings, one per array named pv:<array>, which a dataset cannot name:
name them yourself to record them), grid, battery at its DC
side where there is a battery, and dc_load where a load is on the DC bus, each with
sign 1.
Examples¶
The library ships four example plants (microgrid.plant.examples), each with
synthetic, round parameters fitted to no real plant.
schema = "plant/2"
timezone = "Europe/Berlin"
[[pv]]
name = "roof"
coupling = "ac"
[battery]
capacity_kwh = 12.0
charge_kw = 6.0
discharge_kw = 6.0
eta_charge = 0.96
eta_discharge = 0.96
reserve_soc = 0.1
wear_charge_per_kwh = 0.02
wear_discharge_per_kwh = 0.02
loss_charge_per_kw = 0.003
loss_discharge_per_kw = 0.003
meter_charge = 0.99
meter_discharge = 1.0
connection = "dc_bus"
form = "folded"
[hybrid]
standby_kw = 0.03
working_kw = 0.06
[[dispatch.grid_charge]]
start = "01:00:00"
end = "05:00:00"
target_soc = 0.6
timing = "late"
schema = "plant/2"
timezone = "Europe/Berlin"
[[pv]]
name = "strings"
coupling = "dc"
dc_rating_kw = 8.0
[battery]
capacity_kwh = 10.0
charge_kw = 5.0
discharge_kw = 5.0
eta_charge = 0.98
eta_discharge = 0.98
reserve_soc = 0.1
wear_charge_per_kwh = 0.02
wear_discharge_per_kwh = 0.02
connection = "dc_bus"
form = "split"
[hybrid]
ac_rating_kw = 6.0
standby_kw = 0.03
working_kw = 0.04
[hybrid.conversion]
eta_in = 0.97
eta_out = 0.97
loss_in_per_kw = 0.002
loss_out_per_kw = 0.002
[grid]
export_limit_kw = 5.0
[[dispatch.grid_charge]]
start = "02:00:00"
end = "05:00:00"
target_soc = 0.5
schema = "plant/2"
timezone = "Europe/Berlin"
[battery]
capacity_kwh = 13.5
charge_kw = 5.0
discharge_kw = 5.0
eta_charge = 0.95
eta_discharge = 0.95
reserve_soc = 0.2
wear_charge_per_kwh = 0.03
wear_discharge_per_kwh = 0.03
connection = "ac"
[battery.inverter]
ac_rating_kw = 5.0
standby_kw = 0.03
working_kw = 0.03
[[dispatch.grid_charge]]
start = "00:00:00"
end = "05:00:00"
target_soc = 0.9
[[dispatch.export_windows]]
start = "17:00:00"
end = "20:00:00"
power_kw = 3.0
floor_soc = 0.3