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:
parent
dc8c9df719
commit
0321f0fc80
1 changed files with 28 additions and 7 deletions
|
|
@ -7,10 +7,18 @@
|
||||||
//
|
//
|
||||||
// Provider selection: Met Office DataHub if an api_key is configured AND the
|
// 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
|
// 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
|
// "use Met Office" switch); otherwise, OR if the Met Office call fails for any reason
|
||||||
// way this only ever returns TODAY's forecast high — not live/current temperature —
|
// (see the catch below), Open-Meteo — which needs no key at all. Either way this only
|
||||||
// so a tier, once picked at an occupied-state transition, doesn't need to fight
|
// ever returns TODAY's forecast high — not live/current temperature — so a tier, once
|
||||||
// hour-to-hour swings (see scheduler.js's applyStateTransition()).
|
// 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 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
|
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 metOffice = await getIntegration('met_office')
|
||||||
const peakC = metOffice?.api_key
|
let peakC
|
||||||
? await fetchFromMetOffice(lat, lon, metOffice.api_key)
|
if (metOffice?.api_key) {
|
||||||
: await fetchFromOpenMeteo(lat, lon)
|
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() }
|
cache = { peakC, fetchedAt: Date.now() }
|
||||||
return peakC
|
return peakC
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue