Skip to content

Add independent FORECAST_WEATHER_PROVIDER for rain restriction and /weatherData forecast - #184

Open
smeisens wants to merge 7 commits into
OpenSprinkler:masterfrom
smeisens:master
Open

smeisens wants to merge 7 commits into
OpenSprinkler:masterfrom
smeisens:master

Conversation

@smeisens

@smeisens smeisens commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds an optional, independent FORECAST_WEATHER_PROVIDER for the rain-forecast
weather restriction and the /weatherData forecast display, decoupled from the
main WEATHER_PROVIDER used for the Zimmerman/ETo scale calculation.

No behavior change unless explicitly configured: if FORECAST_WEATHER_PROVIDER
is not set, the forecast comes from the same provider as before (the main provider
resolved for that request, including per-controller overrides).

Motivation

Local PWS setups (WEATHER_PROVIDER=local) intentionally return an empty forecast
array and precip: undefined, because a weather station has no forecast capability.
As a result, the "rain forecasted in the next N days" restriction is silently
inactive and /weatherData shows "Forecasted Rain: NaN mm" for these users.

This PR lets them keep local station data for the scale calculation while taking
only the forecast from an online provider. See #183.

Changes

  • New optional env var FORECAST_WEATHER_PROVIDER, resolved per request via
    resolveForecastProvider(weatherProvider). It falls back to the already-resolved
    main provider (not process.env.WEATHER_PROVIDER), so adjustmentOptions.provider
    overrides are respected.
  • checkWeatherRestriction: the rain-forecast check uses the forecast provider;
    the minTemp and California restrictions are unchanged and keep using the main provider.
  • getWeatherData (/weatherData): forecast, precip, minTemp and maxTemp
    are sourced from the forecast provider; all other fields still come from the main provider.
  • /weatherData reports the provider that actually supplied the forecast
    (weatherProvider), so the API response is accurate for attribution.
  • Both forecast fetches are fail-open and independent of the main fetch: a
    failure logs an error and leaves only the affected feature inactive. It never
    blocks the watering-scale response.
  • No new provider class: the existing WEATHER_PROVIDERS map is reused.
  • Documented in docs/configuration.md and .env.example.
  • Version bumped to 3.2.0-beta02.

Attribution

The official App currently derives the forecast attribution text from
controller.settings.wto.provider (the main provider), not from the provider
info returned by the service. With a local main provider and a separate
forecast provider, the App would show "Powered by your Local PWS". This can
suppress attribution required by commercial providers.

Review feedback addressed

  • Default no longer hardcoded to OpenMeteo; falls back to the main provider (@symposion)
  • Attribution gap: accurate provider info in the API, documented warning, App PR #306 (@symposion)

Related

Testing

  • npm test: unit tests cover resolveForecastProvider (including a regression
    test for a non-OpenMeteo main provider without FORECAST_WEATHER_PROVIDER set),
    mergeForecastWeatherData (including the reported provider) and the fail-open paths.
  • The failing Docker push/tag checks are expected for fork PRs, since registry
    secrets are not exposed. The amd64/arm64 build steps pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

smeisens and others added 5 commits August 27, 2026 12:40
…on to 3.1.4

getWeatherData showed "Forecasted Rain: NaN mm" whenever the main
weatherProvider (e.g. local) doesn't supply forecast data. Fetch the
forecast from the separately configurable FORECAST_WEATHER_PROVIDER
and merge forecast/precip/minTemp/maxTemp into the response, failing
open (logs only) if that fetch fails; all other fields still come from
the main weatherProvider.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…eta01

Note above the FORECAST_WEATHER_PROVIDER fetch in getWeatherData that the
official OpenSprinkler App's forecast attribution text is currently driven
by controller.settings.wto.provider (the main WEATHER_PROVIDER), not by
this forecast-specific value - a known App-side limitation, not a bug here.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@smeisens

Copy link
Copy Markdown
Contributor Author

Related to #176 (closed): that PR attempted a full local+forecast merge across all Zimmerman/ETo input fields via per-provider HybridXxxProvider classes, but ran into real inconsistencies between forecast providers (missing humidity forecasts, optional wind support — see discussion there). This PR takes a narrower approach: local data remains the sole source for Zimmerman/ETo scale and California restriction; only the rain-forecast restriction (and its /weatherData display) uses a separately configurable FORECAST_WEATHER_PROVIDER, avoiding the field-normalization problems entirely.

