A Bluetooth Low Energy (BLE) virtual dashboard system for EpicEFI ECUs. Displays real-time engine data and provides wireless button inputs for ECU control.
| Component | Status |
|---|---|
| Android | |
| Firmware | |
| iOS |
| Component | Description |
|---|---|
| Firmware | ESP32-S3 BLE-to-CAN bridge |
| Android App | Dashboard with gauges and buttons |
| iOS App | Dashboard with gauges and buttons |
- Flash Firmware to ESP32-S3 (see Firmware README)
- Install App - Android or iOS
- Connect - App auto-connects to "ESP32 Dashboard"
- Configure - Set up gauges and buttons in Settings
- Real-Time Gauges - GPS speed + ECU variables (up to 60 Hz)
- Customizable Buttons - 1-16 buttons, momentary or toggle mode
- Two-Tier Layout - 2 large + 4 small gauges
- Dark Theme - Automotive-style UI with orange accents
- BLE Server - Low-latency communication
- Batched Requests - Multiple variables per BLE packet
- CAN Bridge - Buttons TX, variables RX
4fafc201-1fb5-459e-8fcc-c5c9c331914b
| UUID | Name | Direction | Description |
|---|---|---|---|
...a8 |
Button | Android → ESP32 | 2-byte button mask (little-endian) |
...a9 |
VarData | ESP32 → Android | Batched: N × 8-byte entries [hash(4) + value(4)] big-endian |
...aa |
VarRequest | Android → ESP32 | Batched: N × 4-byte hashes (big-endian) |
For higher data rates, variables are requested and returned in batches:
- Android sends multiple 4-byte hashes in one BLE write
- ESP32 requests each variable from ECU via CAN sequentially
- ESP32 collects all responses and sends one batched BLE notification
- Android parses multiple 8-byte entries from the notification
This reduces BLE round-trips from N to 1 per update cycle.
| Byte | Description |
|---|---|
| 0 | Header (0x5A) |
| 1 | Reserved (0x00) |
| 2 | Category ID (27) |
| 3 | Button mask high byte |
| 4 | Button mask low byte |
| Byte | Description |
|---|---|
| 0-3 | VarHash (int32 big-endian) |
| Byte | Description |
|---|---|
| 0-3 | VarHash (int32 big-endian) |
| 4-7 | Value (float32 big-endian) |
Automated builds run on push to main. Releases are created on version tags.
Required Secrets (Settings → Secrets → Actions):
Android:
| Secret | Description |
|---|---|
KEYSTORE_BASE64 |
Base64-encoded Android keystore (base64 keystore.jks) |
KEYSTORE_PASSWORD |
Keystore password |
KEY_ALIAS |
Signing key alias |
KEY_PASSWORD |
Signing key password |
GOOGLE_PLAY_SERVICE_ACCOUNT_JSON |
Google Play API service account JSON |
iOS:
To enable iOS builds, set the repository variable IOS_BUILD_ENABLED to true (Settings → Variables → Repository variables).
| Secret | Description |
|---|---|
IOS_BUILD_CERTIFICATE_BASE64 |
Base64-encoded .p12 distribution certificate |
IOS_P12_PASSWORD |
Password for .p12 certificate |
IOS_KEYCHAIN_PASSWORD |
Temporary keychain password (any value) |
IOS_PROVISIONING_PROFILE_BASE64 |
Base64-encoded .mobileprovision file |
IOS_TEAM_ID |
Apple Developer Team ID |
APP_STORE_CONNECT_API_KEY_ID |
App Store Connect API Key ID |
APP_STORE_CONNECT_API_ISSUER_ID |
App Store Connect Issuer ID |
APP_STORE_CONNECT_API_KEY_BASE64 |
Base64-encoded .p8 API key |
Creating a Release:
- Update the
VERSIONfile with the new version number - Go to Actions → Build → Run workflow
- Check "Create a GitHub release" checkbox
- Click "Run workflow"
The release will be created with the version from the VERSION file.
cd Firmware
pio run
pio run -t upload- Open
Android/folder in Android Studio - Sync Gradle
- Build and run on device
- Open
iOS/EpicDash/EpicDash.xcodeprojin Xcode - Set your development team in Signing & Capabilities
- Build and run on device (BLE requires physical device)
- ESP32-S3 DevKitC-1
- CAN transceiver: TX=GPIO10, RX=GPIO11
- CAN mode pin: GPIO9 (LOW=high speed)
BLUETOOTH_SCAN/BLUETOOTH_CONNECT- BLEACCESS_FINE_LOCATION- GPS speedometer & BLE scanning
The variables.json file contains ECU variable definitions with:
name- Variable namehash- Int32 hash for CAN protocolsource- "output" (live data) or "config"
Common dashboard variables:
AFRValue- Air/Fuel RatiobaroPressure- Barometric pressurebaseIgnitionAdvance- Ignition timingboostboostOutput- Boost control output
