Switch weather API from OpenWeatherMap to Open-Meteo
🎉 **100% KOSTENLOS - KEIN API KEY MEHR NÖTIG!** **Warum Open-Meteo?** - ✅ Komplett kostenlos ohne Limits - ✅ KEIN API Key erforderlich - ✅ Keine Kreditkarte, keine Anmeldung - ✅ Open Source & Non-Profit - ✅ Sehr präzise Daten für die Schweiz - ✅ Schnell & zuverlässig **Technische Änderungen:** **WeatherManager.php:** - API URL auf api.open-meteo.com gewechselt - WMO Weather Codes (0-99) implementiert - Deutsche Wetterbeschreibungen für alle Codes - Temperatur, Wind, Luftdruck, Feuchtigkeit, Niederschlag - Icon-Mapping von WMO Codes zu Emojis - Timezone: Europe/Zurich **index.php Admin-Panel:** - API Key Feld entfernt (nicht mehr nötig!) - Überschrift: "Open-Meteo - 100% kostenlos!" - Event Listener für API Key entfernt - Funktioniert sofort ohne Setup! **API Endpoint:** https://api.open-meteo.com/v1/forecast - Keine Authentication nötig - Parameter: lat, lon, current weather vars - Response: JSON mit aktuellen Wetterdaten **Unterstützte Wetter-Codes:** - 0: Klar - 1-3: Bewölkt (verschiedene Grade) - 45-48: Nebel - 51-65: Regen (Niesel bis stark) - 71-77: Schnee - 80-86: Schauer - 95-99: Gewitter & Hagel **Resultat:** Widget funktioniert SOFORT ohne jegliches Setup! Einfach aktivieren und fertig! 🌤️
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* WeatherManager - Holt und cached Wetterdaten von OpenWeatherMap
|
* WeatherManager - Holt und cached Wetterdaten von Open-Meteo (kostenlos!)
|
||||||
|
* Keine API Key nötig!
|
||||||
*/
|
*/
|
||||||
class WeatherManager {
|
class WeatherManager {
|
||||||
private $settingsManager;
|
private $settingsManager;
|
||||||
@@ -20,23 +21,22 @@ class WeatherManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfe API Key
|
|
||||||
$apiKey = $this->settingsManager->getWeatherApiKey();
|
|
||||||
if (empty($apiKey)) {
|
|
||||||
return ['error' => 'API Key fehlt'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prüfe Cache
|
// Prüfe Cache
|
||||||
$cached = $this->getCache();
|
$cached = $this->getCache();
|
||||||
if ($cached !== null) {
|
if ($cached !== null) {
|
||||||
return $cached;
|
return $cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hole frische Daten von API
|
// Hole frische Daten von API (Open-Meteo)
|
||||||
$coords = $this->settingsManager->getWeatherCoords();
|
$coords = $this->settingsManager->getWeatherCoords();
|
||||||
$units = $this->settingsManager->getWeatherUnits();
|
|
||||||
|
|
||||||
$url = "https://api.openweathermap.org/data/2.5/weather?lat={$coords['lat']}&lon={$coords['lon']}&units={$units}&appid={$apiKey}&lang=de";
|
// Open-Meteo API URL - komplett kostenlos, kein API Key!
|
||||||
|
$url = "https://api.open-meteo.com/v1/forecast?" . http_build_query([
|
||||||
|
'latitude' => $coords['lat'],
|
||||||
|
'longitude' => $coords['lon'],
|
||||||
|
'current' => 'temperature_2m,relative_humidity_2m,precipitation,weather_code,wind_speed_10m,wind_direction_10m,pressure_msl,cloud_cover',
|
||||||
|
'timezone' => 'Europe/Zurich'
|
||||||
|
]);
|
||||||
|
|
||||||
$ch = curl_init();
|
$ch = curl_init();
|
||||||
curl_setopt($ch, CURLOPT_URL, $url);
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
@@ -53,25 +53,27 @@ class WeatherManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$data = json_decode($response, true);
|
$data = json_decode($response, true);
|
||||||
if (!$data || !isset($data['main'])) {
|
if (!$data || !isset($data['current'])) {
|
||||||
return ['error' => 'Ungültige API Antwort'];
|
return ['error' => 'Ungültige API Antwort'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$current = $data['current'];
|
||||||
|
|
||||||
// Formatiere Daten
|
// Formatiere Daten
|
||||||
$weather = [
|
$weather = [
|
||||||
'temp' => round($data['main']['temp'], 1),
|
'temp' => round($current['temperature_2m'], 1),
|
||||||
'feels_like' => round($data['main']['feels_like'], 1),
|
'feels_like' => round($current['temperature_2m'], 1), // Open-Meteo hat keine "feels like"
|
||||||
'humidity' => $data['main']['humidity'],
|
'humidity' => $current['relative_humidity_2m'],
|
||||||
'pressure' => $data['main']['pressure'],
|
'pressure' => round($current['pressure_msl'], 0),
|
||||||
'wind_speed' => round($data['wind']['speed'] * 3.6, 1), // m/s -> km/h
|
'wind_speed' => round($current['wind_speed_10m'], 1), // Schon in km/h!
|
||||||
'wind_deg' => $data['wind']['deg'] ?? 0,
|
'wind_deg' => $current['wind_direction_10m'],
|
||||||
'wind_direction' => $this->getWindDirection($data['wind']['deg'] ?? 0),
|
'wind_direction' => $this->getWindDirection($current['wind_direction_10m']),
|
||||||
'clouds' => $data['clouds']['all'] ?? 0,
|
'clouds' => $current['cloud_cover'] ?? 0,
|
||||||
'description' => ucfirst($data['weather'][0]['description'] ?? 'Unbekannt'),
|
'description' => $this->getWeatherDescription($current['weather_code']),
|
||||||
'icon' => $data['weather'][0]['icon'] ?? '01d',
|
'icon' => $this->getWeatherIcon($current['weather_code']),
|
||||||
'rain_1h' => $data['rain']['1h'] ?? 0,
|
'rain_1h' => $current['precipitation'] ?? 0,
|
||||||
'snow_1h' => $data['snow']['1h'] ?? 0,
|
'snow_1h' => 0, // Open-Meteo gibt Niederschlag gesamt
|
||||||
'location' => $data['name'] ?? $this->settingsManager->getWeatherLocation(),
|
'location' => $this->settingsManager->getWeatherLocation(),
|
||||||
'timestamp' => time()
|
'timestamp' => time()
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -81,6 +83,59 @@ class WeatherManager {
|
|||||||
return $weather;
|
return $weather;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wandelt WMO Weather Code in Beschreibung um
|
||||||
|
* https://open-meteo.com/en/docs
|
||||||
|
*/
|
||||||
|
private function getWeatherDescription($code) {
|
||||||
|
$descriptions = [
|
||||||
|
0 => 'Klar',
|
||||||
|
1 => 'Überwiegend klar',
|
||||||
|
2 => 'Teilweise bewölkt',
|
||||||
|
3 => 'Bewölkt',
|
||||||
|
45 => 'Neblig',
|
||||||
|
48 => 'Nebel mit Reifablagerung',
|
||||||
|
51 => 'Leichter Nieselregen',
|
||||||
|
53 => 'Mäßiger Nieselregen',
|
||||||
|
55 => 'Dichter Nieselregen',
|
||||||
|
61 => 'Leichter Regen',
|
||||||
|
63 => 'Mäßiger Regen',
|
||||||
|
65 => 'Starker Regen',
|
||||||
|
71 => 'Leichter Schneefall',
|
||||||
|
73 => 'Mäßiger Schneefall',
|
||||||
|
75 => 'Starker Schneefall',
|
||||||
|
77 => 'Schneegraupeln',
|
||||||
|
80 => 'Leichte Regenschauer',
|
||||||
|
81 => 'Mäßige Regenschauer',
|
||||||
|
82 => 'Starke Regenschauer',
|
||||||
|
85 => 'Leichte Schneeschauer',
|
||||||
|
86 => 'Starke Schneeschauer',
|
||||||
|
95 => 'Gewitter',
|
||||||
|
96 => 'Gewitter mit leichtem Hagel',
|
||||||
|
99 => 'Gewitter mit starkem Hagel'
|
||||||
|
];
|
||||||
|
|
||||||
|
return $descriptions[$code] ?? 'Unbekannt';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wandelt WMO Weather Code in Icon-Code um (OpenWeatherMap kompatibel)
|
||||||
|
*/
|
||||||
|
private function getWeatherIcon($code) {
|
||||||
|
if ($code == 0) return '01d'; // Klar
|
||||||
|
if ($code >= 1 && $code <= 2) return '02d'; // Teilweise bewölkt
|
||||||
|
if ($code == 3) return '04d'; // Bewölkt
|
||||||
|
if ($code >= 45 && $code <= 48) return '50d'; // Nebel
|
||||||
|
if ($code >= 51 && $code <= 55) return '09d'; // Nieselregen
|
||||||
|
if ($code >= 61 && $code <= 65) return '10d'; // Regen
|
||||||
|
if ($code >= 71 && $code <= 77) return '13d'; // Schnee
|
||||||
|
if ($code >= 80 && $code <= 82) return '09d'; // Regenschauer
|
||||||
|
if ($code >= 85 && $code <= 86) return '13d'; // Schneeschauer
|
||||||
|
if ($code >= 95 && $code <= 99) return '11d'; // Gewitter
|
||||||
|
|
||||||
|
return '01d'; // Default
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wandelt Windrichtung (Grad) in Kompassrichtung um
|
* Wandelt Windrichtung (Grad) in Kompassrichtung um
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1271,7 +1271,7 @@ class AdminManager {
|
|||||||
|
|
||||||
// Weather Settings
|
// Weather Settings
|
||||||
$output .= '<div class="settings-group">';
|
$output .= '<div class="settings-group">';
|
||||||
$output .= '<h4>🌤️ Wetter-Widget</h4>';
|
$output .= '<h4>🌤️ Wetter-Widget <span style="font-size:12px; color:#4CAF50;">(Open-Meteo - 100% kostenlos!)</span></h4>';
|
||||||
|
|
||||||
$output .= '<div class="setting-row">';
|
$output .= '<div class="setting-row">';
|
||||||
$output .= '<span class="setting-label">Wetter-Widget anzeigen</span>';
|
$output .= '<span class="setting-label">Wetter-Widget anzeigen</span>';
|
||||||
@@ -1283,13 +1283,6 @@ class AdminManager {
|
|||||||
$output .= '</div>';
|
$output .= '</div>';
|
||||||
$output .= '</div>';
|
$output .= '</div>';
|
||||||
|
|
||||||
$output .= '<div class="setting-row">';
|
|
||||||
$output .= '<span class="setting-label">OpenWeatherMap API Key <a href="https://openweathermap.org/api" target="_blank" style="font-size:11px;">(kostenlos registrieren)</a></span>';
|
|
||||||
$output .= '<div class="setting-input">';
|
|
||||||
$output .= '<input type="text" id="setting-weather-api-key" class="text-input" placeholder="Dein API Key hier einfügen..." value="' . htmlspecialchars($settingsManager->get('weather.api_key')) . '">';
|
|
||||||
$output .= '</div>';
|
|
||||||
$output .= '</div>';
|
|
||||||
|
|
||||||
$output .= '<div class="setting-row">';
|
$output .= '<div class="setting-row">';
|
||||||
$output .= '<span class="setting-label">Standort (Stadt,Land)</span>';
|
$output .= '<span class="setting-label">Standort (Stadt,Land)</span>';
|
||||||
$output .= '<div class="setting-input">';
|
$output .= '<div class="setting-input">';
|
||||||
@@ -3581,10 +3574,6 @@ const AdminSettings = {
|
|||||||
this.updateSetting('weather.enabled', e.target.checked);
|
this.updateSetting('weather.enabled', e.target.checked);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('setting-weather-api-key')?.addEventListener('change', (e) => {
|
|
||||||
this.updateSetting('weather.api_key', e.target.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('setting-weather-location')?.addEventListener('change', (e) => {
|
document.getElementById('setting-weather-location')?.addEventListener('change', (e) => {
|
||||||
this.updateSetting('weather.location', e.target.value);
|
this.updateSetting('weather.location', e.target.value);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user