diff --git a/BUGS.md b/BUGS.md index 6950b54..3728f6b 100644 --- a/BUGS.md +++ b/BUGS.md @@ -35,11 +35,13 @@ When CLOSED, move the entire entry to Resolved — don't duplicate. (`insert_tracking(gps_x, gps_y, speed=None, …)`) — there is no GPS-derived speed fallback, so the SPEED column stays NULL and the replay shows 0.0 km/h (`speed_source="gps"`). - **Data**: trip #9 has 723 points — 570 with OBD speed, 25 with speed=0, 128 with NULL speed. -- **Fix (proposed)**: - 1. GPS-speed fallback in `_log_loop()` — when OBD speed is None/0 but GPS coords exist, - compute speed from the previous position (haversine / elapsed time) and log that as SPEED, - so the replay shows the real speed (sourced "gps"). - 2. Investigate why the OBD adapter didn't recover for ~20 min (reconnect on stalled reads). +- **Fix**: mirror the Pi's `route_points` GPS-speed fallback in the server's `get_trip_route()` + (`server/modules/db.py`) — when OBD speed is missing, derive speed from the previous point's + movement (haversine / elapsed time, ≥8 m, ≤220 km/h) so the replay shows the real speed + instead of flatlining at 0 km/h. (The Pi's own replay already did this; only the portal was + missing it.) +- **Follow-up**: investigate why the OBD adapter didn't recover for ~20 min (reconnect on + stalled reads). --- diff --git a/PLAN.md b/PLAN.md index a7564af..2b7afbb 100644 --- a/PLAN.md +++ b/PLAN.md @@ -2282,10 +2282,10 @@ logged as `BUG-XX` entries in [BUGS.md](./BUGS.md) (BUG-16 onward) and fixed + v - **BUG-20 (server trip IDs inflate) — ✅ FIXED**: `trips.id BIGSERIAL` burned sequence values on every upsert (recompute after each upload batch). Fixed: sequence clamped to `MAX(id)` after each recompute + one-time renumber migration — trips now 1..10, sequence at 10. -- **BUG-21 (OBD speed dropout mid-drive) — OPEN**: ELM327 stopped returning speed for ~20 min - on 2026-08-13 (22:23:50→22:43:41 UTC); Pi logged NULL speed (no GPS-speed fallback), so the - replay shows 0 km/h for that stretch. Proposed: GPS-speed fallback in `_log_loop()` + OBD - reconnect on stalled reads. +- **BUG-21 (OBD speed dropout mid-drive) — 🚧 IN PROGRESS**: ELM327 stopped returning speed for + ~20 min on 2026-08-13 (22:23:50→22:43:41 UTC). Fix: server `get_trip_route()` now mirrors the + Pi's GPS-speed fallback (derive speed from consecutive GPS points when OBD speed is missing), + so the portal replay no longer flatlines at 0 km/h. Follow-up: OBD reconnect on stalled reads. Open items from the drive — fill in as reported: - (none clock-related — BUG-17/BUG-18 closed 2026-08-14). diff --git a/server/modules/db.py b/server/modules/db.py index 2850b3f..9a7c3b8 100644 --- a/server/modules/db.py +++ b/server/modules/db.py @@ -617,9 +617,20 @@ def get_trip_route(device_id, trip_id): lon = float(p[2]) speed = p[3] or 0 raw_odo = p[4] + speed_source = "obd" if speed > 0 else "gps" + # Mirror the Pi's route_points GPS-speed fallback: when OBD speed is + # missing (adapter dropout), derive speed from the previous point's + # movement so the replay doesn't flatline at 0 km/h while the car moves. + if speed <= 0 and prev is not None: + seconds = (p[0] - prev[2]).total_seconds() + if seconds > 0: + dist_km = hav(prev[0], prev[1], lat, lon) + seg_speed = dist_km / seconds * 3600 + if seg_speed <= 220 and dist_km * 1000 >= 8: + speed = seg_speed if prev is not None: cumulative += hav(prev[0], prev[1], lat, lon) - prev = (lat, lon) + prev = (lat, lon, p[0]) if raw_odo is not None and float(raw_odo) > 0: odometer = float(raw_odo) else: @@ -628,10 +639,10 @@ def get_trip_route(device_id, trip_id): "datetime": p[0].isoformat(), "latitude": lat, "longitude": lon, - "speed": speed, + "speed": round(speed, 1), # Mirror the Pi's route_points: OBD speed when we have it, # otherwise the point is sourced from GPS. - "speed_source": "obd" if speed > 0 else "gps", + "speed_source": speed_source, "odometer": round(odometer, 1), }) return {