From c315811ec31f91d01ea6d2db8fc9b082b5273e5c Mon Sep 17 00:00:00 2001 From: Nathan Coad Date: Mon, 26 Jan 2026 13:08:34 +1100 Subject: [PATCH] more logging --- internal/providers/openmeteo.go | 35 ++++++++++++++++++++++-------- internal/providers/wunderground.go | 13 +++++++++++ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/internal/providers/openmeteo.go b/internal/providers/openmeteo.go index 8e5867f..195e6b9 100644 --- a/internal/providers/openmeteo.go +++ b/internal/providers/openmeteo.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "io" "net/http" "net/url" "time" @@ -20,27 +21,27 @@ func (o *OpenMeteo) Fetch(ctxDone <-chan struct{}, site Site, model string) (*Fo o.Client = &http.Client{Timeout: 15 * time.Second} } - // Hourly fields that are useful for bias-correction / training + // Hourly fields supported by the ECMWF endpoint. hourly := []string{ "temperature_2m", - "relative_humidity_2m", "pressure_msl", "wind_speed_10m", "wind_gusts_10m", "wind_direction_10m", "precipitation", - "precipitation_probability", "cloud_cover", + "relative_humidity_1000hPa", } - u, _ := url.Parse("https://api.open-meteo.com/v1/forecast") + u, _ := url.Parse("https://api.open-meteo.com/v1/ecmwf") q := u.Query() q.Set("latitude", fmt.Sprintf("%.6f", site.Latitude)) q.Set("longitude", fmt.Sprintf("%.6f", site.Longitude)) q.Set("hourly", join(hourly)) q.Set("timezone", "UTC") - q.Set("models", model) // e.g. "ecmwf" - q.Set("forecast_days", "7") // keep it short; you can increase later + q.Set("wind_speed_unit", "ms") + q.Set("temperature_unit", "celsius") + q.Set("precipitation_unit", "mm") u.RawQuery = q.Encode() ctx, cancel := context.WithCancel(context.Background()) @@ -55,6 +56,17 @@ func (o *OpenMeteo) Fetch(ctxDone <-chan struct{}, site Site, model string) (*Fo defer resp.Body.Close() if resp.StatusCode/100 != 2 { + body, _ := io.ReadAll(io.LimitReader(resp.Body, 4096)) + var apiErr struct { + Error bool `json:"error"` + Reason string `json:"reason"` + } + if err := json.Unmarshal(body, &apiErr); err == nil && apiErr.Reason != "" { + return nil, fmt.Errorf("open-meteo HTTP %d: %s", resp.StatusCode, apiErr.Reason) + } + if len(body) > 0 { + return nil, fmt.Errorf("open-meteo HTTP %d: %s", resp.StatusCode, string(body)) + } return nil, fmt.Errorf("open-meteo HTTP %d", resp.StatusCode) } @@ -76,13 +88,18 @@ func (o *OpenMeteo) Fetch(ctxDone <-chan struct{}, site Site, model string) (*Fo // Helpers pull float arrays (may be absent) temp := floatArray(hr["temperature_2m"]) - rh := floatArray(hr["relative_humidity_2m"]) + rh := floatArray(hr["relative_humidity_1000hPa"]) + if rh == nil { + rh = floatArray(hr["relative_humidity_2m"]) + } msl := floatArray(hr["pressure_msl"]) + if msl == nil { + msl = floatArray(hr["surface_pressure"]) + } ws := floatArray(hr["wind_speed_10m"]) gust := floatArray(hr["wind_gusts_10m"]) wd := floatArray(hr["wind_direction_10m"]) precip := floatArray(hr["precipitation"]) - pprob := floatArray(hr["precipitation_probability"]) cloud := floatArray(hr["cloud_cover"]) points := make([]HourlyForecastPoint, 0, len(times)) @@ -96,7 +113,7 @@ func (o *OpenMeteo) Fetch(ctxDone <-chan struct{}, site Site, model string) (*Fo WindGustMS: idx(gust, i), WindDirDeg: idx(wd, i), PrecipMM: idx(precip, i), - PrecipProb: idx(pprob, i), + PrecipProb: nil, CloudCover: idx(cloud, i), }) } diff --git a/internal/providers/wunderground.go b/internal/providers/wunderground.go index 1e14faa..61e2946 100644 --- a/internal/providers/wunderground.go +++ b/internal/providers/wunderground.go @@ -3,6 +3,7 @@ package providers import ( "context" "fmt" + "log" "net/http" "net/url" "strconv" @@ -71,6 +72,18 @@ func (c *WundergroundClient) Upload(ctx context.Context, u WUUpload) (string, er // Optional: a software identifier q.Set("softwaretype", "go-weatherstation-go") + // Log sanitized params so it's clear what we're sending. + safe := url.Values{} + for k, vals := range q { + if k == "PASSWORD" { + continue + } + for _, v := range vals { + safe.Add(k, v) + } + } + log.Printf("wunderground upload params %s", safe.Encode()) + reqURL := wuEndpoint + "?" + q.Encode() req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil) if err != nil {