Try every configured Met Office key per tier, don't assume which covers what
Forecast key -> hourly was tried and confirmed wrong (settings test route reported 'not subscribed'). New fetchWithKeys() tries Spot then Forecast for EVERY tier (hourly, three-hourly, daily) and keeps whichever succeeds, rather than assigning a specific key to a specific endpoint based on an unverified guess about Met Office's product catalog. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
4b535a34f4
commit
15a801b1f4
1 changed files with 35 additions and 12 deletions
|
|
@ -10,13 +10,15 @@
|
|||
// other endpoints could actually serve. This matters because Met Office DataHub
|
||||
// sells "Global Spot" and "Forecast" as SEPARATE subscriptions with separate keys
|
||||
// (settings' met_office integration: api_key = Spot, forecast_api_key = Forecast,
|
||||
// optional) — only Spot (used here for daily) has ever been confirmed live (hvac,
|
||||
// 2026-08-25); hourly/three-hourly try forecast_api_key first (falling back to
|
||||
// api_key if no separate Forecast key is configured), since Spot alone may not
|
||||
// actually be subscribed to those endpoints. Field names for hourly/three-hourly
|
||||
// are taken from the published Met Office DataHub docs, still not verified live —
|
||||
// a mismatch there just throws and that tier falls back to Open-Meteo, same as an
|
||||
// outright subscription failure.
|
||||
// optional) — only Spot's daily endpoint has ever been confirmed live (hvac,
|
||||
// 2026-08-25). Which key actually covers hourly/three-hourly is NOT documented
|
||||
// anywhere we could find, and a first guess (Forecast key -> hourly) was tried and
|
||||
// confirmed wrong via settings' met_office test route — so every tier just tries
|
||||
// whichever keys are configured (Spot then Forecast, see fetchWithKeys) and keeps
|
||||
// whichever works, discovered at runtime rather than assumed. Field names for
|
||||
// hourly/three-hourly are taken from the published Met Office DataHub docs, still
|
||||
// not verified live — a mismatch there just throws and that tier falls back to
|
||||
// Open-Meteo, same as an outright subscription failure.
|
||||
import { pool, setStatus } from '../db.js'
|
||||
import { iconFromMetOffice, iconFromOpenMeteo } from './icons.js'
|
||||
|
||||
|
|
@ -217,6 +219,25 @@ function openMeteoAstroPoints(dailyRows, astroKeys) {
|
|||
.map(r => ({ date: r.dateKey, sunrise: r.sunrise, sunset: r.sunset }))
|
||||
}
|
||||
|
||||
// Tries each configured key in turn against the same tier, returning the first
|
||||
// success. Which of Spot/Forecast actually covers which endpoint isn't documented
|
||||
// anywhere we could find, and a first guess (Forecast -> hourly specifically) was
|
||||
// tried and confirmed wrong live via settings' met_office test route — so rather
|
||||
// than assuming again, every tier just tries whatever keys are configured and
|
||||
// keeps whichever one actually works, discovered at runtime instead of guessed at.
|
||||
async function fetchWithKeys(fetchFn, keys) {
|
||||
const errors = []
|
||||
for (const [name, key] of keys) {
|
||||
if (!key) continue
|
||||
try {
|
||||
return await fetchFn(key)
|
||||
} catch (err) {
|
||||
errors.push(`${name}: ${err.message}`)
|
||||
}
|
||||
}
|
||||
throw new Error(errors.join('; ') || 'no Met Office key configured')
|
||||
}
|
||||
|
||||
// ── Storage ──────────────────────────────────────────────────────────────
|
||||
async function replaceResolution(resolution, points) {
|
||||
const client = await pool.connect()
|
||||
|
|
@ -293,13 +314,15 @@ export async function refreshForecast(log = console) {
|
|||
let hourlyPoints = [], threeHourlyPoints = [], dailyPoints = [], astroPoints = []
|
||||
|
||||
if (metOffice?.api_key) {
|
||||
const spotKey = metOffice.api_key
|
||||
const forecastKey = metOffice.forecast_api_key || metOffice.api_key
|
||||
// Spot first (the one confirmed working, for daily) then Forecast, for
|
||||
// every tier — see fetchWithKeys' comment for why this doesn't assume
|
||||
// which key covers which endpoint.
|
||||
const keys = [['Spot', metOffice.api_key], ['Forecast', metOffice.forecast_api_key]]
|
||||
|
||||
const [hourlyR, threeHourlyR, dailyR] = await Promise.allSettled([
|
||||
fetchMetOfficeHourly(lat, lon, forecastKey),
|
||||
fetchMetOfficeThreeHourly(lat, lon, forecastKey, dayKeys),
|
||||
fetchMetOfficeDaily(lat, lon, spotKey, skipKeys, astroKeys),
|
||||
fetchWithKeys(key => fetchMetOfficeHourly(lat, lon, key), keys),
|
||||
fetchWithKeys(key => fetchMetOfficeThreeHourly(lat, lon, key, dayKeys), keys),
|
||||
fetchWithKeys(key => fetchMetOfficeDaily(lat, lon, key, skipKeys, astroKeys), keys),
|
||||
])
|
||||
|
||||
if (hourlyR.status === 'fulfilled') {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue