diff --git a/cmd/ingestd/web/app.js b/cmd/ingestd/web/app.js index 994493b..ecf843c 100644 --- a/cmd/ingestd/web/app.js +++ b/cmd/ingestd/web/app.js @@ -23,6 +23,8 @@ const colors = { rainStart: "#f77f00", }; +const RAIN_HOURLY_THRESHOLD_MM = 0.1; + function formatNumber(value, digits) { if (value === null || value === undefined) { return "--"; @@ -101,7 +103,6 @@ function computeRainIncrements(points) { if (prev !== null) { delta = p.rain_mm - prev; if (delta < 0) delta = 0; - if (delta < 0.1) delta = 0; } prev = p.rain_mm; out.push({ x: t, y: delta }); @@ -119,7 +120,7 @@ function computeHourlySums(points, tz) { } return Array.from(buckets.entries()) .sort((a, b) => a[0] - b[0]) - .map(([x, y]) => ({ x, y: y < 0.1 ? 0 : y })); + .map(([x, y]) => ({ x, y: y < RAIN_HOURLY_THRESHOLD_MM ? 0 : y })); } function clampRainSeries(points, key) { @@ -372,6 +373,13 @@ function updateText(id, text) { if (el) el.textContent = text; } +function observationBucketSummary() { + if (state.range === "6h") { + return "obs bucket 1m (6h view)"; + } + return "obs bucket 5m (TimescaleDB-aligned)"; +} + function describeBarometer(pressure, trend) { if (pressure === null || pressure === undefined) { return "No barometer data yet."; @@ -649,7 +657,7 @@ function renderDashboard(data) { const forecastMeta = data.forecast && data.forecast.points && data.forecast.points.length ? `forecast retrieved ${formatDateTime(data.forecast.retrieved_at)}` : "forecast not available"; - updateText("forecast-meta", forecastMeta); + updateText("forecast-meta", `${forecastMeta} | ${observationBucketSummary()}`); if (latest) { updateText("live-temp", `${formatNumber(latest.temp_c, 2)} C`); @@ -852,7 +860,7 @@ function renderDashboard(data) { updateText("live-rain-hour", latestRainHour == null ? "--" : `${formatNumber(latestRainHour, 2)} mm`); const rainTitle = document.getElementById("chart-rain-title"); if (rainTitle) { - rainTitle.textContent = "Rain (obs hourly sum vs forecast)"; + rainTitle.textContent = `Rain (obs hourly sum from ${state.bucket} buckets vs forecast)`; } const forecastRain = clampRainSeries(forecastLine, "precip_mm"); @@ -861,7 +869,7 @@ function renderDashboard(data) { datasets: [ { type: "line", - label: "obs hourly sum (mm)", + label: `obs hourly sum (mm, ${state.bucket} buckets)`, data: rainHourly, borderColor: colors.rain, yAxisID: "y", diff --git a/internal/db/series.go b/internal/db/series.go index f9ebb7f..6b3959e 100644 --- a/internal/db/series.go +++ b/internal/db/series.go @@ -74,7 +74,7 @@ func (d *DB) ObservationSeries(ctx context.Context, site, bucket string, start, max(light_lux) AS light_lux_max, avg(battery_mv) AS battery_mv_avg, avg(supercap_v) AS supercap_v_avg, - avg(rain_mm) AS rain_mm_avg, + max(rain_mm) AS rain_mm_avg, max(rain_start) AS rain_start_max FROM observations_ws90 WHERE site = $1