A production industrial IoT system for real-time fuel dispensing measurement across a fleet of fuel trucks. Full stack: hardware signal conditioning → MicroPython firmware → Flask/SocketIO web HMI → MySQL database.
Live system — deployed across active fuel trucks in Columbus, Ohio operations.
Fuel trucks dispensing to heavy equipment need accurate, accountable metering. This system replaces manual dip-stick logging with real-time digital measurement — pulse-counting flowmeters feed a Pico 2 microcontroller, which streams JSON over USB serial to a Raspberry Pi CM5, which serves a live web HMI accessible from any tablet on the truck's WiFi hotspot.
┌──────────────────────────────────────────────────────────────┐
│ FUEL TRUCK │
│ │
│ [Flowmeter]──[Signal Conditioning]──[Pico 2] │
│ Macnaught PC817 Optoisolator MicroPython │
│ M40ARP-2-E7 ADC Schmitt Trigger Firmware │
│ NPN pulse out JSON over USB │
│ │ │
│ [Raspberry Pi CM5] │
│ Flask/SocketIO HMI │
│ SQLite local DB │
│ wlan0 ──┤├── eth0 │
│ │ │ │
│ [LTE Jetpack] [PoE Injector] │
│ internet 12V truck pwr │
│ SSH/Tailscale │ │
│ Cat6 in conduit │
│ │ │
│ [TP-Link EAP225-Outdoor] │
│ SAVKO-Fuel SSID │
│ covers tank area │
│ │ │
│ [Tablets] │
│ http://192.168.4.1:5000 │
└────────────────────────────────────────────────────┼─────────┘
│ Tailscale VPN
┌────────▼────────┐
│ Central Server │
│ MySQL Database │
│ SQLite → MySQL │
│ sync daemon │
└─────────────────┘
- Macnaught M40ARP-2-E7 — 1.5" oval gear flowmeter
- NPN transistor pulse output
- K-factor: 54.85 pulses/gallon (single-channel, empirically calibrated)
- PC817 optoisolator — galvanic isolation between flowmeter and Pi GPIO
- ADC-based pulse detection with software Schmitt trigger hysteresis
- Handles noisy industrial NPN outputs reliably
- Raspberry Pi CM5 — headless, truck-mounted in custom 3D-printed enclosure
- Raspberry Pi Pico 2 — dedicated pulse counting, MicroPython firmware
- USB serial communication between Pico 2 and CM5
- CM5 wlan0 connects to LTE Jetpack for internet (SSH, Tailscale sync to central server)
- CM5 eth0 feeds a 12V DC PoE injector (LINOVISION, truck ignition-switched circuit)
- Single Cat6 run in conduit to back of truck
- TP-Link EAP225-Outdoor AP mounted at tank area — broadcasts
SAVKO-FuelSSID - Tablets connect to AP and access HMI at
http://192.168.4.1:5000
Single-channel pulse counting with ADC-based Schmitt trigger:
# Schmitt trigger thresholds (empirically tuned)
HIGH_THRESHOLD = 40000 # ~3.2V — count rising edge
LOW_THRESHOLD = 20000 # ~1.6V — reset for next pulse
# Output: JSON over USB serial at 1Hz
{
"pulses": 1234,
"gallons": 5.94,
"flow_rate_gpm": 45.2,
"timestamp": 1718200000
}Key design decisions:
- ADC-based detection (not interrupt) — more robust against bounce and noise on long cable runs
- Schmitt trigger in software — eliminates need for external hysteresis components
- JSON serial protocol — easy to parse on CM5, easy to debug with any terminal
web_flowmeter.py — Flask/SocketIO HMI serving a real-time dispensing interface:
- Live gallon counter pushed via WebSocket to tablet browser
- Transaction logging (start/stop/total per fill)
- Equipment selection (which unit is being fueled)
- SQLite local storage — survives network outages
- Background sync daemon pushes completed transactions to central MySQL over Tailscale
Tablet-optimized interface accessible at http://truck-ip:5000:
- Large-format live gallon display
- Start / Stop / Reset controls
- Equipment selector (pulls from fleet management system)
- Transaction history for shift review
- Works offline — syncs when Tailscale connection is available
[Truck SQLite] ──── Tailscale VPN ────▶ [Central MySQL]
local first savko-fuelsysserver
survives gaps fleet-wide reporting
Sync daemon runs as systemd service, retries on connection failure, deduplicates on transaction ID.
- CM5 and Pico 2 mounted in custom 3D-printed enclosures (Creality K1)
- Designed for truck vibration and temperature cycling
- DIN rail compatible mounts for clean installation
- Custom KiCad PCB designed for signal conditioning circuit (JLCPCB fabricated)
| Unit | Status |
|---|---|
| TRK157 | ✅ Production |
| TRK163 | ✅ Production |
| Component | Technology |
|---|---|
| Microcontroller firmware | MicroPython (Pico 2) |
| Single-board computer | Raspberry Pi CM5, Linux |
| Web HMI | Python, Flask, SocketIO |
| Local database | SQLite |
| Central database | MySQL |
| Networking | Tailscale VPN, LTE Jetpack (wlan0), PoE + TP-Link EAP225-Outdoor (eth0) |
| PCB design | KiCad → JLCPCB |
| Enclosures | FDM 3D printing (Creality K1) |
Commercial fleet fuel management systems cost thousands per truck and lock you into proprietary hardware. This system was designed, built, and deployed in-house — total BOM per truck is under $200. The signal conditioning design went through several iterations after discovering reversed-polarity damage to flowmeter NPN outputs in early prototypes; the optoisolator stage now protects the hardware regardless of wiring errors in the field.
🟢 Production — running on active fuel trucks in daily operations.
Built by Keith Soderberg