You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Status — 2026-09-02. Implemented. #718 (plane-of-array wiring) merged;
open as green drafts based on master: #734 (STRÅNG + source coverage +
vendored MapLibre) · #735 (roof geometry + building picker, now with
catalog-agnostic STAC Basic auth) · #826 (draw your array on the map).
Optional vostok shading (#736) is closed and parked as idea #1048 — the
operator would have to build GPL C++ themselves, which is too much to ask.
This post was rewritten on 2026-09-02 to consolidate the original proposal
and its three update comments into one text; implementation details live in
the PR bodies.
Summary
Two Swedish open-data sources sharpen FTW's PV modeling:
SMHI STRÅNG — modelled solar irradiance
(hourly, ~2.5 km, 1999→present, CC BY 4.0, no key), used to score how real
panels actually performed against a weather-expected baseline and to
calibrate the forward PV predictor.
Lantmäteriet open geodata — building
footprints + LiDAR, used to derive roof tilt/azimuth/rated W automatically —
plus a map-drawing fallback that needs no account at all.
Everything is additive and optional; nothing changes the control tick,
dispatch, or the optimizer contract.
The finding that shaped the design
STRÅNG is an analysis product with no forward horizon — it is historical
truth, not a forecast. So it scores and calibrates; forward forecasting stays
on the existing providers. Its parameter set was probed against the live API
(data for exactly codes 116–122; the measured table and the two checks that
pin the identification are in #734). It publishes no cloud cover, but sunshine
duration derives it as 1 − minutes/60, with an explicit unknown when the
sun is too low for the number to mean anything.
Its domain was probed too, and the grid is rotated relative to lat/lon, so the
declared coverage box is honestly advisory: covers: false is definitive, covers: true means "worth asking". The same logic handles Sweden's diagonal
border for Lantmäteriet — the box admits Oslo, and the STAC search returning no
tiles is the authority, not geometry.
roofmodel/ optional module: pick your building → clip LiDAR to its footprint → RANSAC/DBSCAN segmentation → pre-filled pv_arrays. Credentials are the operator's own Geotorget account (HTTP Basic — Lantmäteriet provides no OAuth for the STAC download APIs), and the client is catalog-agnostic: stac_base_url + collection keys point it at any STAC catalog
Per-face shading factors via vostok — parked as an idea
idea issue
Decisions worth recording (and two corrections)
Picking a building is a correctness fix, not a nicety. RANSAC fits infinite planes: a south roof is z = f(y) with no x term, so any second
building sharing pitch and ridge orientation lies on the same plane — measured
as byte-identical contamination at every separation from 3 m to 40 m
(distance-invariance is the signature of a global fit). Clipping the cloud to
the picked footprint restores the isolated segmentation exactly. The honest
caveats: in one synthetic scene the contaminated area was coincidentally
closer to truth, and the clipped pipeline systematically under-reads area
(~−12 % at 8 pts/m², worse at Laserdata Skog's real 1–2 pts/m²) because DBSCAN
drops boundary points — both reasons a derived rated W is a proposal, never
a quote.
Derived arrays fill the editor, not the config. A successful derive puts
real numbers in the form with the 3D preview updating, then stops at "Review
them and press Save". Config never changes behind the operator's back, but the
proposal lands where it can be seen and edited. (The original text promised
fully automatic writes; this is the better shape.)
Ingest matches what Lantmäteriet actually publishes. Byggnad-vektor
delivers GeoPackage, Laserdata-skog delivers LAZ organised as COPC; assets are
selected by declared media type, not key names. GeoPackage is decoded with
~100 lines of sqlite3 + struct against the published OGC layouts rather
than a GDAL dependency, and COPC's octree index turns "which building" into a
kilobytes-sized range request instead of a hundreds-of-MB tile — the difference
between a derive being feasible on a Pi and not. (An earlier claim here that
GeoJSON assets were already handled was wrong; both paths now exist and are
tested.)
A roofmodel (Python) CI job now exists. The module's suite was invisible
upstream (only optimizer/tests ran); wiring it in immediately caught two
shell-quoting bugs that Windows was hiding.
The GPL boundary for vostok (now in #1048): separate process, files and a
command line, never bundled, never auto-installed; absent vostok, shading_factor is omitted, never defaulted to 1.0 — "we did not look" and
"we looked and it is clear" are different claims.
The original open questions, answered
Third optional module? Yes — roofmodel/ mirrors the optimizer:
arm's-length subprocess, one versioned roof_model.json, safe-absent.
MapLibre: CDN or vendored?Vendored (web/vendor/maplibre/, web/vendor/terra-draw/), per the ship-it-on-the-box policy fix(web): escape loadpoint HTML and ship Leaflet on the box #910
established after this RFC opened. Byte-identity to the npm artifacts is
verified; nothing loads from a CDN.
A live derive against Lantmäteriet's real service with an operator's own
Geotorget credentials (Byggnad-vektor + Laserdata-skog ordered on the
account). Every layer is tested against fakes and synthetic tiles, and the
HTTP/STAC layer against a local server speaking the real formats — the one
thing that has never run is the production endpoint end-to-end.
Attribution: SMHI STRÅNG and Lantmäteriet data are licensed CC BY 4.0.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary
Two Swedish open-data sources sharpen FTW's PV modeling:
(hourly, ~2.5 km, 1999→present, CC BY 4.0, no key), used to score how real
panels actually performed against a weather-expected baseline and to
calibrate the forward PV predictor.
footprints + LiDAR, used to derive roof tilt/azimuth/rated W automatically —
plus a map-drawing fallback that needs no account at all.
Everything is additive and optional; nothing changes the control tick,
dispatch, or the optimizer contract.
The finding that shaped the design
STRÅNG is an analysis product with no forward horizon — it is historical
truth, not a forecast. So it scores and calibrates; forward forecasting stays
on the existing providers. Its parameter set was probed against the live API
(data for exactly codes 116–122; the measured table and the two checks that
pin the identification are in #734). It publishes no cloud cover, but sunshine
duration derives it as
1 − minutes/60, with an explicit unknown when thesun is too low for the number to mean anything.
Its domain was probed too, and the grid is rotated relative to lat/lon, so the
declared coverage box is honestly advisory:
covers: falseis definitive,covers: truemeans "worth asking". The same logic handles Sweden's diagonalborder for Lantmäteriet — the box admits Oslo, and the STAC search returning no
tiles is the authority, not geometry.
The pieces
GET /api/data-sourcescoverage registry (answers part of #726),mpc.PVBand, Leaflet → vendored MapLibre GL 6roofmodel/optional module: pick your building → clip LiDAR to its footprint → RANSAC/DBSCAN segmentation → pre-filledpv_arrays. Credentials are the operator's own Geotorget account (HTTP Basic — Lantmäteriet provides no OAuth for the STAC download APIs), and the client is catalog-agnostic:stac_base_url+ collection keys point it at any STAC catalogDecisions worth recording (and two corrections)
Picking a building is a correctness fix, not a nicety. RANSAC fits
infinite planes: a south roof is
z = f(y)with noxterm, so any secondbuilding sharing pitch and ridge orientation lies on the same plane — measured
as byte-identical contamination at every separation from 3 m to 40 m
(distance-invariance is the signature of a global fit). Clipping the cloud to
the picked footprint restores the isolated segmentation exactly. The honest
caveats: in one synthetic scene the contaminated area was coincidentally
closer to truth, and the clipped pipeline systematically under-reads area
(~−12 % at 8 pts/m², worse at Laserdata Skog's real 1–2 pts/m²) because DBSCAN
drops boundary points — both reasons a derived rated W is a proposal, never
a quote.
Derived arrays fill the editor, not the config. A successful derive puts
real numbers in the form with the 3D preview updating, then stops at "Review
them and press Save". Config never changes behind the operator's back, but the
proposal lands where it can be seen and edited. (The original text promised
fully automatic writes; this is the better shape.)
Ingest matches what Lantmäteriet actually publishes. Byggnad-vektor
delivers GeoPackage, Laserdata-skog delivers LAZ organised as COPC; assets are
selected by declared media type, not key names. GeoPackage is decoded with
~100 lines of
sqlite3+structagainst the published OGC layouts ratherthan a GDAL dependency, and COPC's octree index turns "which building" into a
kilobytes-sized range request instead of a hundreds-of-MB tile — the difference
between a derive being feasible on a Pi and not. (An earlier claim here that
GeoJSON assets were already handled was wrong; both paths now exist and are
tested.)
A
roofmodel (Python)CI job now exists. The module's suite was invisibleupstream (only
optimizer/testsran); wiring it in immediately caught twoshell-quoting bugs that Windows was hiding.
The GPL boundary for vostok (now in #1048): separate process, files and a
command line, never bundled, never auto-installed; absent vostok,
shading_factoris omitted, never defaulted to 1.0 — "we did not look" and"we looked and it is clear" are different claims.
The original open questions, answered
roofmodel/mirrors the optimizer:arm's-length subprocess, one versioned
roof_model.json, safe-absent.web/vendor/maplibre/,web/vendor/terra-draw/), per the ship-it-on-the-box policy fix(web): escape loadpoint HTML and ship Leaflet on the box #910established after this RFC opened. Byte-identity to the npm artifacts is
verified; nothing loads from a CDN.
improved every radiation provider with no new surface.
irradiance_historytable? Yes;forecastsstays forward-only.Still needed
A live derive against Lantmäteriet's real service with an operator's own
Geotorget credentials (Byggnad-vektor + Laserdata-skog ordered on the
account). Every layer is tested against fakes and synthetic tiles, and the
HTTP/STAC layer against a local server speaking the real formats — the one
thing that has never run is the production endpoint end-to-end.
Attribution: SMHI STRÅNG and Lantmäteriet data are licensed CC BY 4.0.
All reactions