from __future__ import annotations
import json
from dataclasses import dataclass
from datetime import datetime
from gibil.classes.models import WeatherForecastPoint, WeatherResolvedTruth
@dataclass(frozen=True)
class WeatherDisplayDataset:
forecast_points: list[WeatherForecastPoint]
resolved_truth: list[WeatherResolvedTruth]
class WeatherDisplay:
"""Renders weather source data for the Astrape web UI."""
def render(self) -> str:
return """
Weather
External forecast history
Horizons
Resolved truth
"""
def data_payload(self, dataset: WeatherDisplayDataset | None = None) -> str:
if dataset is None:
dataset = WeatherDisplayDataset(forecast_points=[], resolved_truth=[])
forecast_points = [self._forecast_point(point) for point in dataset.forecast_points]
resolved_truth = [self._truth_point(point) for point in dataset.resolved_truth]
horizons = sorted({point["horizon_hours"] for point in forecast_points})
return json.dumps(
{
"forecast_points": forecast_points,
"resolved_truth": resolved_truth,
"horizons": horizons,
"min_horizon": 1,
"max_horizon": 47,
}
)
def _forecast_point(self, point: WeatherForecastPoint) -> dict[str, object]:
return {
"issued_at": self._iso(point.issued_at),
"target_at": self._iso(point.target_at),
"horizon_hours": point.horizon_hours,
"source": point.source,
"temperature_c": point.temperature_c,
"shortwave_radiation_w_m2": point.shortwave_radiation_w_m2,
"cloud_cover_pct": point.cloud_cover_pct,
}
def _truth_point(self, point: WeatherResolvedTruth) -> dict[str, object]:
return {
"resolved_at": self._iso(point.resolved_at),
"source": point.source,
"temperature_c": point.temperature_c,
"shortwave_radiation_w_m2": point.shortwave_radiation_w_m2,
}
def _iso(self, value: datetime) -> str:
return value.isoformat()