CUSTOM MOBILE APP • ANDROID • FLUTTER • OBD-II
🍋 Lemon OBD Car Scanner
A Flutter Android app that queries your car’s ECU directly —
auto-detects exactly which parameters your vehicle supports.
No guessing. No subscriptions. Zero server cost.

Dashboard

Live Data

Fault Codes
14
Car Brands
121+
Models
20
OBD-II PIDs
$0
Server Cost
THE PROBLEM
What’s wrong with existing OBD-II apps?
Most apps guess which parameters your car supports — and get it wrong.
❌
Parameters are assumed, not verified
Static databases guess what your car supports. No mechanism to discover what the ECU actually exposes.
❌
Wrong data with false confidence
Sensors shown that don’t exist. Sensors hidden that do. Users never know which is which.
❌
Dashboard ≠ Live Data
Different screens show different parameters. Confusing, untrustworthy, and a sign of poor architecture.
❌
Paywalled standard data
Subscriptions for data the OBD-II standard makes freely available to anyone with an adapter.
THE SOLUTION
Ask the car. Don’t guess.
“Instead of guessing, Lemon OBD sends four OBD-II bitmask requests (0x00, 0x20, 0x40, 0x60) — each returning a 32-bit map of exactly which parameters the ECU supports. The car tells the app. Not the other way around.”
✅
ECU-verified parameters
Auto-detects exactly what your car supports on connection. Database serves as fallback only.
✅
Single source of truth
Dashboard and Live Data always show identical PIDs — same filter, same sort, same data.
✅
Demo Mode included
Physics-based engine simulation across all 20 PIDs. Explore every feature without hardware.
✅
100% on-device
Zero server cost. Zero subscriptions. Zero telemetry. All data stays on your phone.
LIVE PROOF
Tested on a real vehicle
Mitsubishi Mirage G4 2022 — 16 parameters auto-detected live from the ECU

Live data from Mitsubishi Mirage G4 2022 — real ELM327 connection
| PID | Parameter | Value |
|---|---|---|
| 0x0C | Engine RPM | 813–1293 rpm |
| 0x05 | Coolant Temp | 45–54°C |
| 0x0B | MAP | 28–30 kPa |
| 0x0E | Timing Advance | 11–14° |
| 0x14 | O2 Upstream | 0.1–0.5V |
| 0x42 | Module Voltage | 13.8V |
| + 10 more parameters auto-detected… | ||
KEY FINDING
Fuel Level (0x2F) was correctly identified as NOT supported — confirmed by the ECU’s own bitmask. The database had assumed it was supported. This is exactly the problem auto-detection exists to solve.
16
Parameters detected
Live from real ECU
100%
On-device
No cloud, no telemetry
$0
Subscription cost
Zero backend needed
✓
End-to-end tested
Real car, real adapter
FEATURES
Everything you need to diagnose your vehicle
🔍
Auto PID Detection
Queries ECU bitmask directly on connection. Your car reports exactly what it supports — no database guessing.

📊
Live Dashboard
Animated circular gauges in priority order. RPM, Speed, Coolant Temp, Engine Load — always first.

⚠️
Fault Code Scanner
Scan stored and pending DTCs simultaneously. 100+ code descriptions built in. Clear with confirmation.

📈
Live Data + 60s Charts
60-second time-series chart per sensor. Tap any PID to see its history. Fully synced with Dashboard.

🚗
Vehicle Database
14 brands, 121+ models. Diesel, hybrid, and EV variants. Cascading brand → model → year dropdowns.

🎮
Demo Mode
Physics-based engine simulation across all 20 PIDs using sin/cos waves. Full exploration without hardware.

TECH STACK
Built with modern tools, from scratch
ARCHITECTURE HIGHLIGHTS
- Raw TCP socket — No OBD library. ELM327 protocol implemented from scratch
- Single source of truth — _enabledPids is the only PID filter for every screen
- StringBuffer + Completer — Handles TCP fragmentation, resolves on ELM327 prompt
- 3-strike blacklisting — PIDs need 3 consecutive failures before removal
- Bitmask PID discovery — 4 queries, 32-bit parse, persisted to SharedPreferences
LAYER BREAKDOWN
| Framework | Flutter 3.x / Dart 3.x |
| State | Provider 6.x |
| Charts | fl_chart 0.68 |
| Hardware | dart:io TCP Socket |
| Build | AGP 8.6, Kotlin 2.1.0 |
| Target | Android 5.0+ (API 21) |
ENGINEERING PROCESS
Hard problems solved
Real engineering challenges encountered and resolved during development
CHALLENGE 01
Database assumptions were wrong
Problem: Static PID database guessed wrong parameters for specific vehicles. Mirage G4 missing O2 Downstream, incorrectly included Fuel Level.
Solution: Implemented OBD-II bitmask discovery protocol. The ECU reports its own truth — overrides all database assumptions.
CHALLENGE 02
Dashboard ≠ Live Data
Problem: Two screens used different PID filtering logic. O2 Downstream appeared on Dashboard but was missing from Live Data.
Solution: Refactored both screens to a single shared filter. _enabledPids is the only authority — same filter, same sort, everywhere.
CHALLENGE 03
TCP buffer race conditions
Problem: TCP data arrives in arbitrary chunk sizes. A response could split across callbacks or multiple responses merge into one chunk.
Solution: StringBuffer accumulates bytes. Completer resolves only on ELM327’s > prompt — guaranteeing complete responses regardless of fragmentation.
CHALLENGE 04
Single timeout killed gauges
Problem: One NO DATA response permanently blacklisted a PID. Normal ECU load variations caused gauges to vanish mid-session.
Solution: 3-strike system using _pidErrorCount map. Blacklist only triggers after 3 consecutive failures. Any success resets the counter.
Need a custom diagnostic tool?
I build hardware-connected Android apps with real-time data pipelines.
Fleet diagnostics, custom OBD-II integrations, vehicle data dashboards — let’s talk.
CATEGORY
Custom Mobile App Development
PLATFORM
Android (Flutter)
HARDWARE
ELM327 WiFi OBD-II
STATUS
✓ Live tested on real vehicle
