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 screen showing live RPM gauges

Dashboard

Live data screen showing 16 auto-detected parameters

Live Data

Fault codes screen

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

Real Mirage G4 connected showing 16 detected parameters

Live data from Mitsubishi Mirage G4 2022 — real ELM327 connection

PIDParameterValue
0x0CEngine RPM813–1293 rpm
0x05Coolant Temp45–54°C
0x0BMAP28–30 kPa
0x0ETiming Advance11–14°
0x14O2 Upstream0.1–0.5V
0x42Module Voltage13.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.

Auto detection showing 16 parameters

📊

Live Dashboard

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

Dashboard with circular gauges

⚠️

Fault Code Scanner

Scan stored and pending DTCs simultaneously. 100+ code descriptions built in. Clear with confirmation.

Fault codes screen

📈

Live Data + 60s Charts

60-second time-series chart per sensor. Tap any PID to see its history. Fully synced with Dashboard.

Live data with 60s chart

🚗

Vehicle Database

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

Vehicle selection dropdowns

🎮

Demo Mode

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

Demo mode with purple DEMO chip

TECH STACK

Built with modern tools, from scratch

Flutter 3.x Dart 3.x Provider 6.x fl_chart 0.68 TCP Socket (raw) ELM327 Protocol OBD-II PID Parsing SharedPreferences Android Gradle 8.6 minSdk 21 (Android 5+)

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

FrameworkFlutter 3.x / Dart 3.x
StateProvider 6.x
Chartsfl_chart 0.68
Hardwaredart:io TCP Socket
BuildAGP 8.6, Kotlin 2.1.0
TargetAndroid 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