['Klar', 'sun'], 1 => ['Überwiegend klar', 'sun'], 2 => ['Teilweise bewölkt', 'cloud-sun'], 3 => ['Bedeckt', 'cloud'], 45 => ['Nebel', 'fog'], 48 => ['Reifnebel', 'fog'], 51 => ['Leichter Nieselregen', 'drizzle'], 53 => ['Nieselregen', 'drizzle'], 55 => ['Starker Nieselregen', 'drizzle'], 61 => ['Leichter Regen', 'rain'], 63 => ['Regen', 'rain'], 65 => ['Starker Regen', 'rain'], 71 => ['Leichter Schnee', 'snow'], 73 => ['Schnee', 'snow'], 75 => ['Starker Schnee', 'snow'], 77 => ['Schneegriesel', 'snow'], 80 => ['Regenschauer', 'rain'], 81 => ['Regenschauer', 'rain'], 82 => ['Heftige Regenschauer', 'rain'], 85 => ['Schneeschauer', 'snow'], 86 => ['Heftige Schneeschauer', 'snow'], 95 => ['Gewitter', 'storm'], 96 => ['Gewitter mit Hagel', 'storm'], 99 => ['Schweres Gewitter', 'storm'], ]; /** * @return array{temperature: float|null, city: string, icon: string, description: string, fetched_at: ?string} */ public function fetch(): array { $lat = (float) config('services.weather.lat', env('FOX_LAT', 48.2082)); $lon = (float) config('services.weather.lon', env('FOX_LON', 16.3738)); $city = (string) config('services.weather.city', env('FOX_CITY', 'Wien')); $cacheKey = sprintf('fox.weather.%s.%s', $lat, $lon); return Cache::remember($cacheKey, now()->addMinutes(10), function () use ($lat, $lon, $city) { try { $response = Http::timeout(8)->get('https://api.open-meteo.com/v1/forecast', [ 'latitude' => $lat, 'longitude' => $lon, 'current' => 'temperature_2m,weathercode', 'timezone' => 'auto', ]); if (! $response->successful()) { return $this->fallback($city); } $temp = $response->json('current.temperature_2m'); $code = (int) $response->json('current.weathercode', 0); [$description, $icon] = self::CODES[$code] ?? ['Unbekannt', 'cloud']; return [ 'temperature' => $temp !== null ? round((float) $temp, 1) : null, 'city' => $city, 'icon' => $icon, 'description' => $description, 'fetched_at' => now()->toIso8601String(), ]; } catch (\Throwable $e) { Log::warning('WeatherService failed', ['error' => $e->getMessage()]); return $this->fallback($city); } }); } protected function fallback(string $city): array { return [ 'temperature' => null, 'city' => $city, 'icon' => 'cloud', 'description' => 'Keine Daten', 'fetched_at' => null, ]; } }