fix forecast data
This commit is contained in:
@@ -147,7 +147,7 @@ func (s *webServer) handleDashboard(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
forecast, err := s.db.ForecastSeriesLatest(r.Context(), s.site.Name, s.model)
|
forecast, err := s.db.ForecastSeriesRange(r.Context(), s.site.Name, s.model, start, end)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "failed to query forecast", http.StatusInternalServerError)
|
http.Error(w, "failed to query forecast", http.StatusInternalServerError)
|
||||||
log.Printf("web dashboard forecast error: %v", err)
|
log.Printf("web dashboard forecast error: %v", err)
|
||||||
|
|||||||
@@ -223,6 +223,65 @@ func (d *DB) ForecastSeriesLatest(ctx context.Context, site, model string) (Fore
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DB) ForecastSeriesRange(ctx context.Context, site, model string, start, end time.Time) (ForecastSeries, error) {
|
||||||
|
rows, err := d.Pool.Query(ctx, `
|
||||||
|
SELECT DISTINCT ON (ts)
|
||||||
|
ts,
|
||||||
|
retrieved_at,
|
||||||
|
temp_c,
|
||||||
|
rh,
|
||||||
|
pressure_msl_hpa,
|
||||||
|
wind_m_s,
|
||||||
|
wind_gust_m_s,
|
||||||
|
wind_dir_deg,
|
||||||
|
precip_mm,
|
||||||
|
cloud_cover
|
||||||
|
FROM forecast_openmeteo_hourly
|
||||||
|
WHERE site = $1 AND model = $2 AND ts >= $3 AND ts <= $4
|
||||||
|
ORDER BY ts ASC, retrieved_at DESC
|
||||||
|
`, site, model, start, end)
|
||||||
|
if err != nil {
|
||||||
|
return ForecastSeries{}, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
points := make([]ForecastPoint, 0, 256)
|
||||||
|
var maxRetrieved time.Time
|
||||||
|
for rows.Next() {
|
||||||
|
var (
|
||||||
|
ts time.Time
|
||||||
|
retrieved time.Time
|
||||||
|
temp, rh, msl, wind, gust sql.NullFloat64
|
||||||
|
dir, precip, cloud sql.NullFloat64
|
||||||
|
)
|
||||||
|
if err := rows.Scan(&ts, &retrieved, &temp, &rh, &msl, &wind, &gust, &dir, &precip, &cloud); err != nil {
|
||||||
|
return ForecastSeries{}, err
|
||||||
|
}
|
||||||
|
if retrieved.After(maxRetrieved) {
|
||||||
|
maxRetrieved = retrieved
|
||||||
|
}
|
||||||
|
points = append(points, ForecastPoint{
|
||||||
|
TS: ts,
|
||||||
|
TempC: nullFloatPtr(temp),
|
||||||
|
RH: nullFloatPtr(rh),
|
||||||
|
PressureMSLH: nullFloatPtr(msl),
|
||||||
|
WindMS: nullFloatPtr(wind),
|
||||||
|
WindGustMS: nullFloatPtr(gust),
|
||||||
|
WindDirDeg: nullFloatPtr(dir),
|
||||||
|
PrecipMM: nullFloatPtr(precip),
|
||||||
|
CloudCover: nullFloatPtr(cloud),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if rows.Err() != nil {
|
||||||
|
return ForecastSeries{}, rows.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ForecastSeries{
|
||||||
|
RetrievedAt: maxRetrieved,
|
||||||
|
Points: points,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func nullFloatPtr(v sql.NullFloat64) *float64 {
|
func nullFloatPtr(v sql.NullFloat64) *float64 {
|
||||||
if !v.Valid {
|
if !v.Valid {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user