Fall back to Open-Meteo when a configured Met Office call fails

getPeakTempC() previously only tried Open-Meteo when NO Met Office api_key
was set at all — if a key was set but the call itself failed (wrong
DataHub product subscription, outage, etc.) the whole fetch went dark
with no fallback, so weather compensation silently stopped surfacing
anywhere. Root cause hit live: fetchFromMetOffice() calls the "Global
Spot" deterministic product, which is a separate DataHub subscription
from "Site-Specific Blended Probabilistic Forecast" — subscribing to the
wrong one 403s. Now any Met Office failure degrades to Open-Meteo instead
of returning nothing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-08-25 11:19:30 +00:00
parent dc8c9df719
commit 0321f0fc80

View file

@ -7,10 +7,18 @@
//
// Provider selection: Met Office DataHub if an api_key is configured AND the
// integration is enabled in settings (the existing enable/disable toggle IS the
// "use Met Office" switch); otherwise Open-Meteo, which needs no key at all. Either
// way this only ever returns TODAY's forecast high — not live/current temperature —
// so a tier, once picked at an occupied-state transition, doesn't need to fight
// hour-to-hour swings (see scheduler.js's applyStateTransition()).
// "use Met Office" switch); otherwise, OR if the Met Office call fails for any reason
// (see the catch below), Open-Meteo — which needs no key at all. Either way this only
// ever returns TODAY's forecast high — not live/current temperature — so a tier, once
// picked at an occupied-state transition, doesn't need to fight hour-to-hour swings
// (see scheduler.js's applyStateTransition()).
//
// IMPORTANT: fetchFromMetOffice() below calls the "Global Spot" deterministic product
// (`sitespecific/v0/point/daily`) — a DIFFERENT Met Office DataHub subscription from
// the "Site-Specific Blended Probabilistic Forecast" product (percentile/probability
// bands, no plain max-temp field). Subscribing to the wrong one on the DataHub side
// gives a 403 here, which the catch below quietly degrades to Open-Meteo — confirmed
// live 2026-08-25.
const CACHE_TTL_MS = 60 * 60 * 1000 // 1h — forecasts don't move fast enough to poll more often
const STALE_FALLBACK_MS = 6 * 60 * 60 * 1000 // still serve a cached value up to 6h old if a refetch fails
@ -73,9 +81,22 @@ export async function getPeakTempC() {
}
const metOffice = await getIntegration('met_office')
const peakC = metOffice?.api_key
? await fetchFromMetOffice(lat, lon, metOffice.api_key)
: await fetchFromOpenMeteo(lat, lon)
let peakC
if (metOffice?.api_key) {
try {
peakC = await fetchFromMetOffice(lat, lon, metOffice.api_key)
} catch (err) {
// Met Office configured but the call failed (wrong product subscription, key not
// yet propagated, outage, ...) — degrade to Open-Meteo rather than going dark.
// Common cause: the key is only subscribed to the Site-Specific Blended
// Probabilistic Forecast product, not the deterministic Global Spot one this
// fetches from — they're separate subscriptions on Met Office's side.
console.error('[weather] Met Office fetch failed, falling back to Open-Meteo:', err.message)
peakC = await fetchFromOpenMeteo(lat, lon)
}
} else {
peakC = await fetchFromOpenMeteo(lat, lon)
}
cache = { peakC, fetchedAt: Date.now() }
return peakC