From 7eda2fbbe8753cd9a85d46e62e56cbf27e4c8bb8 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Jan 2026 18:50:16 +0000 Subject: [PATCH] Add weather widget with OpenWeatherMap integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implementiert vollständiges Wetter-Widget oberhalb des Webcam-Videos: **Features:** 🌤️ **Wetter-Anzeige:** - Temperatur (°C) - Windgeschwindigkeit & Richtung (km/h) - Luftdruck (hPa) - Luftfeuchtigkeit (%) - Wetterbeschreibung mit Emoji-Icons - Niederschlag (Regen/Schnee) wenn vorhanden ⚙️ **Technisch:** - OpenWeatherMap API Integration - 5 Minuten Cache (konfigurierbar) - Auto-Update alle X Minuten (Frontend) - WeatherManager Klasse für Backend - Schönes Gradient-Design mit Hover-Effekten - Responsive für Mobile 🎛️ **Admin-Settings:** - Wetter-Widget ein/aus - API Key Eingabefeld + Registrierungs-Link - Standort konfigurierbar (Stadt,Land) - GPS-Koordinaten (Lat/Lon) - Update-Intervall (5-60 Minuten) - Einheiten (Metrisch/Imperial) **Dateien:** - WeatherManager.php: Neue Klasse für API-Calls & Caching - SettingsManager.php: Weather Settings Defaults & Helper - index.php: Widget HTML, CSS, JavaScript Auto-Update - settings.json: Weather Defaults initialisiert **Koordinaten Oberdürnten:** Lat: 47.2833, Lon: 8.7167 **Setup für User:** 1. Gratis Account auf openweathermap.org erstellen 2. API Key im Admin-Panel einfügen 3. Fertig! Widget zeigt Live-Wetter an --- aurora-livecam/SettingsManager.php | 38 ++++ aurora-livecam/WeatherManager.php | 160 ++++++++++++++ aurora-livecam/index.php | 339 ++++++++++++++++++++++++++++- aurora-livecam/settings.json | 9 + 4 files changed, 544 insertions(+), 2 deletions(-) create mode 100644 aurora-livecam/WeatherManager.php diff --git a/aurora-livecam/SettingsManager.php b/aurora-livecam/SettingsManager.php index 0db1f1d..3dc0415 100644 --- a/aurora-livecam/SettingsManager.php +++ b/aurora-livecam/SettingsManager.php @@ -73,6 +73,16 @@ class SettingsManager { 'meta_description' => '', 'meta_keywords' => '' ], + // Weather Widget + 'weather' => [ + 'enabled' => true, + 'api_key' => '', + 'location' => 'Oberdürnten,CH', + 'lat' => '47.2833', + 'lon' => '8.7167', + 'update_interval' => 5, // Minuten + 'units' => 'metric' // metric (Celsius) oder imperial (Fahrenheit) + ], 'last_updated' => null, 'updated_by' => null ]; @@ -239,4 +249,32 @@ class SettingsManager { public function getMetaKeywords() { return $this->get('seo.meta_keywords') ?? ''; } + + // Weather Helper + public function isWeatherEnabled() { + return $this->get('weather.enabled') === true; + } + + public function getWeatherApiKey() { + return $this->get('weather.api_key') ?? ''; + } + + public function getWeatherLocation() { + return $this->get('weather.location') ?? 'Oberdürnten,CH'; + } + + public function getWeatherCoords() { + return [ + 'lat' => $this->get('weather.lat') ?? '47.2833', + 'lon' => $this->get('weather.lon') ?? '8.7167' + ]; + } + + public function getWeatherUpdateInterval() { + return $this->get('weather.update_interval') ?? 5; + } + + public function getWeatherUnits() { + return $this->get('weather.units') ?? 'metric'; + } } diff --git a/aurora-livecam/WeatherManager.php b/aurora-livecam/WeatherManager.php new file mode 100644 index 0000000..4bc6dd0 --- /dev/null +++ b/aurora-livecam/WeatherManager.php @@ -0,0 +1,160 @@ +settingsManager = $settingsManager; + } + + /** + * Holt aktuelle Wetterdaten (cached) + */ + public function getCurrentWeather() { + // Prüfe ob Weather aktiviert ist + if (!$this->settingsManager->isWeatherEnabled()) { + return null; + } + + // Prüfe API Key + $apiKey = $this->settingsManager->getWeatherApiKey(); + if (empty($apiKey)) { + return ['error' => 'API Key fehlt']; + } + + // Prüfe Cache + $cached = $this->getCache(); + if ($cached !== null) { + return $cached; + } + + // Hole frische Daten von API + $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"; + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 5); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($httpCode !== 200 || !$response) { + return ['error' => 'API Fehler']; + } + + $data = json_decode($response, true); + if (!$data || !isset($data['main'])) { + return ['error' => 'Ungültige API Antwort']; + } + + // Formatiere Daten + $weather = [ + 'temp' => round($data['main']['temp'], 1), + 'feels_like' => round($data['main']['feels_like'], 1), + 'humidity' => $data['main']['humidity'], + 'pressure' => $data['main']['pressure'], + 'wind_speed' => round($data['wind']['speed'] * 3.6, 1), // m/s -> km/h + 'wind_deg' => $data['wind']['deg'] ?? 0, + 'wind_direction' => $this->getWindDirection($data['wind']['deg'] ?? 0), + 'clouds' => $data['clouds']['all'] ?? 0, + 'description' => ucfirst($data['weather'][0]['description'] ?? 'Unbekannt'), + 'icon' => $data['weather'][0]['icon'] ?? '01d', + 'rain_1h' => $data['rain']['1h'] ?? 0, + 'snow_1h' => $data['snow']['1h'] ?? 0, + 'location' => $data['name'] ?? $this->settingsManager->getWeatherLocation(), + 'timestamp' => time() + ]; + + // Cache speichern + $this->saveCache($weather); + + return $weather; + } + + /** + * Wandelt Windrichtung (Grad) in Kompassrichtung um + */ + private function getWindDirection($deg) { + $directions = ['N', 'NNO', 'NO', 'ONO', 'O', 'OSO', 'SO', 'SSO', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']; + $index = round($deg / 22.5) % 16; + return $directions[$index]; + } + + /** + * Holt Daten aus Cache (wenn noch gültig) + */ + private function getCache() { + if (!file_exists($this->cacheFile)) { + return null; + } + + $content = file_get_contents($this->cacheFile); + $data = json_decode($content, true); + + if (!$data || !isset($data['timestamp'])) { + return null; + } + + // Update-Intervall aus Settings holen (in Minuten) + $updateInterval = $this->settingsManager->getWeatherUpdateInterval() * 60; // Minuten -> Sekunden + + // Prüfe ob Cache noch gültig + if (time() - $data['timestamp'] < $updateInterval) { + return $data; + } + + return null; + } + + /** + * Speichert Daten im Cache + */ + private function saveCache($data) { + $json = json_encode($data, JSON_PRETTY_PRINT); + file_put_contents($this->cacheFile, $json, LOCK_EX); + } + + /** + * Gibt Wetter-Icon-Emoji zurück + */ + public function getWeatherEmoji($iconCode) { + $map = [ + '01d' => '☀️', '01n' => '🌙', + '02d' => '⛅', '02n' => '☁️', + '03d' => '☁️', '03n' => '☁️', + '04d' => '☁️', '04n' => '☁️', + '09d' => '🌧️', '09n' => '🌧️', + '10d' => '🌦️', '10n' => '🌧️', + '11d' => '⛈️', '11n' => '⛈️', + '13d' => '❄️', '13n' => '❄️', + '50d' => '🌫️', '50n' => '🌫️' + ]; + return $map[$iconCode] ?? '🌤️'; + } + + /** + * AJAX Handler für Wetter-Updates + */ + public function handleAjax() { + if ($_SERVER['REQUEST_METHOD'] !== 'GET') return; + if (!isset($_GET['weather_action'])) return; + + header('Content-Type: application/json'); + + if ($_GET['weather_action'] === 'get') { + $weather = $this->getCurrentWeather(); + echo json_encode(['success' => true, 'data' => $weather]); + exit; + } + } +} diff --git a/aurora-livecam/index.php b/aurora-livecam/index.php index 5ac8104..d1ee8ad 100644 --- a/aurora-livecam/index.php +++ b/aurora-livecam/index.php @@ -4,12 +4,17 @@ use PHPMailer\PHPMailer\Exception; require __DIR__ . '/vendor/autoload.php'; require_once 'SettingsManager.php'; +require_once 'WeatherManager.php'; // SettingsManager initialisieren $settingsManager = new SettingsManager(); -// AJAX-Handler für Settings (VOR anderen Ausgaben!) +// WeatherManager initialisieren +$weatherManager = new WeatherManager($settingsManager); + +// AJAX-Handler für Settings und Weather (VOR anderen Ausgaben!) $settingsManager->handleAjax(); +$weatherManager->handleAjax(); if (isset($_GET['download_video'])) { $videoDir = './videos/'; @@ -1264,6 +1269,67 @@ class AdminManager { $output .= ''; $output .= ''; // settings-group + // Weather Settings + $output .= '
'; + $output .= '

