Skip to content

SteffEng-lab/Microtransit_Tracking

Repository files navigation

OpenTrack GPS Platform

Real-time GPS tracking platform for the MicroTransit Innovation Challenge — Florida Polytechnic University

An end-to-end cellular GPS tracking system: an Arduino-based hardware tracker publishes live telemetry over the Hologram IoT cellular network to a self-hosted MQTT broker, a Python backend stores and broadcasts every update in real time, and a browser dashboard renders live vehicle positions on an interactive map.


Screenshots

Live map with route polyline Route with multiple segments

Dark mode with satellite view Mobile dashboard

More screenshots — Devices, Alerts, History, Settings

Devices table view Alerts event log

History replay Settings drawer


Architecture

Arduino Uno + SIM7000A
  └─ GPS + cellular (Hologram IoT SIM)
  └─ publishes JSON over MQTT (port 1883)
        │
        ▼
  Mosquitto MQTT Broker  (Docker, public VPS)
        │
        ▼
  Python Backend  (FastAPI + paho-mqtt + SQLite)
  └─ Kalman filter → SQLite → WebSocket broadcast
        │
        ▼
  Browser Dashboard  (Next.js 16 + Leaflet.js)

Three-tier architecture diagram


Features

Firmware (Arduino)

Feature Description
GPS + cellular botletics SIM7000A shield — GPS and GPRS in one
RAM-efficient JSON Hand-written dtostrf-based builder; no ArduinoJSON heap bloat
EEPROM offline buffer 56-entry circular buffer — stores fixes during outages, flushes on reconnect
Hardware watchdog 8 s WDTO_8S — chip-level MCU reset on any software hang
Layered auto-reconnect Network → GPRS → MQTT; full modem reinit when buffer fills (≈ 18 min)
Last Will message Broker publishes "offline" within ~20 s of unexpected disconnect
Remote rate control Dashboard can change the GPS publish interval without reflashing
GPS valid flag gps_valid: false payloads keep the heartbeat alive when no fix is held

Backend (Python)

Feature Description
MQTT subscriber paho-mqtt daemon thread, thread-safe WebSocket bridge
Kalman filter Server-side 2-D constant-velocity model — smooths GPS noise per device
SQLite persistence 3 tables: devices, positions, alerts — survives restarts
Route segmentation segment_id increments on GPS loss or reconnect — no false polyline gaps
Alert logging Online/offline and GPS fix/lost events with timestamps
REST API /api/devices, /api/history, /api/alerts, /api/get_rate, /api/set_rate
WebSocket Real-time push for location and status messages
Docker deployment Three containers via Docker Compose: Mosquitto, Python backend, Next.js frontend

Dashboard (Next.js)

Feature Description
Live map Leaflet.js markers update in real time on every WebSocket push
Route polylines Per-device breadcrumb trail, broken correctly on GPS loss
Multi-device Each device gets a distinct color; new devices appear automatically
Device panel Collapsible cards — coordinates, speed, battery, GPS state, last seen
Fleet stats Online count, GPS count, average/max speed, average/min battery
Navigation tabs Map · Devices · History (replay) · Alerts
Settings Map style, speed/battery units, publish rate, per-device labels
Dark / light mode Warm aerospace light theme + soft dark theme
Mobile support Fully responsive — works on phone without a separate app

Repository Layout

.
├── 01_Documents/
│   ├── 01_Proposal/          # Phase 1 proposal (Typst source + PDF)
│   ├── 02_Midprogress_Report/
│   ├── 03_Final_Report/      # Final report (Typst source + compiled PDF)
│   ├── 04_Media/             # Demo screenshots
│   └── 05_Presentation/      # Slide deck
│
├── 02_Arduino_Code/
│   └── MicroTransit_Tracking_Arduino_Code/
│       └── src/
│           ├── main.cpp      # Main loop — state machine, WDT, EEPROM flush
│           ├── modem.cpp/h   # TinyGSM init, GPS read, battery read
│           ├── mqtt.cpp/h    # PubSubClient connect, callback, Last Will
│           ├── buffer.cpp/h  # EEPROM circular buffer
│           ├── payload.cpp/h # Hand-written JSON builder
│           └── config.h      # All pins, APN, broker, timing constants
│
├── 03_Backend/
│   ├── backend.py            # MQTT subscriber + Kalman filter integration
│   ├── websocket.py          # FastAPI app, REST endpoints, WebSocket server
│   ├── database.py           # SQLite helpers
│   ├── kalman.py             # 2-D constant-velocity Kalman filter
│   ├── config.py             # Broker host/port/credentials, topic names
│   └── simulate_GPS_payload.py  # Device emulator for testing
│
└── 04_Frontend/
    ├── app/                  # Next.js app router (layout, page)
    ├── components/           # Map, DevicePanel, StatsPanel, TopNav, Settings
    │   └── views/            # DeviceTable, HistoryView, AlertsView
    ├── hooks/useTracker.ts   # WebSocket state machine
    ├── contexts/             # Settings context (localStorage persistence)
    └── types/index.ts        # Shared TypeScript types

Hardware

Assembled shield Assembled shield

Component Part
Microcontroller Arduino Uno (ATmega328P, 2 KB SRAM)
Cellular + GPS shield botletics SIM7000A
SIM card Hologram IoT SIM (APN: hologram)
GPS antenna Active antenna via bridge jumper on shield
Power 2x 3.7 V LiPo (cellular module) + Arduino power
Wiring SoftwareSerial TX/RX on D10/D11; PWRKEY D6; RST D7

Quick Start

1 — Arduino Firmware

Requirements: PlatformIO (VS Code extension or CLI)

cd 02_Arduino_Code/MicroTransit_Tracking_Arduino_Code

Edit src/config.h:

#define DEVICE_ID     "tracker-01"
#define APN_SETTING   "hologram"       // your SIM's APN
#define MQTT_HOST     "your.server.ip"
#define MQTT_PORT     1883
#define MQTT_USER     "mosquitto"
#define MQTT_PASSWORD "your_password"

Flash with PlatformIO:

pio run --target upload

The built-in LED lights when a valid GPS fix is held.


2 — Full Stack (Docker Compose)

Requirements: Docker with the Compose plugin

cp .env.example .env          # edit .env with your broker credentials
docker compose up -d

This starts three containers: mosquitto (port 1883), backend (port 8000), and frontend (port 3000).

Open http://localhost:3000.

Run without Docker

Requirements: uv, a running Mosquitto broker

Edit 03_Backend/config.py to match your broker, then:

cd 03_Backend
uv sync
uv run python backend.py      # starts MQTT subscriber + FastAPI server

3 — Frontend (development)

The frontend is included in the Docker Compose setup above. To run it separately in dev mode:

Requirements: Node.js 20+ / Bun

cd 04_Frontend
bun install        # or: npm install
bun run dev        # or: npm run dev

Open http://localhost:3000. The dashboard connects to the backend WebSocket automatically (configure the URL in hooks/useTracker.ts if needed).


4 — Device Simulation for Testing (optional)

To simulate a device without hardware:

uv run python simulate_GPS_payload.py

Telemetry Payload

The Arduino publishes one JSON message per cycle to tracker/{device_id}/location:

{
  "device_id": "tracker-01",
  "battery_mv": 3921,
  "gps_valid": true,
  "lat": 28.150612,
  "lng": -81.847583,
  "speed_kmh": 14.3,
  "timestamp": "2026-04-11T18:42:07Z"
}

When no GPS fix is available, only device_id, battery_mv, and gps_valid: false are sent — keeping the heartbeat alive without polluting the position history.


API Reference

Endpoint Method Description
/api/devices GET All devices with online state, GPS state, battery, last seen
/api/history/{device_id} GET Full position history ordered by timestamp
/api/alerts GET Most recent 500 online/offline and GPS fix/lost events
/api/get_rate GET Current GPS publish interval (seconds)
/api/set_rate/{device_id} POST {"rate": N} — update interval over MQTT without reflashing
/ws WebSocket Real-time push: location and status message types

Notes

  • TLS: The SIM7000A firmware on the provided hardware does not support AT+CNACT / AT+CIPSSL, so the broker uses plain TCP on port 1883 with username/password authentication. Switching to a TLS-capable managed broker (HiveMQ Cloud, Flespi.io) requires changing two lines in config.h and one block in config.py.
  • Multi-device: Each additional tracker needs only a unique DEVICE_ID in config.h. The broker, backend, and dashboard require no changes.
  • Kalman filter: Applied server-side before each position is saved to SQLite. Tuned for near-pass-through behaviour (R = 1×10⁻⁹) — smooths GPS jitter without lagging behind the vehicle.

Documents

Document Link
Wiring Instructions Wiring_Instructions.md
Backend README README.md
Final Report final_report.pdf
Proposal tracking_proposal.pdf
Mid-Progress Report MicroTransitTracking_Midprogress_Report.pdf
Presentation OpenTrack_Presentation.pptx

2026 Steffen Ullmann · sullmann3121@floridapoly.edu · Florida Polytechnic University · MicroTransit Innovation Challenge

About

Real-time cellular GPS tracking platform: Arduino + SIM7000A firmware, Python/FastAPI backend with Kalman filtering, and a Next.js live map dashboard.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors