Tik op een dag in de verwachtingsstrook voor een uuroverzicht van
temperatuur, regen en wind (richting + snelheid), om de 2 uur, 12
punten per dag. Sluit na 20 seconden vanzelf of bij een tik op de
overlay zelf.
Backend: Open-Meteo levert hourly-data in dezelfde call als daily
(geen extra verzoek, dezelfde 60min-cache). Nieuwe HourlyForecastMapper
groepeert per kalenderdatum en bemonstert om het andere uur, robuust
voor de zomertijddag (23/25 uur). OpenMeteoClient::dailyForecast()
hernoemd naar forecast(), geeft nu {daily, hourly} terug. Elke dag in
de forecast-array krijgt een hourly-lijst.
Frontend: temperatuurlijn hergebruikt sparklinePath (nu ook als
sparklinePoints voor exacte uitlijning met de 12-koloms grid), regen
als kleine staafjes, windpijl (nieuw icoon) wijst waarheen de wind
waait. 20s-balk via CSS transition met reflow-restart. Servicewerker
naar v5.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
40 lines
1.3 KiB
PHP
40 lines
1.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Weerscherm;
|
|
|
|
/** Open-Meteo dagverwachting. Gratis voor niet-commercieel gebruik, geen API-key. */
|
|
final class OpenMeteoClient
|
|
{
|
|
private const URL = 'https://api.open-meteo.com/v1/forecast';
|
|
|
|
public function __construct(private readonly HttpClient $http)
|
|
{
|
|
}
|
|
|
|
/** @return array{daily: array<string, mixed>, hourly: array<string, mixed>} */
|
|
public function forecast(float $lat, float $lon, string $timezone): array
|
|
{
|
|
$res = $this->http->get(self::URL, [
|
|
'latitude' => $lat,
|
|
'longitude' => $lon,
|
|
'daily' => 'weather_code,temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_probability_max',
|
|
'hourly' => 'temperature_2m,precipitation,wind_speed_10m,wind_direction_10m',
|
|
'timezone' => $timezone,
|
|
'forecast_days' => 6,
|
|
]);
|
|
if ($res->status !== 200) {
|
|
throw new UpstreamException("Open-Meteo: HTTP {$res->status}");
|
|
}
|
|
$json = $res->json();
|
|
if (!is_array($json['daily'] ?? null)) {
|
|
throw new UpstreamException('Open-Meteo: geen daily-blok in antwoord');
|
|
}
|
|
return [
|
|
'daily' => $json['daily'],
|
|
'hourly' => is_array($json['hourly'] ?? null) ? $json['hourly'] : [],
|
|
];
|
|
}
|
|
}
|