Repository navigation
feat(forecast): Open-Meteo + Forecast.Solar weather providers - #87
Conversation
Two new weather providers that give materially better PV-prediction input than the cloud-cover-only sources (met.no, openweather): - open_meteo: free, no key, ECMWF-driven. Returns hourly shortwave_radiation in W/m² alongside cloud cover and temperature. Radiation is a far better PV proxy than cloud fraction — "49 % cloud in the sky" can mean anything from full sun to overcast depending on which part of the sky the Sun is behind. fetchAndStore now derives pv_w_estimated from SolarWm2 × rated/1000 when it's populated, instead of the brittle (1 - cloud)^1.5 curve. - forecast_solar: purpose-built for residential PV. Free tier is 12 req/hour (rolling window) — ample for our 3-hour refresh cadence. Takes site geometry (lat/lon/tilt/azimuth/kWp) and returns site-calibrated watts per timestamp using the EU PVGIS clear-sky model + weather forecast. fetchAndStore uses PVWEstimated directly when present — the RLS twin becomes a thin calibration layer on top of an already-good prediction, not the sole calibration mechanism. Signal selection in fetchAndStore is a simple precedence: PVWEstimated (direct) > SolarWm2 × rated/1000 > cloud-derated prior Config (new fields on Weather): - provider: open_meteo | forecast_solar (plus existing met_no, openweather) - pv_tilt_deg, pv_azimuth_deg: panel geometry for forecast_solar Tests (8 new): - Open-Meteo: happy-path radiation/cloud/temp parsing, null-field handling, non-200 error surfacing. - Forecast.Solar: bucket-to-hour with max-in-hour aggregation, URL geometry verification, 429 rate-limit surfacing, zero-kWp rejection, sortByHour stability. Motivation: operator report 2026-04-17 on homelab-rpi — met.no says 49 % cloud, naive formula predicts 2.1 kW, reality is 8 kW. The twin can only self-correct once it has ~50 samples of the right features; until then, the plan undercommits. Using radiation or direct PV output sidesteps the problem: the conversion is either (a) already done by Forecast.Solar with proper site parameters, or (b) a single calibration factor on top of physics-measured radiation instead of a seven-feature RLS over cloud fraction. Rollout: the switch is per-site via config. No default changed; existing sites stay on met.no until explicitly migrated. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2a2c6a7e19
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| out := make([]RawForecast, 0, len(buckets)) | ||
| for hourMs, watts := range buckets { |
There was a problem hiding this comment.
Emit contiguous hourly rows for Forecast.Solar output
This provider currently returns only the hours that appear in doc.Result.Watts, but Forecast.Solar timestamps are irregular and can omit long spans (commonly overnight). In go/internal/mpc/service.go, lookupPV forward-fills with the previous row between forecast timestamps, so these gaps can carry the last daytime value into night slots and produce materially wrong charge/discharge plans. Please materialize a continuous hourly series (using 0 W for missing hours) before returning rows.
Useful? React with 👍 / 👎.
Direct fix for the operator report on homelab-rpi today: met.no says 49 % cloud, naive PV formula predicts 2.1 kW, reality is 8 kW. The RLS twin needs ~50 samples of matching features to self-correct — meanwhile the MPC undercommits. Using a forecaster that returns radiation or site-calibrated PV output sidesteps the cloud-fraction conversion entirely.
What's new
shortwave_radiation(W/m²),cloud_cover,temperature_2m. 16-day horizon. Radiation is a far better PV proxy than cloud fraction.Signal precedence in
fetchAndStore:No default changed — sites stay on met.no until explicitly migrated via config.
Config
Tests
Test plan
go test ./...green (unit + e2e).weather.provider: forecast_solar, observepv_w_predictedtrack reality across multi-hour slots.Follow-ups (not in this PR)
pvmodelshould drop the (1 - cloud)^1.5 prior when radiation or direct-PV signal is present — the RLS is then a thin calibration on top.EstimatePVWonce no sites use cloud-only providers.🤖 Generated with Claude Code