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:
+19
-3
@@ -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)
|
||||
|
||||
|
||||
+12
-2
@@ -47,9 +47,11 @@ def normalize_tracking_rows(rows):
|
||||
longitude = _number(row[3])
|
||||
speed = _number(row[4]) or 0
|
||||
odometer = _number(row[5]) if len(row) > 5 else None
|
||||
if timestamp is None or latitude is None or longitude is None:
|
||||
if timestamp is None:
|
||||
continue
|
||||
if not (-90 <= latitude <= 90 and -180 <= longitude <= 180):
|
||||
if latitude is not None and not (-90 <= latitude <= 90):
|
||||
continue
|
||||
if longitude is not None and not (-180 <= longitude <= 180):
|
||||
continue
|
||||
normalized.append({
|
||||
"id": int(row[0]),
|
||||
@@ -66,6 +68,11 @@ def _segment(row, previous):
|
||||
seconds = (row["datetime"] - previous["datetime"]).total_seconds()
|
||||
if seconds <= 0:
|
||||
return 0, 0
|
||||
if (
|
||||
previous["latitude"] is None or previous["longitude"] is None
|
||||
or row["latitude"] is None or row["longitude"] is None
|
||||
):
|
||||
return 0, 0
|
||||
distance_km = haversine_km(
|
||||
(previous["latitude"], previous["longitude"]),
|
||||
(row["latitude"], row["longitude"]),
|
||||
@@ -218,6 +225,9 @@ def build_trip_summaries(raw_rows):
|
||||
|
||||
def route_points(raw_rows, max_points=2000, odometer_baseline=0.0, prior_km=0.0):
|
||||
rows = normalize_tracking_rows(raw_rows)
|
||||
# The route polyline needs coordinates — drop speed-only rows logged before
|
||||
# the first GPS fix (no position to draw; they add 0 distance anyway).
|
||||
rows = [r for r in rows if r["latitude"] is not None and r["longitude"] is not None]
|
||||
filtered_rows = []
|
||||
for row in rows:
|
||||
if filtered_rows:
|
||||
|
||||
Reference in New Issue
Block a user