fox/app/Services/WeatherService.php

96 lines
3.3 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class WeatherService
{
/**
* Open-Meteo Weather Code Mapping → [description, icon-key]
* Icons werden im Blade als inline SVG anhand des Keys gerendert.
*/
protected const CODES = [
0 => ['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,
];
}
}