@smeisens

Copy link
Copy Markdown
Contributor Author

The 3 failing Docker checks (Merge & Push, Re-Tag, Build & Push Success) are expected for a fork PR — they require registry secrets that aren't exposed to PRs from forks. The actual build steps (amd64/arm64) pass; push/tag will succeed once merged into master with repo secrets available.

@symposion

Copy link
Copy Markdown

@smeisens This looks like a great improvement that would really help me. A couple of things that might need checking:

  1. Unless I've misunderstood, I think this is going to change the forecast provider for basically all users who aren't currently using OpenMeteo and don't update their config. That seems a bit unfriendly; could we change it to default to the current WEATHER_PROVIDER if FORECAST_WEATHER_PROVIDER is not set explicitly?
  2. The attribution issue may be more of an issue than you're acknowledging. I think you'll be suppressing attribution for commercial forecast services like Apple, and I think that might be a violation of their ToS.

Address reviewer feedback: FORECAST_WEATHER_PROVIDER was resolved once at
startup with a hardcoded OpenMeteo fallback, which silently changed the
forecast provider for anyone using something other than OpenMeteo as their
main WEATHER_PROVIDER (e.g. AccuWeather), even without opting in.

Replace it with resolveForecastProvider(weatherProvider), called per
request right after weatherProvider is resolved, falling back to that
already-resolved provider (not process.env.WEATHER_PROVIDER directly, since
weatherProvider already accounts for adjustmentOptions.provider overrides).
Nobody who hasn't explicitly set FORECAST_WEATHER_PROVIDER sees any change
in behavior.

Also:
- Remove config.ts's now-unused resolveForecastWeatherProvider() default
  resolver and its tests.
- Add resolveForecastProvider unit tests, including the AccuWeather
  regression scenario.
- Document FORECAST_WEATHER_PROVIDER in docs/configuration.md (previously
  undocumented) with a note on the App's current attribution limitation,
  and add an example to .env.example.
- Bump version to 3.2.0-beta02.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@smeisens

Copy link
Copy Markdown
Contributor Author

Thanks @symposion for the review, both points are fair and I'll address them:

You're right, that's a real regression risk. I'll change the default so FORECAST_WEATHER_PROVIDER falls back to whatever weatherProvider was actually resolved for that request (respecting per-controller overrides too, not just the env var) rather than hardcoding OpenMeteo. That means zero behavior change for anyone unless they explicitly set the new variable.
Also fair, and more serious than I initially framed it. The root cause is actually in the official App (weather.js:798 derives attribution from controller.settings.wto.provider rather than the service's own forecast-provider info), which this PR alone can't fix. I'll: (a) still send accurate provider info in the /weatherData response so the API is correct regardless, (b) add an explicit README warning about the attribution gap for anyone pointing FORECAST_WEATHER_PROVIDER at an attribution-required commercial provider that differs from WEATHER_PROVIDER, and (c) open a companion issue in OpenSprinkler-App referencing the exact line. Happy to hold off merging until that App-side issue is at least filed and visible.

@smeisens

Copy link
Copy Markdown
Contributor Author

Reference PR OpenSprinkler/OpenSprinkler-App#306

@symposion

Copy link
Copy Markdown

What's the status of this? I'm running locally with my own fork of the weather service that does something a bit similar and more limited to this PR, and I'd love to be able to move back to running a proper released version. Is there a channel to request reviews from the maintainers somehow?

mergeForecastWeatherData now also takes weatherProvider from the forecast
fetch, so the response names the actual source of the forecast data
(consumed by OpenSprinkler/OpenSprinkler-App#306). Updates the related
test, comment and docs, and replaces the leftover issue placeholder in
docs/configuration.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015kgnUEJ28iL8vuJtweUZLp
@smeisens

smeisens commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor Author

What's the status of this? I'm running locally with my own fork of the weather service that does something a bit similar and more limited to this PR, and I'd love to be able to move back to running a proper released version. Is there a channel to request reviews from the maintainers somehow?

Thanks for the nudge! From my side the PR is complete: your two review points are addressed (forecast provider now defaults to the request's main provider, so zero behavior change unless opted in; attribution fix is in OpenSprinkler/OpenSprinkler-App#306). I've updated the description to reflect the current state.

I haven't found a formal review-request channel either. @rayshobby – could someone take a look at this and the companion App PR #306 when you have time? Happy to rebase or adjust anything.

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