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:
Claude
2026-01-22 20:59:07 +00:00
parent 6bca898488
commit 20704b3cd8
2 changed files with 80 additions and 36 deletions
+79 -24
View File
@@ -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
*/ */
+1 -12
View File
@@ -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);
}); });