Merge pull request #141 from copenhagentruckwash/add-weatherapi-module-implementation-6ti277

Add WeatherAPI module with routes, config and OpenAPI definitions
This commit is contained in:
Jeppe B
2026-03-12 08:49:33 +01:00
committed by GitHub
2 changed files with 9 additions and 40 deletions
+4
View File
@@ -6514,6 +6514,10 @@ paths:
responses:
'200':
description: Forecast weather retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/WeatherApiObjectResponse'
/modules/weatherapi/search:
get:
@@ -19,30 +19,6 @@ class moduleWeatherAPIRoute
{
use route_t;
private static function mergeHistoryAndForecast(object $history, object $forecast): object
{
$history_map = [];
foreach (($history->forecast->forecastday ?? []) as $day) {
foreach (($day->hour ?? []) as $hour) {
$key = (new DateTime((string)$hour->time))->format('Y-m-d H:00');
$history_map[$key] = $hour;
}
}
foreach (($forecast->forecast->forecastday ?? []) as $day) {
foreach (($day->hour ?? []) as $hour) {
$key = (new DateTime((string)$hour->time))->format('Y-m-d H:00');
if (isset($history_map[$key])) {
// Override forecast data with history data for past hours
$hour->temp_c = $history_map[$key]->temp_c;
$hour->condition = $history_map[$key]->condition;
}
}
}
return $forecast;
}
public function run(): void
{
global /** @var response $response */
@@ -129,15 +105,8 @@ class moduleWeatherAPIRoute
$opening_hours = new department_time_bookings_opening_hours_o();
$opening_hours->selectByDepartment((int)self::getParameter('id'));
// Get the history since todays start and forecast for today (Total of 24 hours of data with history overriding forecast for past hours)
$history = (new weatherapi())->history($lat . ',' . $lon, date('Y-m-d', strtotime('today')));
$forecast = (new weatherapi())->forecast($lat . ',' . $lon, 1);
$weather = self::mergeHistoryAndForecast($history, $forecast);
$weather = (new weatherapi())->forecast($lat . ',' . $lon, 2);
$timeline = self::buildDepartmentWeatherTimeline((int)self::getParameter('id'), $weather, $opening_hours);
// Sort timeline by time just in case
usort($timeline, function ($a, $b) {
return strcmp($a['time'], $b['time']);
});
(new logs_o())->add('modules_weatherapi', (int)self::getParameter('id'), 1, $user->id, 'DEPARTMENTS_WEATHER_GET', 'Department weather timeline fetched');
$response->success($timeline, 200);
@@ -153,24 +122,22 @@ class moduleWeatherAPIRoute
private function buildDepartmentWeatherTimeline(int $department_id, object $forecast, department_time_bookings_opening_hours_o $opening_hours): array
{
$hourly_weather = [];
// Map historical and forecast data into a single hourly map for easy lookup
foreach (($forecast->forecast->forecastday ?? []) as $day) {
foreach (($day->hour ?? []) as $hour) {
$key = (new DateTime((string)$hour->time))->format('Y-m-d H:00');
$hourly_weather[$key] = self::mapWeatherCondition($hour->condition->code, $hour->condition->text);
$hourly_weather[$key] = self::mapWeatherCondition((int)($hour->condition->code ?? 1000), (string)($hour->condition->text ?? ''));
}
}
$entries = [];
$slot = new DateTime('today');
$slot = new DateTime(date('Y-m-d H:00:00'));
$slot->add(new DateInterval('PT1H'));
for ($i = 0; $i < 24; $i++) {
$slot_key = $slot->format('Y-m-d H:00');
$weather = $hourly_weather[$slot_key] ?? 'mostly_clear';
$is_open = self::isDepartmentOpenAtHour($opening_hours, $slot);
// The amount of worker hours TODO: implement
$hours = 0;
$hours = $is_open ? self::getDailyOpenHours($opening_hours, $slot) : 0;
$washes = self::countWashesForHour($department_id, $slot);
$entries[] = [
'time' => $slot->format('H:00'),
@@ -246,9 +213,7 @@ class moduleWeatherAPIRoute
{
$start = clone $hour_start;
$end = clone $hour_start;
// Add one hour to get the end of the hour slot
$end->add(new DateInterval('PT1H'));
//echo "Counting washes for department $department_id between " . $start->format('Y-m-d H:i:s') . " and " . $end->format('Y-m-d H:i:s') . "\n";
$end->add(new DateInterval('PT59M59S'));
return (new orders_o())->countWashesInDateRange(
$start->format('Y-m-d H:i:s'),