Add forecast_solar_open_meteo_first to use Open-Meteo as the primary solar source - #4387
Merged
Conversation
…llback Adds a design for forecast_solar_open_meteo_first, a single boolean that reverses the existing source order so a site can be evaluated on Open-Meteo without restructuring its forecast_solar configuration. Motivated by a customer investigation which found Forecast.solar carried a consistent 1.33x low bias for that site, while ruling out Predbat-side causes: the watts to kWh integration matches Forecast.solar's own watt_hours_day to within 0.35%, the calibration caps do not clip the planner's data, and the site's azimuth and kWp were both confirmed correct. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three tasks: add the setting and reverse the source order with four tests, warn on active source change with one test, and document the setting in apps-yaml.md and install.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
log_source_change was called with the source actually used this cycle rather than the configured primary, so a one-off Forecast.solar/Open-Meteo fallback (e.g. a rate-limit blip) produced a pair of misleading "source changed" warnings and polluted the web UI Warnings tab. It was also called unconditionally, persisting a source even on cycles where no data was fetched at all. - Track configured_source (user intent) instead of active_source, and only call log_source_change when pv_forecast_data is non-empty. - Guard log_source_change against a falsy source so a future branch that leaves it unset can't suppress the next real warning. - Correct apps-yaml.md/install.md: forecast_solar_max_age does not apply while forecast_solar_open_meteo_first is set (the refresh interval comes from open_meteo_forecast_max_age instead), move the install.md paragraph below the YAML example it was floating above, use a descriptive anchor link, and note that forecast_solar_open_meteo_backup is a no-op once forecast_solar_open_meteo_first is set. - Add tests pinning steady-state silence across repeated cycles and no warning on a same-cycle transient fallback. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new configuration flag to prefer Open-Meteo for PV forecasting while preserving the existing Forecast.solar configuration shape and keeping the Open-Meteo “backup” behavior intact. This supports evaluating Open-Meteo as a primary source without restructuring per-array config, and introduces a persisted “source change” warning to set expectations around PV calibration settling time.
Changes:
- Introduces
forecast_solar_open_meteo_first(bool) to make Open-Meteo the primary PV forecast source with Forecast.solar as fallback. - Persists/logs a warning when the configured forecast source changes to highlight the PV calibration settling window.
- Adds/extends documentation and expands the solcast test suite to cover the new ordering, azimuth handling, and warning behavior.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/superpowers/specs/2026-07-30-open-meteo-primary-source-design.md | Design spec describing the new flag, ordering, and calibration warning rationale. |
| docs/superpowers/plans/2026-07-30-open-meteo-primary-source.md | Implementation plan and test plan for the feature. |
| docs/install.md | Documents the new flag and clarifies refresh interval behavior under the flag. |
| docs/apps-yaml.md | Documents the new flag, ordering semantics, max-age note, and calibration warning behavior. |
| apps/predbat/tests/test_solcast.py | Adds new integration-style tests validating ordering, fallback, azimuth convention, and source-change warning semantics. |
| apps/predbat/solcast.py | Implements the new ordering flag and adds persisted source-change warning support. |
| apps/predbat/config.py | Adds schema entry for forecast_solar_open_meteo_first. |
| apps/predbat/components.py | Wires the new config option into the Solar component argument mapping. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
forecast_solar_open_meteo_first, a single boolean that reverses the solar forecast source order: Open-Meteo becomes primary and Forecast.solar becomes the fallback, reusing the existingforecast_solarconfiguration entries unchanged.forecast_solar_open_meteo_backupis untouched in both type and behaviour. When both are set,_firstwins.Motivation
Investigating a customer report of consistently under-reported solar found Forecast.solar carrying a ~33% low bias for that site: 127.2 kWh forecast against 168.7 kWh actually generated over seven days, low on seven days out of seven.
Predbat-side causes were ruled out first:
wattsto kWh integration indownload_forecast_solar_data()reproduces Forecast.solar's ownwatt_hours_dayto within 0.35%, so nothing is lost in parsing.pv_calibration()do not clip the planner's data — they apply only to the publishedpv_estimateCL/10/90sensor attributes.The existing
forecast_solar_open_meteo_backuponly fires when Forecast.solar returns no data, so a biased-but-successful response never triggers it. This flag makes it possible to evaluate Open-Meteo on a site without restructuring its configuration.Note on cost: the Open-Meteo path uses the Ensemble API for P10, which is available on the free tier (rate limited), so evaluating a small number of sites needs no paid plan.
Behaviour
While Open-Meteo succeeds, Forecast.solar is not called at all, so no Forecast.solar quota is consumed. Config reuse needs no translation because both download paths read the same keys with identical defaults and apply
azimuth_zero_souththe same way.Also adds a warning when the configured forecast source changes, because PV calibration compares seven days of recorded forecasts against actual generation and that history is source-specific — the scaling factor takes up to seven days to settle after a switch. The warning deliberately tracks configured intent rather than the source a fallback happened to land on, so a transient Forecast.solar outage does not produce a misleading "calibration will settle over the next 7 days" message.
Documentation
docs/apps-yaml.mdanddocs/install.md. These note one thing worth calling out: while the flag is set, the refresh interval comes fromopen_meteo_forecast_max_age(default 4 hours), notforecast_solar_max_age(default 8) — so a site that raisedforecast_solar_max_ageto conserve quota should set the Open-Meteo equivalent instead.Testing
Seven new tests in
apps/predbat/tests/test_solcast.py:azimuth_zero_south: truesurvives the config reuse and reaches the Open-Meteo request unconvertedFull suite passes:
All tests passed (total time: 237.82s).Out of scope
pv_estimateCL/10/90attributes are capped to nameplate/observed peak while the planner's data is not. Worth fixing separately — it is the most likely explanation for a user reporting a forecast apparently pinned near a fixed ceiling.kwp * efficiencyto Forecast.solar, which applies its own internal system losses. Possible ~5% double-derate, unverified, affects only the Forecast.solar path.🤖 Generated with Claude Code