🌤️ Wetter-Widget

'; + + $output .= '
'; + $output .= 'Wetter-Widget anzeigen'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'OpenWeatherMap API Key (kostenlos registrieren)'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Standort (Stadt,Land)'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Latitude (Breitengrad)'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Longitude (Längengrad)'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Update-Intervall (Minuten)'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Einheit'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + $output .= '
'; // settings-group + $output .= ''; // admin-settings-panel // Bestehender Admin-Content @@ -2065,6 +2131,90 @@ button[type="submit"]:hover { background-color: #45a049; } .delete-btn { background-color: #ff4136; color: white; border: none; padding: 5px 10px; cursor: pointer; font-size: 0.8em; margin-left: 10px; border-radius: 3px; } +/* Weather Widget */ +.weather-widget { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + gap: 20px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + padding: 20px; + border-radius: 12px; + margin-bottom: 20px; + box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3); + animation: weatherFadeIn 0.5s ease; +} +.weather-widget.weather-error { + background: linear-gradient(135deg, #f44336 0%, #e91e63 100%); + color: white; + font-weight: bold; + justify-content: center; +} +.weather-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 5px; + padding: 10px 15px; + background: rgba(255, 255, 255, 0.15); + border-radius: 8px; + backdrop-filter: blur(10px); + min-width: 120px; + transition: transform 0.3s ease, background 0.3s ease; +} +.weather-item:hover { + transform: translateY(-3px); + background: rgba(255, 255, 255, 0.25); +} +.weather-icon { + font-size: 32px; + line-height: 1; +} +.weather-value { + font-size: 18px; + font-weight: bold; + color: white; + white-space: nowrap; +} +.weather-label { + font-size: 12px; + color: rgba(255, 255, 255, 0.9); + text-transform: uppercase; + letter-spacing: 0.5px; +} +.weather-description { + flex: 1 1 auto; + min-width: 180px; +} +.weather-description .weather-value { + font-size: 16px; + text-align: center; +} +@keyframes weatherFadeIn { + from { opacity: 0; transform: translateY(-10px); } + to { opacity: 1; transform: translateY(0); } +} +@media (max-width: 768px) { + .weather-widget { + gap: 10px; + padding: 15px 10px; + } + .weather-item { + min-width: 90px; + padding: 8px 10px; + } + .weather-icon { + font-size: 24px; + } + .weather-value { + font-size: 14px; + } + .weather-label { + font-size: 10px; + } +} + /* Guestbook */ .guestbook-entry { background-color: #f9f9f9; border-left: 5px solid #4CAF50; margin-bottom: 20px; padding: 15px; border-radius: 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } @@ -2498,6 +2648,53 @@ body.theme-neo footer {
+ + isWeatherEnabled()): ?> + getCurrentWeather(); + if ($weather && !isset($weather['error'])): + ?> +
+
+ 🌡️ + °C + Temperatur +
+
+ 💨 + km/h + Wind +
+
+ 🔽 + hPa + Luftdruck +
+
+ 💧 + % + Luftfeuchtigkeit +
+
+ getWeatherEmoji($weather['icon']); ?> + + +
+ 0 || $weather['snow_1h'] > 0): ?> +
+ 0 ? '🌧️' : '❄️'; ?> + 0 ? $weather['rain_1h'] : $weather['snow_1h']; ?> mm + Niederschlag +
+ +
+ +
+ ⚠️ Wetterdaten nicht verfügbar: +
+ + +
displayWebcam(); ?> @@ -3262,6 +3459,25 @@ const AdminSettings = { case 'seo.meta_keywords': this.showNotification('SEO Meta gespeichert (wirksam bei Reload)', 'success'); break; + + // Weather Settings + case 'weather.enabled': + const weatherWidget = document.getElementById('weather-widget'); + if (weatherWidget) { + weatherWidget.style.display = boolValue ? 'flex' : 'none'; + } + this.showNotification('Wetter-Widget ' + (boolValue ? 'aktiviert' : 'deaktiviert'), 'success'); + break; + case 'weather.api_key': + case 'weather.location': + case 'weather.lat': + case 'weather.lon': + case 'weather.units': + this.showNotification('Wetter-Einstellung gespeichert (Reload empfohlen)', 'success'); + break; + case 'weather.update_interval': + this.showNotification('Update-Intervall: ' + value + ' Minuten (Reload empfohlen)', 'success'); + break; } }, @@ -3359,6 +3575,35 @@ const AdminSettings = { document.getElementById('setting-meta-keywords')?.addEventListener('change', (e) => { this.updateSetting('seo.meta_keywords', e.target.value); }); + + // Weather Settings + document.getElementById('setting-weather-enabled')?.addEventListener('change', (e) => { + 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) => { + this.updateSetting('weather.location', e.target.value); + }); + + document.getElementById('setting-weather-lat')?.addEventListener('change', (e) => { + this.updateSetting('weather.lat', e.target.value); + }); + + document.getElementById('setting-weather-lon')?.addEventListener('change', (e) => { + this.updateSetting('weather.lon', e.target.value); + }); + + document.getElementById('setting-weather-interval')?.addEventListener('change', (e) => { + this.updateSetting('weather.update_interval', parseInt(e.target.value)); + }); + + document.getElementById('setting-weather-units')?.addEventListener('change', (e) => { + this.updateSetting('weather.units', e.target.value); + }); }, showNotification: function(message, type) { @@ -3597,7 +3842,97 @@ document.addEventListener('DOMContentLoaded', function() { } }); - + + + diff --git a/aurora-livecam/settings.json b/aurora-livecam/settings.json index 58bb23d..d731a77 100644 --- a/aurora-livecam/settings.json +++ b/aurora-livecam/settings.json @@ -46,6 +46,15 @@ "meta_description": "", "meta_keywords": "" }, + "weather": { + "enabled": true, + "api_key": "", + "location": "Oberdürnten,CH", + "lat": "47.2833", + "lon": "8.7167", + "update_interval": 5, + "units": "metric" + }, "last_updated": null, "updated_by": null }