feat: FEAT-05 — DTC history sync to remote server
- Server: dtc_events table (migrate_phase27_dtc.sql), db.py helpers (upsert_dtc_snapshot, list_dtc_events, delete_dtc_event) - Server API: POST /api/v1/dtc/batch (device auth), GET/DELETE /api/v1/portal/dtc - Server portal: /dtc page with code, description, MIL, status, timestamps, delete - Server nav: DTC history in sidebar + mobile bottom nav - Pi: _upload_dtc_snapshot() in app_upload.py — uploads when snapshot changes, skips when OBD disconnected or unchanged
This commit is contained in:
@@ -310,6 +310,50 @@ def _upload_dashcam_files():
|
||||
return uploaded_count
|
||||
|
||||
|
||||
_last_dtc_hash = None # tracks last-uploaded DTC snapshot to avoid redundant pushes
|
||||
|
||||
|
||||
def _upload_dtc_snapshot():
|
||||
"""Upload current DTC snapshot to server if it differs from last upload.
|
||||
Skips when OBD is disconnected (no point sending empty snapshots that
|
||||
would clear all server-side DTC events)."""
|
||||
global _last_dtc_hash
|
||||
import hashlib as _hl
|
||||
from . import app_obd, app_sql
|
||||
|
||||
# Only upload when OBD is actually connected — don't clear server DTCs
|
||||
# just because the Pi rebooted or the adapter is unplugged.
|
||||
if app_obd.connection is None:
|
||||
return
|
||||
|
||||
mil_on = app_obd.mil_on
|
||||
codes = app_obd.dtc_codes or []
|
||||
if not codes and mil_on is None:
|
||||
return # No data yet
|
||||
|
||||
# Hash the current snapshot to detect changes
|
||||
payload = {"mil_on": bool(mil_on), "codes": codes}
|
||||
h = _hl.sha256(repr(payload).encode()).hexdigest()
|
||||
if h == _last_dtc_hash:
|
||||
return
|
||||
_last_dtc_hash = h
|
||||
|
||||
try:
|
||||
creds = _credentials()
|
||||
if not creds["server_url"] or not creds["device_name"] or not creds["api_key"]:
|
||||
return
|
||||
resp = requests.post(
|
||||
f"{creds['server_url']}/api/v1/dtc/batch",
|
||||
json=payload,
|
||||
headers=_headers(creds),
|
||||
timeout=5,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
except requests.RequestException:
|
||||
_last_dtc_hash = None # retry next cycle
|
||||
raise
|
||||
|
||||
|
||||
def _upload_loop():
|
||||
global _last_error, _last_success_at
|
||||
import datetime as _dt
|
||||
@@ -323,6 +367,7 @@ def _upload_loop():
|
||||
sent = _upload_tracking_batch()
|
||||
uploaded = _upload_dashcam_files()
|
||||
cleanup = app_video.cleanup_uploaded_videos()
|
||||
_upload_dtc_snapshot() # silently skips when unchanged or OBD offline
|
||||
if sent or uploaded:
|
||||
print(f"Upload: sent {sent} tracking rows, {uploaded} dashcam files")
|
||||
if cleanup["deleted"]:
|
||||
|
||||
Reference in New Issue
Block a user