feat: log OBD speed before GPS fix so rolling starts aren't lost

- _log_loop: when GPS has no fix but OBD speed > 1, write speed-only rows
  (NULL coordinates) instead of dropping the motion
- insert_tracking: accept None gps_x/gps_y -> NULL GPSX/GPSY
- app_trip: keep NULL-coord rows through normalize; _segment returns 0 for
  missing coords; route_points drops them (no position to draw)
- tests: speed-only rows build a trip with max speed + zero distance
- docs: FEAT-12 + readme note; server already filters NULL-GPS safely
This commit is contained in:
Mathieu Moran
2026-08-13 02:02:45 -04:00
parent fa8ae0001a
commit 3d49764855
5 changed files with 64 additions and 6 deletions
+19 -3
View File
@@ -314,7 +314,11 @@ def count_active_dtcs():
def insert_tracking(gps_x, gps_y, speed, odometer=None):
"""Insert a single trip-tracking snapshot row (GPS position + speed)."""
"""Insert a single trip-tracking snapshot row (GPS position + speed).
gps_x/gps_y may be None (logged before the first GPS fix) — the row then
stores NULL coordinates and relies on OBD speed for motion detection.
"""
conn = get_conn()
if conn is None:
return False
@@ -323,8 +327,14 @@ def insert_tracking(gps_x, gps_y, speed, odometer=None):
VALUES (?, ?, ?, ?, ?, ?, ?)"""
with _conn_lock:
try:
latitude = float(str(gps_x).replace("\x00", "").strip())
longitude = float(str(gps_y).replace("\x00", "").strip())
latitude = (
None if gps_x is None
else float(str(gps_x).replace("\x00", "").strip())
)
longitude = (
None if gps_y is None
else float(str(gps_y).replace("\x00", "").strip())
)
conn.execute(
sql,
(car.model, account.name, datetime.now(), latitude, longitude, speed, odometer),
@@ -847,6 +857,12 @@ def _log_loop():
) and insert_tracking(position[0], position[1], speed, app_obd.odometer):
last_position = position
last_logged_at = now
elif speed is not None and speed > 1:
# No GPS fix yet but the car is moving (OBD speed) — log a
# speed-only row so a rolling start / mid-drive reboot isn't lost.
# Coordinates stay NULL until the first fix; trip building treats
# these as OBD-motion events with zero GPS distance.
insert_tracking(None, None, speed, app_obd.odometer)
time.sleep(LOG_INTERVAL)