Fix periodic poll never finding new readings

extract_readings() only read the latestReading field embedded in the
stations-endpoint response. For some stations that field is always
null even though the measure's own /readings endpoint has current
data, so every non-backfill poll silently found 0 readings forever.
Now falls back to fetching the single latest reading directly from
the measure when the embedded field is missing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-05 01:41:02 +01:00
parent b1abac0f33
commit b7b2e7fc61

View File

@@ -160,7 +160,22 @@ def fetch_historical_readings(
return readings return readings
def extract_readings(stations: Iterable[dict]) -> list[Reading]: def fetch_latest_reading(session: requests.Session, measure_id: str) -> Optional[dict]:
"""Fetch a measure's single most recent reading directly. Some stations
never populate the stations-endpoint's embedded `latestReading` field,
even though the measure's own /readings endpoint has current data."""
try:
resp = session.get(
f"{measure_id}/readings", params={"_sorted": "", "_limit": 1}, timeout=15
)
resp.raise_for_status()
except requests.RequestException:
return None
items = resp.json().get("items", [])
return items[0] if items else None
def extract_readings(session: requests.Session, stations: Iterable[dict]) -> list[Reading]:
readings: list[Reading] = [] readings: list[Reading] = []
for station in stations: for station in stations:
station_id = station.get("stationReference") or station.get("@id", "").rsplit("/", 1)[-1] station_id = station.get("stationReference") or station.get("@id", "").rsplit("/", 1)[-1]
@@ -178,7 +193,10 @@ def extract_readings(stations: Iterable[dict]) -> list[Reading]:
for measure in measures: for measure in measures:
if measure.get("parameter") != "level": if measure.get("parameter") != "level":
continue continue
measure_id = measure.get("@id", "")
latest = measure.get("latestReading") latest = measure.get("latestReading")
if not latest and measure_id:
latest = fetch_latest_reading(session, measure_id)
if not latest: if not latest:
continue continue
readings.append( readings.append(
@@ -188,7 +206,7 @@ def extract_readings(stations: Iterable[dict]) -> list[Reading]:
river_name=river_name, river_name=river_name,
lat=lat, lat=lat,
lon=lon, lon=lon,
measure_id=measure.get("@id", ""), measure_id=measure_id,
unit=measure.get("unitName"), unit=measure.get("unitName"),
qualifier=measure.get("qualifier"), qualifier=measure.get("qualifier"),
value=latest.get("value"), value=latest.get("value"),
@@ -445,7 +463,7 @@ def poll_once(cfg: dict, session: requests.Session, verbose: bool = True, backfi
print(f"[{ts}] Backfilling {backfill_days} days of history for {len(stations)} stations...") print(f"[{ts}] Backfilling {backfill_days} days of history for {len(stations)} stations...")
readings = fetch_historical_readings(session, stations, backfill_days) readings = fetch_historical_readings(session, stations, backfill_days)
else: else:
readings = extract_readings(stations) readings = extract_readings(session, stations)
new_rows = store_readings(conn, readings) new_rows = store_readings(conn, readings)
if not no_html: if not no_html:
build_dashboard(conn, Path(cfg["output"])) build_dashboard(conn, Path(cfg["output"]))