Files
yaris-obd/templates/dash.html
T
Mathieu MoranandCopilot 6d61b70a06 Add SIM868 cellular fallback for tracking uploads (untested, no SIM card)
modules/app_cellular.py: uses the SIM868's built-in AT-command HTTP(S)
client (AT+HTTPINIT/HTTPPARA/HTTPACTION/HTTPREAD) instead of a real
ppp0 interface, since the module's GNSS (polled continuously by
app_gps.py) and its GSM/GPRS radio share the same physical UART
(/dev/serial0) - a pppd/chat dial-up would take over that port
entirely and starve GNSS polling. Staying in AT-command mode lets
cellular HTTP calls interleave safely through the same serial lock.

Only carries small JSON tracking batches, never dashcam video -
cellular is far too slow/limited for that, and the modem's HTTP AT
interface has too small an internal buffer anyway. Dashcam uploads
remain WiFi/Ethernet-only, unchanged.

modules/app_upload.py: tracking-batch upload always tries WiFi/
Ethernet first; only on a connection-level failure (not an HTTP error
status, which means the server was reached) does it retry over
cellular. Exposes last_network_path/cellular_fallback_configured in
/api/upload/status; UI shows which path the last batch used.

Feature-flagged off by default via new YARIS_CELLULAR_ENABLED/
YARIS_CELLULAR_APN/_APN_USER/_APN_PASS keys in db/upload_creds.env
(all blank by default) - has zero effect on the existing WiFi upload
path unless explicitly configured. Regression-tested against the real
deployed server that normal WiFi uploads are unaffected while
cellular stays unconfigured.

*** UNTESTED against real cellular hardware - no SIM card was
*** available. See docstrings in app_cellular.py and PLAN.md for
*** exactly what needs validation once a SIM card is available.

Co-authored-by: Copilot <[email protected]>
2026-08-08 20:34:53 -04:00

115 lines
7.9 KiB
HTML

<!DOCTYPE html>
<html data-bs-theme="light" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>Dashboard - yaris vroom vroom de course</title>
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap/css/bootstrap.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='yaris.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='fonts/fontawesome-all.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='vendor/leaflet/leaflet.css') }}">
</head>
<body id="page-top">
<div id="wrapper">
<nav class="navbar align-items-start sidebar sidebar-dark accordion bg-gradient-primary p-0 navbar-dark" style="color: var(--bs-accordion-btn-focus-border-color);background: rgb(0,0,0);filter: blur(0px);backdrop-filter: blur(0px) hue-rotate(0deg);">
<div class="container-fluid d-flex flex-column p-0"><a class="navbar-brand d-flex justify-content-center align-items-center sidebar-brand m-0" href="#">
<div class="sidebar-brand-icon rotate-n-15"><i class="fas fa-car"></i></div>
<div id="index-car-model" class="sidebar-brand-text mx-3"><span>{{ car.model }}</span></div>
</a>
<hr class="sidebar-divider my-0">
<ul class="navbar-nav text-light" id="accordionSidebar">
<li class="nav-item"><a class="nav-link" href="/"><i class="fas fa-tachometer-alt"></i><span>Dashboard</span></a></li>
<li class="nav-item"></li>
<li class="nav-item"><a class="nav-link active" href="/dash"><i class="fas fa-table"></i><span>Dashcam&nbsp;</span></a></li>
<li class="nav-item"></li>
<li class="nav-item"><a class="nav-link" href="/dtc"><i class="fas fa-table"></i><span>DTC&nbsp;</span></a></li>
</ul>
<div class="text-center d-none d-md-inline"><button class="btn rounded-circle border-0" id="sidebarToggle" type="button"></button></div>
</div>
</nav>
<div class="d-flex flex-column" id="content-wrapper">
<div id="content">
<nav class="navbar navbar-expand bg-white shadow mb-4 topbar static-top navbar-light">
<div class="container-fluid"><button class="btn btn-link d-md-none rounded-circle me-3" id="sidebarToggleTop" type="button"><i class="fas fa-bars"></i></button>
<form class="d-none d-sm-inline-block me-auto ms-md-3 my-2 my-md-0 mw-100 navbar-search">
<div class="input-group"></div>
</form>
<ul class="navbar-nav flex-nowrap ms-auto">
<li class="nav-item dropdown d-sm-none no-arrow"><a class="dropdown-toggle nav-link" aria-expanded="false" data-bs-toggle="dropdown" href="#"><i class="fas fa-search"></i></a>
<div class="dropdown-menu dropdown-menu-end p-3 animated--grow-in" aria-labelledby="searchDropdown">
<form class="me-auto navbar-search w-100">
<div class="input-group"><input class="bg-light form-control border-0 small" type="text" placeholder="Search for ...">
<div class="input-group-append"><button class="btn btn-primary py-0" type="button"><i class="fas fa-search"></i></button></div>
</div>
</form>
</div>
</li>
<div class="d-none d-sm-block topbar-divider"></div>
<li class="nav-item dropdown no-arrow">
<div class="nav-item dropdown no-arrow"><a class="dropdown-toggle nav-link" aria-expanded="false" data-bs-toggle="dropdown" href="#"><span id="index-pp" class="d-none d-lg-inline me-2 text-gray-600 small">{{ account.name }}</span><img class="border rounded-circle img-profile" src="{{ url_for('static', filename='img/yaris.png') }}"></a>
</div>
<div class="shadow dropdown-list dropdown-menu dropdown-menu-end" aria-labelledby="alertsDropdown"></div>
</li>
<div class="d-none d-sm-block topbar-divider"></div>
</ul>
</div>
</nav>
<div class="container-fluid">
<h3 class="text-dark mb-4">Dashcam</h3>
<div class="card shadow mb-4">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Detected device</p>
</div>
<div class="card-body">
<p id="dash-device-status">Checking for a USB dashcam...</p>
<button id="dash-scan-btn" class="btn btn-secondary" type="button">Scan for dashcam</button>
<button id="dash-import-btn" class="btn btn-primary" type="button" disabled>Import videos</button>
</div>
</div>
<div class="card shadow mb-4">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Import results</p>
</div>
<div class="card-body">
<p id="dash-import-status">No import has been run yet.</p>
</div>
</div>
<div class="card shadow">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Remote server upload</p>
</div>
<div class="card-body">
<p id="upload-status">Checking upload status...</p>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="dashcam-upload-toggle" disabled>
<label class="form-check-label" for="dashcam-upload-toggle">
Upload dashcam videos to remote server
</label>
</div>
<p class="text-muted small mt-2 mb-0">
Trip/GPS log uploads always stay on. Turning this off only pauses
the (larger) dashcam video uploads - useful on a slow or metered
connection. If configured, small trip-log batches can also fall
back to the SIM868's cellular data when WiFi/Ethernet is
unreachable - dashcam video never uses cellular.
</p>
</div>
</div>
</div>
</div>
<footer class="bg-white sticky-footer">
<div class="container my-auto">
<div class="text-center my-auto copyright"><span>Copyright © yaris vroom vroom de course 2023</span></div>
</div>
</footer>
</div><a class="border rounded d-inline scroll-to-top" href="#page-top"><i class="fas fa-angle-up"></i></a>
</div>
<script src="{{ url_for('static', filename='js/dash.js') }}"></script>
<script src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/bs-init.js') }}"></script>
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
</body>
</html>