Revive yaris-obd: USB OBD adapter, real GPS/GNSS, offline map, hotspot, SQLite logging, dashcam retrieval

Squashed rewrite of the project revival work (replaces prior history on this
branch to remove personal data that had been accidentally committed - real
LAN IP, GPS coordinates, home WiFi SSID, and phone model). See PLAN.md for
full phase-by-phase details. Summary:

- Phase 2: adapt app_obd.py for a USB OBD-II adapter (was Bluetooth-only),
  auto-detect /dev/ttyUSB*, fix several pre-existing crash bugs.
- Phase 3/4: make the web UI work fully offline (vendored Socket.IO/Leaflet/
  Chart.js/FontAwesome, offline map tile downloader script, live GPS marker
  tracking fix).
- Phase 5: systemd deployment/autostart on the Pi.
- Phase 6: WiFi hotspot mode via NetworkManager (auto-switch between home
  WiFi and a local AP for in-car web UI access), mDNS hostname + port 80
  redirect so the UI is reachable at a plain hostname with no port number.
- Phase 7: fix app_db.py/app_sql.py bugs, wire up local SQLite trip logging.
- Phase 8: brand-agnostic USB dashcam file retrieval (lsblk transport-based
  detection, works with any dashcam brand/folder layout).
- Rewritten readme.md with a proper project overview.

Co-authored-by: Copilot <[email protected]>
This commit is contained in:
Mathieu Moran
2026-08-08 18:01:35 -04:00
co-authored by Copilot
parent f91a3d479d
commit 261ef3f4db
46 changed files with 2150 additions and 255 deletions
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
# One-time install of the yaris-obd WiFi hotspot <-> home-WiFi auto-switch
# watcher on the Pi. Run this ON THE PI as the `yaris` user (needs sudo):
# cd /home/yaris/app/yaris-obd && bash deploy/install_netwatch.sh
#
# Prerequisite: the "home-wifi" (home WiFi) and "Hotspot" (AP mode) NetworkManager
# connection profiles must already exist (see PLAN.md Phase 6 for the nmcli
# commands used to create them) with home-wifi having a higher
# connection.autoconnect-priority than Hotspot.
set -euo pipefail
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
sudo install -m 755 "$REPO_DIR/deploy/yaris-netwatch.sh" /usr/local/bin/yaris-netwatch.sh
sudo cp "$REPO_DIR/deploy/yaris-netwatch.service" /etc/systemd/system/yaris-netwatch.service
sudo cp "$REPO_DIR/deploy/yaris-netwatch.timer" /etc/systemd/system/yaris-netwatch.timer
sudo systemctl daemon-reload
sudo systemctl enable --now yaris-netwatch.timer
echo "Done. Check status with: systemctl status yaris-netwatch.timer"
echo "Logs: journalctl -t yaris-netwatch -f"
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
# One-time install of the port-80 -> port-5000 redirect on the Pi, so the
# web UI is reachable at "http://yaris.local/" (or "http://<pi-ip>/") without
# typing the port number. Run this ON THE PI (needs sudo):
# cd /home/yaris/app/yaris-obd && bash deploy/install_port_redirect.sh
set -euo pipefail
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
NFT_FRAGMENT="/etc/nftables.yaris.conf"
NFT_MAIN="/etc/nftables.conf"
INCLUDE_LINE="include \"$NFT_FRAGMENT\""
sudo cp "$REPO_DIR/deploy/nftables-yaris.conf" "$NFT_FRAGMENT"
if ! grep -qF "$INCLUDE_LINE" "$NFT_MAIN"; then
echo "$INCLUDE_LINE" | sudo tee -a "$NFT_MAIN" > /dev/null
fi
sudo systemctl enable --now nftables.service
sudo systemctl restart nftables.service
echo "Done. Verify with: sudo nft list ruleset"
echo "Test with: curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/"
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
# One-time install of the yaris-obd systemd service on the Pi.
# Run this ON THE PI as the `yaris` user (needs sudo for the systemctl bits):
# cd /home/yaris/app/yaris-obd && bash deploy/install_service.sh
set -euo pipefail
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SERVICE_FILE="$REPO_DIR/deploy/yaris-obd.service"
SERVICE_NAME="yaris-obd.service"
if [ ! -d "$REPO_DIR/venv" ]; then
echo "No venv found at $REPO_DIR/venv - creating one and installing requirements..."
python3 -m venv "$REPO_DIR/venv"
"$REPO_DIR/venv/bin/pip" install --upgrade pip
"$REPO_DIR/venv/bin/pip" install -r "$REPO_DIR/requirements.txt"
fi
sudo cp "$SERVICE_FILE" "/etc/systemd/system/$SERVICE_NAME"
sudo systemctl daemon-reload
sudo systemctl enable "$SERVICE_NAME"
sudo systemctl restart "$SERVICE_NAME"
echo "Done. Check status with: sudo systemctl status $SERVICE_NAME"
echo "Logs: tail -f $REPO_DIR/yaris-obd.log (or: sudo journalctl -u $SERVICE_NAME -f)"
+10
View File
@@ -0,0 +1,10 @@
# Redirects incoming HTTP traffic on port 80 to the yaris-obd app (port 5000),
# so the web UI is reachable at "http://yaris.local/" or "http://<pi-ip>/"
# without needing to type the port number. Loaded by /etc/nftables.conf via
# an `include` directive (see deploy/install_port_redirect.sh).
table ip nat {
chain prerouting {
type nat hook prerouting priority -100;
tcp dport 80 redirect to :5000
}
}
+8
View File
@@ -0,0 +1,8 @@
[Unit]
Description=yaris-obd network watcher (hotspot -> home WiFi reconnect check)
After=NetworkManager.service
Wants=NetworkManager.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/yaris-netwatch.sh
+47
View File
@@ -0,0 +1,47 @@
#!/bin/bash
# yaris-netwatch.sh
#
# Runs periodically via yaris-netwatch.timer. If wlan0 is currently in
# AP/hotspot mode, briefly attempts to reconnect to the known home WiFi.
# If that succeeds, we're back on home WiFi (used for syncing itinerary/
# dashcam data to the remote server). If it fails (still out of range),
# reactivates the hotspot so the web UI stays reachable locally in the car.
#
# The Pi's onboard WiFi radio (BCM43438) cannot act as an AP and scan for
# client networks at the same time, so this brief switch-and-check is the
# only way to detect "home WiFi is back in range" while sitting in AP mode.
# The reverse direction (home WiFi -> hotspot, i.e. leaving range) is handled
# automatically by NetworkManager's own autoconnect-priority mechanism and
# needs no watcher: the "home-wifi" profile has a higher
# connection.autoconnect-priority than Hotspot, so NM tries it first whenever
# the device needs to reconnect, and falls through to Hotspot on its own once
# home WiFi drops out of range.
set -u
LOG_TAG="yaris-netwatch"
HOME_CON="home-wifi"
AP_CON="Hotspot"
IFACE="wlan0"
LAST_LOG="/tmp/yaris-netwatch-last.log"
active_con() {
nmcli -t -f DEVICE,CONNECTION device status | awk -F: -v d="$IFACE" '$1==d {print $2}'
}
current="$(active_con)"
if [ "$current" != "$AP_CON" ]; then
# Already on home WiFi (or something else) - nothing to do.
logger -t "$LOG_TAG" "wlan0 is on '$current', no action needed"
exit 0
fi
logger -t "$LOG_TAG" "wlan0 is on hotspot, checking for home WiFi ($HOME_CON)..."
if nmcli --wait 20 con up "$HOME_CON" >"$LAST_LOG" 2>&1; then
logger -t "$LOG_TAG" "home WiFi found, switched to '$HOME_CON'"
else
logger -t "$LOG_TAG" "home WiFi not found, restoring hotspot"
nmcli con up "$AP_CON" >>"$LAST_LOG" 2>&1
fi
+11
View File
@@ -0,0 +1,11 @@
[Unit]
Description=Periodically check if home WiFi is back in range while in hotspot mode
[Timer]
OnBootSec=1min
OnUnitActiveSec=3min
AccuracySec=15s
Unit=yaris-netwatch.service
[Install]
WantedBy=timers.target
+22
View File
@@ -0,0 +1,22 @@
[Unit]
Description=Yaris OBD/GPS tracker web UI
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=yaris
Group=yaris
WorkingDirectory=/home/yaris/app/yaris-obd
ExecStart=/home/yaris/app/yaris-obd/venv/bin/python app.py
Restart=on-failure
RestartSec=5
# Give the app a few seconds after boot for USB/serial devices to enumerate
# before the first connection attempt - it retries gracefully either way,
# but this avoids needless noisy "no connection" logs on every cold boot.
ExecStartPre=/bin/sleep 5
StandardOutput=append:/home/yaris/app/yaris-obd/yaris-obd.log
StandardError=append:/home/yaris/app/yaris-obd/yaris-obd.log
[Install]
WantedBy=multi-user.target