ChronoDisplay
An ESP32-based display panel for the FX Archery Chronograph (v1) that provides a real-time, always-on ePaper display of shot data via Bluetooth Low Energy (BLE). Compatible with airguns and archery applications.
Overview
ChronoDisplay connects wirelessly to the FX Archery Chronograph via BLE, receives speed readings in real time, and displays comprehensive shot statistics on a 7.5" monochrome ePaper screen. It runs entirely on an ESP32 — no PC or phone required.
Key Features
- Live BLE Connection — Automatically scans for, connects to, and maintains a link with the FX Chronograph
- Real-Time E-Paper Display — Always-on, sunlight-readable display showing:
- Latest shot velocity (FPS) and energy (FPE)
- Running shot count, average / min / max FPS
- Spread and standard deviation
- Profile info (gun name, power level, projectile type/caliber/weight)
- Last 32 shot history
- Real-time clock (EST timezone)
- Connection status indicator
- Built-in Web Server — Configure everything from any browser on your WiFi network
- Gun profiles (Bow/Airsoft, CO2 Pistol, Air Pistol, Air Gun UK, FAC)
- Projectile profiles (pellets & slugs with caliber and weight)
- Export all readings as CSV
- Reset readings, format storage, toggle test mode
- Accessible at
http://esp32.local(mDNS) or the device's IP
- Persistent Storage — Gun and projectile profiles saved to LittleFS filesystem
- Test Mode — Generate simulated readings for display debugging
Hardware
| Component | Specification |
|---|---|
| Microcontroller | ESP32 |
| Display | 7.5" Monochrome ePaper (UC8179 chipset, Screen Combo board ID: 502) |
| BLE Library | NimBLEDevice |
| Display Library | TFT_eSPI |
| Filesystem | LittleFS |
Pin / Board Configuration
The board type is defined in driver.h:
#define BOARD_SCREEN_COMBO 502
#define USE_XIAO_EPAPER_DRIVER_BOARD
Ensure your User_Setup_Select.h (from TFT_eSPI) is configured for the XIAO ePaper driver board with a 7.5" UC8179 display.
Architecture
┌──────────────┐ BLE ┌──────────────────┐ WiFi ┌──────────────┐
│ FX Chrono │ ◄──────────► │ ESP32 │ ◄──────────► │ Browser │
│ (v1) │ (speed │ │ (web UI) │ │
│ │ data) │ ┌──────────────┐│ │ 192.168.x.x │
│ │ │ │ ChronoBLE ││ │ esp32.local │
│ │ │ ├──────────────┤│ │ │
│ │ │ │ Display │ │ │ │
│ │ │ ├──────────────┤│ │ │
│ │ │ │ WebServer │ │ │ │
│ │ │ ├──────────────┤│ │ │
│ │ │ │ FileMgr │ │ │ │
│ │ │ └──────────────┘│ │ │
└──────────────┘ └──────────────────┘ └──────────────┘
Core Modules
| Module | File(s) | Purpose |
|---|---|---|
| Main | ChronoDisplay.ino |
Arduino setup/loop, orchestrates all subsystems |
| BLE Client | ChronoBLE.h/.cpp |
NimBLE connection to FX Chronograph, reads speed notifications |
| Display | Display.h/.cpp |
E-Paper rendering of all data fields |
| Web Server | ChronoWebServer.h/.cpp |
HTTP server with embedded HTML/JS UI |
| File Manager | FileManager.h/.cpp |
Persistent profile storage on LittleFS |
| Reading Manager | ChronoReadingManager.h/.cpp |
Singleton that tracks all readings, profiles, and stats |
| Profiles | GunProfile.h/.cpp, ProjectileProfile.h/.cpp, ChronoProfile.h/.cpp |
Gun and projectile profile data models |
| Reading | ChronoReading.h/.cpp |
Individual shot reading (FPS + FPE + profile) |
BLE Details
FX Chronograph BLE Characteristics
The device uses a custom GATT service with the following UUIDs:
| Description | UUID |
|---|---|
| Device Info Service | 0000180A-0000-1000-8000-00805F9B34FB |
| Chronograph Service | 00001623-88EC-688C-644B-3FA706C0BB75 |
| Speed Characteristic (notify) | 00001624-88EC-688C-644B-3FA706C0BB75 |
| Profile Setting Low | 00001626-88EC-688C-644B-3FA706C0BB75 |
| Battery Level | 00001627-88EC-688C-644B-3FA706C0BB75 |
| Profile Setting High | 00001628-88EC-688C-644B-3FA706C0BB75 |
Speed data is received as a 2-byte big-endian value and converted to FPS by multiplying by 0.0475111859.
Connection Flow
- Start BLE scan for devices advertising the Device Info Service UUID
- When target found, connect using cached or new BLE client
- Subscribe to the speed characteristic for notifications
- Write low/high speed profile bytes to configure range
- On disconnect, return to scan state and repeat
Web Interface
Connect to the device's WiFi network (or existing network — SSID and password are set in ChronoWebServer.cpp), then open:
- mDNS:
http://esp32.local - Direct IP:
http://<ESP32-IP>
Available Pages & Endpoints
| Route | Method | Purpose |
|---|---|---|
/ |
GET | Main dashboard — select gun & projectile profiles, control panel |
/gunprofile |
GET | Form to add a new gun profile |
/gunprofile/add |
POST | Create a gun profile (name + type) |
/gunprofile/set |
POST | Activate a gun profile |
/gunprofile/remove |
POST | Delete a gun profile |
/projectileprofile |
GET | Form to add a projectile profile |
/projectileprofile/add |
POST | Create a projectile profile (name, type, caliber, weight) |
/projectileprofile/set |
POST | Activate a projectile profile |
/projectileprofile/remove |
POST | Delete a projectile profile |
/export |
GET | Download all readings as data.csv |
/reset |
GET | Clear all readings (shot count, stats) |
/format |
GET | Format LittleFS — erase all stored profiles |
/testmode |
GET | Toggle test mode (simulated readings every 5s) |
/ota |
GET | OTA firmware update page |
/ota |
POST | Upload and apply firmware update (.bin file) |
Gun Profile Types
| Type | Description |
|---|---|
| 0 | Bow / Airsoft |
| 1 | CO2 Pistol |
| 2 | Air Pistol |
| 3 | Air Gun UK |
| 4 | FAC (French) |
Display Layout
┌──────────────────────────────────────────────────────────────────────────────────────────┐
│ 14:56 EST ┌─────────────────────────────────┐ │
│ [Time] │ Profile: │ │
│ │ "My Rifle" [1] │ │
│ Latest Shot │ .22 Pellet │ │
│ ┌────────────────────┐ │ Cal: 6.35 │ │
│ │ │ │ Pellet 0.58g │ │
│ │ 905 fps │ └─────────────────────────────────┘ │
│ └────────────────────┘ (Right Panel) │
│ │ │ │
│ ┌─────────┐┌─────────┐┌─────────┐ ┌──────────────────────────────────────────┐ │ │
│ │Avg: 902│ │Count: 12│ │Spread: 5│ │Last Shots: │ │ │
│ └─────────┘└─────────┘└─────────┘ │ 12) 905 / 18.2 11) 904 / 18.2 ... │ │ │
│ ┌─────────┐┌─────────┐┌─────────┐ └──────────────────────────────────────────┘ │ │
│ │Low: 897│ │High: 907│ │SD: 3.2 │ │ │
│ └─────────┘└─────────┘└─────────┘ │ │
│ │ │
│ FPE: 18.2 │ │
└──────────────────────────────────────────────────────────────────────────────────────────┘
Development
Prerequisites
- Arduino IDE or PlatformIO
- ESP32 board support package
- TFT_eSPI library — configure
User_Setup_Select.hfor your display - NimBLE-Arduino library
TFT_eSPI Configuration
In your TFT_eSPI User_Setup_Select.h, uncomment the XIAO ePaper 7.5" setup. The board constant used is BOARD_SCREEN_COMBO 502 with USE_XIAO_EPAPER_DRIVER_BOARD.
WiFi Configuration
Edit the SSID and password in ChronoWebServer.cpp:
const char *ssid = "your-network";
const char *password = "your-password";
Build & Upload
- Configure libraries and board in Arduino IDE / PlatformIO
- Set board to your ESP32 variant
- Flash via USB
Project Status
Initial development. The project compiles and runs with the following functionality:
- ✅ BLE connection to FX Chronograph v1
- ✅ Live ePaper display of shot data
- ✅ Web-based gun & projectile profile management
- ✅ CSV export of readings
- ✅ Persistent profile storage
- ✅ Test mode for display debugging
- ✅ OTA firmware updates (via web UI at /ota)
- ✅ Time synchronization via NTP
License
[Add your license here]