more chart development

This commit is contained in:
2026-01-27 17:16:36 +11:00
parent 47df7bc431
commit 2953690d5c
5 changed files with 306 additions and 65 deletions

View File

@@ -19,6 +19,8 @@ type ObservationPoint struct {
WindDirDeg *float64 `json:"wind_dir_deg,omitempty"`
UVI *float64 `json:"uvi,omitempty"`
LightLux *float64 `json:"light_lux,omitempty"`
BatteryMV *float64 `json:"battery_mv,omitempty"`
SupercapV *float64 `json:"supercap_v,omitempty"`
}
type ForecastPoint struct {
@@ -38,38 +40,42 @@ type ForecastSeries struct {
Points []ForecastPoint `json:"points"`
}
func (d *DB) ObservationSeries(ctx context.Context, site, bucket string, rangeSeconds int64) ([]ObservationPoint, error) {
if rangeSeconds <= 0 {
return nil, errors.New("range must be > 0")
func (d *DB) ObservationSeries(ctx context.Context, site, bucket string, start, end time.Time) ([]ObservationPoint, error) {
if end.Before(start) || end.Equal(start) {
return nil, errors.New("invalid time range")
}
table := "cagg_ws90_5m"
interval := "5 minutes"
switch bucket {
case "1m":
table = "cagg_ws90_1m"
interval = "1 minute"
case "5m":
table = "cagg_ws90_5m"
interval = "5 minutes"
default:
return nil, fmt.Errorf("unsupported bucket: %s", bucket)
}
query := fmt.Sprintf(`
SELECT
bucket,
temp_c_avg,
rh_avg,
wind_avg_ms_avg,
wind_gust_ms_max,
wind_dir_deg_avg,
uvi_max,
light_lux_max
FROM %s
time_bucket(INTERVAL '%s', ts) AS bucket,
avg(temperature_c) AS temp_c_avg,
avg(humidity) AS rh_avg,
avg(wind_avg_m_s) AS wind_avg_ms_avg,
max(wind_max_m_s) AS wind_gust_ms_max,
avg(wind_dir_deg) AS wind_dir_deg_avg,
max(uvi) AS uvi_max,
max(light_lux) AS light_lux_max,
avg(battery_mv) AS battery_mv_avg,
avg(supercap_v) AS supercap_v_avg
FROM observations_ws90
WHERE site = $1
AND bucket >= now() - make_interval(secs => $2)
AND ts >= $2
AND ts <= $3
GROUP BY bucket
ORDER BY bucket ASC
`, table)
`, interval)
rows, err := d.Pool.Query(ctx, query, site, rangeSeconds)
rows, err := d.Pool.Query(ctx, query, site, start, end)
if err != nil {
return nil, err
}
@@ -78,11 +84,11 @@ func (d *DB) ObservationSeries(ctx context.Context, site, bucket string, rangeSe
points := make([]ObservationPoint, 0, 512)
for rows.Next() {
var (
ts time.Time
temp, rh, wind, gust sql.NullFloat64
dir, uvi, light sql.NullFloat64
ts time.Time
temp, rh, wind, gust sql.NullFloat64
dir, uvi, light, battery, supercap sql.NullFloat64
)
if err := rows.Scan(&ts, &temp, &rh, &wind, &gust, &dir, &uvi, &light); err != nil {
if err := rows.Scan(&ts, &temp, &rh, &wind, &gust, &dir, &uvi, &light, &battery, &supercap); err != nil {
return nil, err
}
points = append(points, ObservationPoint{
@@ -94,6 +100,8 @@ func (d *DB) ObservationSeries(ctx context.Context, site, bucket string, rangeSe
WindDirDeg: nullFloatPtr(dir),
UVI: nullFloatPtr(uvi),
LightLux: nullFloatPtr(light),
BatteryMV: nullFloatPtr(battery),
SupercapV: nullFloatPtr(supercap),
})
}
if rows.Err() != nil {
@@ -113,7 +121,9 @@ func (d *DB) LatestObservation(ctx context.Context, site string) (*ObservationPo
wind_max_m_s,
wind_dir_deg,
uvi,
light_lux
light_lux,
battery_mv,
supercap_v
FROM observations_ws90
WHERE site = $1
ORDER BY ts DESC
@@ -121,11 +131,11 @@ func (d *DB) LatestObservation(ctx context.Context, site string) (*ObservationPo
`
var (
ts time.Time
temp, rh, wind, gust sql.NullFloat64
dir, uvi, light sql.NullFloat64
ts time.Time
temp, rh, wind, gust sql.NullFloat64
dir, uvi, light, battery, supercap sql.NullFloat64
)
err := d.Pool.QueryRow(ctx, query, site).Scan(&ts, &temp, &rh, &wind, &gust, &dir, &uvi, &light)
err := d.Pool.QueryRow(ctx, query, site).Scan(&ts, &temp, &rh, &wind, &gust, &dir, &uvi, &light, &battery, &supercap)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return nil, nil
@@ -142,6 +152,8 @@ func (d *DB) LatestObservation(ctx context.Context, site string) (*ObservationPo
WindDirDeg: nullFloatPtr(dir),
UVI: nullFloatPtr(uvi),
LightLux: nullFloatPtr(light),
BatteryMV: nullFloatPtr(battery),
SupercapV: nullFloatPtr(supercap),
}, nil
}