fix: restore station telemetry and make river flow visualization data-driven
Station selection showed no history since 21ca844: Chart.js v4 datasets
had parsing:false with plain number arrays, drawing empty axes. Remove
the flag so the chart parses values again.
Backend hardening for the same flow:
- /measurements/history/{code} no longer 503s on non-Postgres configs;
it falls back to the configured adapter (reversed to ascending order)
- DB_TYPE defaults to postgresql when POSTGRES_CONNECTION_STRING is set
and DB_TYPE is unset, so the .env psql wins over the sqlite default
- zero readings (0.0) are no longer coerced to None, which would fail
MeasurementResponse validation and 500 /measurements/latest
Map visualization:
- river segments are now colored, widened and dash-speed-animated by
the discharge at the nearest gauge (same scale as the marker legend)
- fix z-order bug that drew the animated flow line behind its casing
- legend entries for river lines, reduced-motion fallback
River geometry: rebuild ping-river-network.geojson from Overpass
(110 -> 202 features), restoring missing Ping mainstem reaches through
the Bhumibol reservoir and the Tak-Kamphaeng Phet braided section
(unnamed waterway=river ways in OSM), with short synthetic connectors
(connector: true) bridging remaining sub-8 km holes.
This commit is contained in:
+24
-13
@@ -454,7 +454,7 @@ async def get_postgres_history(
|
||||
hours: int = Query(168, ge=1),
|
||||
limit: int = Query(50000, ge=1, le=100000),
|
||||
):
|
||||
"""Get historical measurements for a station from PostgreSQL."""
|
||||
"""Get historical measurements for a station from the configured database."""
|
||||
cache_key = f"{station_code}:{hours}:{limit}"
|
||||
now = time.monotonic()
|
||||
with HISTORY_CACHE_LOCK:
|
||||
@@ -463,25 +463,36 @@ async def get_postgres_history(
|
||||
return cached[1]
|
||||
try:
|
||||
db_config = Config.get_database_config()
|
||||
if db_config["type"] != "postgresql":
|
||||
raise RuntimeError("PostgreSQL is not configured")
|
||||
history = PostgresHistory(db_config["connection_string"])
|
||||
end_time = datetime.now()
|
||||
data = await asyncio.to_thread(
|
||||
history.station_history,
|
||||
station_code,
|
||||
end_time - timedelta(hours=hours),
|
||||
end_time,
|
||||
limit,
|
||||
)
|
||||
if db_config["type"] == "postgresql":
|
||||
history = PostgresHistory(db_config["connection_string"])
|
||||
data = await asyncio.to_thread(
|
||||
history.station_history,
|
||||
station_code,
|
||||
end_time - timedelta(hours=hours),
|
||||
end_time,
|
||||
limit,
|
||||
)
|
||||
else:
|
||||
scraper = app_state["scraper"]
|
||||
if not scraper or not scraper.db_adapter:
|
||||
raise RuntimeError("Database not available")
|
||||
rows = await asyncio.to_thread(
|
||||
scraper.db_adapter.get_measurements_by_timerange,
|
||||
end_time - timedelta(hours=hours),
|
||||
end_time,
|
||||
[station_code],
|
||||
)
|
||||
# adapter returns newest-first; keep the newest `limit` rows, chart wants ascending
|
||||
data = list(reversed(rows[:limit]))
|
||||
with HISTORY_CACHE_LOCK:
|
||||
HISTORY_CACHE[cache_key] = (now, data)
|
||||
return data
|
||||
except RuntimeError as error:
|
||||
raise HTTPException(status_code=503, detail=str(error))
|
||||
except Exception as error:
|
||||
logger.error(f"Error fetching PostgreSQL history: {error}")
|
||||
raise HTTPException(status_code=502, detail="PostgreSQL history unavailable")
|
||||
logger.error(f"Error fetching measurement history: {error}")
|
||||
raise HTTPException(status_code=502, detail="Measurement history unavailable")
|
||||
|
||||
|
||||
@app.get("/measurements/latest", response_model=List[MeasurementResponse])
|
||||
|
||||
Reference in New Issue
Block a user