diff options
Diffstat (limited to 'internal/openmeteo')
| -rw-r--r-- | internal/openmeteo/openmeteo.go | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/internal/openmeteo/openmeteo.go b/internal/openmeteo/openmeteo.go index b5220f4..b1596e0 100644 --- a/internal/openmeteo/openmeteo.go +++ b/internal/openmeteo/openmeteo.go @@ -383,3 +383,52 @@ func presentSlice(v any) []bool { } return out } + +// AirHourly fetches per-hour values for air-quality fields, keyed by the local +// timestamp the API reports ("2006-01-02T15:04") and then by field. +// +// Keyed by time rather than by index because this is a different endpoint from +// the forecast: nothing guarantees the two arrays start at the same hour, and +// merging by position would silently shift a column by an hour. +// +// A field the API withholds is absent rather than zero, so a column shows blank +// instead of a confident wrong number. +func AirHourly(lat, lon float64, hours int, fields []string) (map[string]map[string]float64, error) { + out := map[string]map[string]float64{} + if len(fields) == 0 { + return out, nil + } + days := hours/24 + 2 + if days > MaxAirDays { + days = MaxAirDays + } + var r struct { + Hourly map[string]any `json:"hourly"` + } + err := get(airURL, url.Values{ + "latitude": {strconv.FormatFloat(lat, 'f', 4, 64)}, + "longitude": {strconv.FormatFloat(lon, 'f', 4, 64)}, + "hourly": {strings.Join(fields, ",")}, + "forecast_days": {strconv.Itoa(days)}, + "timezone": {"auto"}, + }, &r) + if err != nil { + return nil, err + } + + times := stringSlice(r.Hourly["time"]) + for _, f := range fields { + vals := floatSlice(r.Hourly[f]) + have := presentSlice(r.Hourly[f]) + for i, t := range times { + if i >= len(vals) || (i < len(have) && !have[i]) { + continue + } + if out[t] == nil { + out[t] = map[string]float64{} + } + out[t][f] = vals[i] + } + } + return out, nil +} |
