Open-Meteo API Integration: Multi-Model Wettervorhersage für Segelflieger
Wie man icon_d2 und best_match Modelle kombiniert, mit pickField-Funktion Daten extrahiert, und Fallback-Mechanismen implementiert
🌦️ Das Problem: Welches Wettermodell ist das Beste?
Bei der Entwicklung von EDXE Thermik-X, einer Wettervorhersage für Segelflieger, stand ich vor einer Herausforderung: Open-Meteo bietet mehrere Wettermodelle (icon_d2, best_match, icon_eu, etc.), aber nicht alle Datenfelder sind in jedem Modell verfügbar.
Zum Beispiel: wind_direction_10m ist im icon_d2 Modell oft zuverlässiger, aber manchmal ist best_match
der einzige Weg, um bestimmte Parameter wie CAPE (Konvektive Energie) zu erhalten.
Die Lösung? Eine flexible pickField() Funktion, die automatisch zwischen Modellen wechselt und Fallbacks implementiert.
⚙️ Die pickField() Funktion
Das Herzstück der Datenextraktion ist diese kleine, aber mächtige Funktion:
function pickField(obj, field) {
// Priority order: icon_d2 > best_match > naked field
if (obj[field + '_icon_d2'] !== undefined && obj[field + '_icon_d2'] !== null) {
return obj[field + '_icon_d2'];
}
if (obj[field + '_best_match'] !== undefined && obj[field + '_best_match'] !== null) {
return obj[field + '_best_match'];
}
if (obj[field] !== undefined && obj[field] !== null) {
return obj[field];
}
return null;
}
So funktioniert's:
- Schritt 1: Versuche zuerst, das Feld mit
_icon_d2Suffix zu finden (z.B.wind_speed_10m_icon_d2) - Schritt 2: Falls nicht vorhanden, greife auf
_best_matchzurück - Schritt 3: Als letztes Fallback: Verwende das "nackte" Feld ohne Suffix
- Schritt 4: Gib
nullzurück, falls nichts gefunden wurde
📡 API-Call Setup: Dual-Model Request
Der Trick ist, Open-Meteo mit models=icon_d2,best_match zu konfigurieren. Das gibt uns beide Modelle
in einer einzigen API-Response:
const API_URL = `https://api.open-meteo.com/v1/forecast?
latitude=52.27669
&longitude=7.4925
&hourly=temperature_2m,wind_speed_10m,wind_direction_10m,wind_gusts_10m,cape
&models=icon_d2,best_match
&timezone=Europe/Berlin
&forecast_days=3`;
const res = await fetch(API_URL);
const data = await res.json();
Die Response sieht dann so aus:
{
"hourly": {
"time": ["2025-01-22T00:00", "2025-01-22T01:00", ...],
"temperature_2m_icon_d2": [5.2, 4.8, ...],
"temperature_2m_best_match": [5.1, 4.9, ...],
"wind_speed_10m_icon_d2": [12.5, 11.8, ...],
"wind_speed_10m_best_match": [13.2, 12.1, ...],
"cape_best_match": [120, 150, ...]
}
}
Beachte: cape gibt es nur in _best_match, während wind_speed_10m in beiden Modellen vorhanden ist.
🔄 Praktische Anwendung: Datenextraktion
So verwenden wir pickField() in der Praxis, um stündliche Wetterdaten zu verarbeiten:
// Hourly-Daten nach Tagen gruppieren
const days = {};
hourly.time.forEach((t, i) => {
const dateKey = t.slice(0, 10); // "2025-01-22"
if (!days[dateKey]) {
days[dateKey] = { date: dateKey, hours: [] };
}
// Erstelle Stunden-Objekt mit allen Feldern
const hour = { time: t };
Object.keys(hourly).forEach(key => {
if (key !== 'time') {
hour[key] = hourly[key][i];
}
});
// Jetzt extrahieren wir die Werte mit pickField
const temp = pickField(hour, 'temperature_2m'); // → icon_d2 bevorzugt
const windSpeed = pickField(hour, 'wind_speed_10m'); // → icon_d2 bevorzugt
const cape = pickField(hour, 'cape'); // → best_match (nur dort vorhanden)
console.log(`${t}: Temp ${temp}°C, Wind ${windSpeed} km/h, CAPE ${cape}`);
days[dateKey].hours.push({ temp, windSpeed, cape });
});
🛡️ Fehlerbehandlung und Fallbacks
Was passiert, wenn ein Modell ausfällt oder Daten fehlen?
// Beispiel: Wind-Richtung mit Fallback
const windDir = pickField(hour, 'wind_direction_10m');
if (windDir == null) {
console.warn('Keine Windrichtung verfügbar für', t);
// Fallback: Verwende vorherigen Wert oder Default
windDir = previousWindDir || 0;
}
// Dominante Wind-Richtung für den ganzen Tag berechnen
const windDirDom = pickField(dayObj, 'wind_direction_10m_dominant');
const windDirText = windDirDom != null ? degToDir(windDirDom) : '?';
// degToDir() konvertiert Grad in Himmelsrichtung
function degToDir(deg) {
const dirs = ['N', 'NNO', 'NO', 'ONO', 'O', 'OSO', 'SO', 'SSO',
'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW'];
return dirs[Math.round(deg / 22.5) % 16];
}
🚀 Best Practices für Multi-Model APIs
- Bevorzuge regionale Modelle:
icon_d2ist für Deutschland/Europa präziser als globale Modelle - Verwende best_match als Fallback: Wenn spezielle Parameter (wie CAPE) nur dort verfügbar sind
- Immer null-checks: API-Daten können unvollständig sein – defensiv programmieren!
- Log die verwendeten Modelle: Für Debugging ist es hilfreich zu wissen, welches Modell für welches Feld verwendet wurde
- Cache API-Responses: Open-Meteo hat Rate Limits – caching spart Requests
💡 Erweiterte Techniken
Dual-Location Requests
Für das Projekt laden wir gleichzeitig Daten von zwei Standorten (EDXE Flugplatz + Porta Westfalica Hangflug):
// Parallele Fetches
const [resEDXE, resPorta] = await Promise.all([
fetch(EDXE_API_URL),
fetch(PORTA_API_URL)
]);
const edxeData = await resEDXE.json();
const portaData = await resPorta.json();
// Verarbeite beide Datasets separat
processEDXEData(edxeData);
processPortaData(portaData);
Höhenwind-Berechnung aus Hourly-Daten
Ein häufiges Problem: wind_speed_120m_max ist keine gültige daily-Variable in Open-Meteo.
Die Lösung? Berechne das Tages-Maximum selbst aus hourly-Daten:
// Höhenwind-Maximum für den Tag berechnen
const hourlyByDay = {};
portaHourly.time.forEach((t, i) => {
const dateKey = t.slice(0, 10);
if (!hourlyByDay[dateKey]) {
hourlyByDay[dateKey] = { wind_120m: [], wind_180m: [] };
}
const hourObj = {...}; // Erstelle Objekt aus allen hourly-Feldern
const ws120 = pickField(hourObj, 'wind_speed_120m');
const ws180 = pickField(hourObj, 'wind_speed_180m');
if (ws120 != null) hourlyByDay[dateKey].wind_120m.push(ws120);
if (ws180 != null) hourlyByDay[dateKey].wind_180m.push(ws180);
});
// Tages-Maximum ermitteln
const max120 = Math.max(...hourlyByDay[dateKey].wind_120m);
const max180 = Math.max(...hourlyByDay[dateKey].wind_180m);
const windSpeedAloft = Math.max(max120, max180);
console.log(`Höhenwind Maximum: ${windSpeedAloft} km/h`);
🎯 Zusammenfassung
Mit der pickField() Funktion und Multi-Model Requests kannst du:
- ✅ Mehrere Wettermodelle gleichzeitig nutzen
- ✅ Automatisch das beste verfügbare Modell pro Datenfeld wählen
- ✅ Robuste Fallback-Mechanismen implementieren
- ✅ Fehlende Daten elegant behandeln
- ✅ API-Responses flexibel verarbeiten
Der vollständige Code ist im EDXE Thermik-X Projekt zu finden. Schau dir auch die anderen Blog-Artikel zum Projekt an!