Recipes#

Copy-paste starting points for common setups. Save any block below as config.toml, then:

breos validate-config config.toml                  # check resolved choices first
breos run --config config.toml --output result.json

Every key works identically as a Python dict passed to App. Valid option keys for locations, modules, cost presets, emissions countries, and load profiles are listed on the packaged options page or via breos list.

PV-only home#

Set battery_kwh = 0 to disable storage. Investment, payback, and NPV then reflect the PV system alone, and battery-specific result keys are omitted:

location = "porto"
n_modules = 10
annual_consumption_kwh = 4000
battery_kwh = 0.0
cost_preset = "residential_pt"
emissions_country = "PT"

PV plus battery#

The packaged quickstart, configs/examples/quickstart.toml:

location = "porto"
n_modules = 10
annual_consumption_kwh = 4000
battery_kwh = 5.0
load_profile = "demandlib_h0"
cost_preset = "residential_pt"
emissions_country = "PT"
projection_years = 20
resolution = "h"

See the quickstart for representative output values.

Custom latitude / longitude / timezone#

Any site works without a packaged preset — pass coordinates and an IANA timezone instead of a location key:

location = { latitude = 48.2082, longitude = 16.3738, timezone = "Europe/Vienna" }
n_modules = 12
annual_consumption_kwh = 4500
battery_kwh = 5.0
cost_preset = "residential_de"
emissions_country = "AT"

Tilt and azimuth are auto-estimated from the latitude when not set. There is no Austrian cost preset yet, so this example borrows the German one — replace it with your own tariffs for real economics.

East-west roof with pv_arrays#

Each array is simulated independently and the DC output is combined before the energy balance, so an east-west layout is not collapsed into one representative orientation. n_modules is derived from the array totals:

location = "porto"
annual_consumption_kwh = 4000
battery_kwh = 5.0
cost_preset = "residential_pt"
emissions_country = "PT"

[[pv_arrays]]
modules = 8
module = "Erlangen_445W"
tilt = 10
azimuth = 90    # east

[[pv_arrays]]
modules = 8
module = "Erlangen_445W"
tilt = 10
azimuth = 270   # west

Anisotropic sky-diffusion model#

The default isotropic transposition underestimates plane-of-array irradiance on clear days. Switch to an anisotropic model — here Perez — to capture circumsolar and horizon brightening. No extra weather inputs are needed; see Sky-diffusion model:

location = "porto"
n_modules = 10
annual_consumption_kwh = 4000
cost_preset = "residential_pt"
emissions_country = "PT"
transposition_model = "perez"
surface_type = "grass"          # or a numeric albedo, e.g. albedo = 0.2

surface_type (or a numeric albedo) sets the ground reflectance that feeds the ground-diffuse component; a snowy or sandy foreground ("snow", "sand") raises annual yield further. Leave both unset to keep pvlib’s 0.25 default.

From the CLI, the equivalent flag is --transposition-model perez (alias --sky-model).

Parameter sweep#

Use breos sweep when you want to run the same scenario over an explicit grid of App config values. The top-level keys define the base scenario; every key under [sweep] replaces the matching top-level key for each run. The command runs the Cartesian product and writes one CSV row per combination:

location = "porto"
n_modules = 10
annual_consumption_kwh = 4000
battery_kwh = 0.0
load_profile = "demandlib_h0"
cost_preset = "residential_pt"
emissions_country = "PT"
projection_years = 20
resolution = "h"

[sweep]
n_modules = [8, 10, 12]
battery_kwh = [0.0, 5.0]
breos sweep --config config.toml --output sweep_results.csv

The output includes the varied parameters (param_* columns), resolved system sizing, the BREOS version, and top-level scalar result metrics such as grid independence, NPV, payback, LCOE, and battery replacement totals. This is explicit enumeration, not an optimizer; use the optimization API for searching over objectives and constraints.

15-minute resolution#

Hourly weather is interpolated to 15-minute steps (Makima), and the bundled H0 profile has a native 15-minute variant. Simulations take correspondingly longer:

location = "porto"
n_modules = 10
annual_consumption_kwh = 4000
battery_kwh = 5.0
resolution = "15min"
cost_preset = "residential_pt"
emissions_country = "PT"

External load profile (E-REDES, BDEW, REE)#

Only the demandlib-derived H0 profile ("1", alias "demandlib_h0") ships with BREOS. For the other standard profiles, download the source CSVs yourself under terms that permit your use, put them in a local directory, and point rlp_directory at it. Load Profile Data lists the exact expected filenames per profile key:

rlp_directory = "external_rlp"
location = "porto"
n_modules = 10
annual_consumption_kwh = 4000
battery_kwh = 5.0
load_profile = "6"   # E-REDES BTN C
resolution = "15min"
cost_preset = "residential_pt"
emissions_country = "PT"

A runnable template also ships in the repository as configs/examples/external-rlp.toml.

Offline runs with cached weather#

When the config uses a location preset key, BREOS scans a weather/ directory in the current working directory before fetching from PVGIS, and silently reuses a file named <location>_tmy_<year0>_<year1>_<source>.csv. Seed the cache once while online:

from pathlib import Path
from breos.weather import fetch_tmy_weather_data

Path("weather").mkdir(exist_ok=True)
tmy, _ = fetch_tmy_weather_data(
    latitude=41.1579,
    longitude=-8.6291,
    timezone="Europe/Lisbon",
)
tmy.to_csv("weather/porto_tmy_2005_2023_pvgis-sarah3.csv")

Subsequent runs from the same working directory work without network access (the log line Found local weather file confirms the cache hit). Custom coordinate-dict locations always fetch; delete or rename the file to force a fresh fetch. The filename’s year and source parts only need to match the pattern — they are metadata, not lookup keys.