Skip to content

Add forecast_solar_open_meteo_first to use Open-Meteo as the primary solar source - #4387

Merged
springfall2008 merged 8 commits into
mainfrom
feature/open-meteo-primary
Jul 30, 2026
Merged

Add forecast_solar_open_meteo_first to use Open-Meteo as the primary solar source#4387
springfall2008 merged 8 commits into
mainfrom
feature/open-meteo-primary

Conversation

@springfall2008

Copy link
Copy Markdown
Owner

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 existing forecast_solar configuration entries unchanged.

forecast_solar:
  - latitude: 54.81306
    longitude: -1.38647
    declination: 32
    azimuth: 85
    kwp: 6.44
    api_key: xxxx

forecast_solar_open_meteo_first: true

forecast_solar_open_meteo_backup is untouched in both type and behaviour. When both are set, _first wins.

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:

  • The watts to kWh integration in download_forecast_solar_data() reproduces Forecast.solar's own watt_hours_day to within 0.35%, so nothing is lost in parsing.
  • The caps in pv_calibration() do not clip the planner's data — they apply only to the published pv_estimateCL/10/90 sensor attributes.
  • The site's configuration is correct. Reconstructing the actual generation profile from the logged slot adjustments fits the configured azimuth of 85 (WSW) far better than south or east (SSE 0.00067 vs 0.00586 and 0.01920). Open-Meteo GTI at the same tilt, azimuth and kWp predicted 182.9 kWh across the same seven days against 168.7 kWh actual, confirming the declared 6.44 kWp.

The existing forecast_solar_open_meteo_backup only 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_south the 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.md and docs/install.md. These note one thing worth calling out: while the flag is set, the refresh interval comes from open_meteo_forecast_max_age (default 4 hours), not forecast_solar_max_age (default 8) — so a site that raised forecast_solar_max_age to conserve quota should set the Open-Meteo equivalent instead.

Testing

Seven new tests in apps/predbat/tests/test_solcast.py:

  • Open-Meteo used as primary when the flag is set, with Forecast.solar not called
  • fallback to Forecast.solar when Open-Meteo returns no data
  • existing ordering unchanged when the flag is unset
  • azimuth_zero_south: true survives the config reuse and reaches the Open-Meteo request unconverted
  • source change emits the warning
  • steady state produces no repeated warning
  • a transient fallback produces no source-change warning

Full suite passes: All tests passed (total time: 237.82s).

Out of scope

  • The published pv_estimateCL/10/90 attributes 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.
  • Predbat sends kwp * efficiency to Forecast.solar, which applies its own internal system losses. Possible ~5% double-derate, unverified, affects only the Forecast.solar path.

🤖 Generated with Claude Code

springfall2008 and others added 6 commits July 30, 2026 13:55
…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>
Copilot AI review requested due to automatic review settings July 30, 2026 13:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread apps/predbat/solcast.py
Comment thread docs/install.md Outdated
springfall2008 and others added 2 commits July 30, 2026 15:36
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>
@springfall2008
springfall2008 merged commit 13ed420 into main Jul 30, 2026
2 checks passed
@springfall2008
springfall2008 deleted the feature/open-meteo-primary branch July 30, 2026 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants