Skip to content

TheJinxNL/F1_Light

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

F1 Light — ESP32 LED + TFT Display Controller

A live-connected ESP32 project that tracks the official F1 Live Timing feed and reacts in real time:

  • An 18-LED WS2812B strip animates the current track status (green / yellow / safety car / VSC / red flag)
  • A 1.9″ ST7789 TFT display shows the upcoming race schedule, live track status, and championship standings

Based on the original 3D design of Julian F: https://makerworld.com/en/models/1624039-formula-1-lamp-stand#profileId-1714575 Inspiration on how to access the F1 Live Feeds: https://github.com/Nicxe/f1_sensor


f1light

Features

  • Live track status via the official F1 SignalR feed — no third-party API key needed
  • LED effects for every flag condition: Green, Yellow, Safety Car, VSC, VSC Ending, Red Flag
  • Race battery overlay — during Race sessions, the last 4 LEDs drain over time like an EV battery indicator
  • Session-end celebration — chequered flag LED sweep + 3× white flash + fade + "FINISHED" screen when a session ends
  • Reconnect resilience — display and LEDs hold the last known track status during a SignalR reconnect
  • Upcoming screen — next race name, up to 3 sessions with local times; alternates every 10 s with the standings screen
  • Resilient schedule sources — upcoming sessions are fetched from Index.json, then event-tracker fallback
  • Championship standings screen — top 6 drivers with position badge, code, and points; fetched from the Ergast mirror
  • 5-minute countdown before each session
  • WiFiManager — configure WiFi from your phone on first boot; credentials saved to flash
  • WiFi reset button — hold GPIO 0 (BOOT button) at power-on to wipe credentials and re-configure
  • Dimmable backlight — reduced brightness at idle, full brightness during a live session
  • Auto-reconnect with exponential back-off on SignalR disconnect
  • Web settings UI — browser-accessible settings page (LED brightness, LCD backlight brightness, idle battery level, race battery animation toggle, test mode, reboot) with persistent NVS storage; URL shown on display at boot
  • Track status test mode — trigger any flag condition or the session-finished animation directly from the web UI without waiting for a live session
  • Boot-time OTA check — checks a remote manifest, installs newer firmware, and reboots automatically
  • OTA status screen — shows OTA check / download / install progress on the TFT during boot

Hardware

Component Detail
Microcontroller ESP32 DevKit (any 30-pin or 38-pin variant)
LED strip WS2812B / NeoPixel — 18 LEDs
Display 1.9″ ST7789 TFT, 170×320 px
Power 5 V / ≥ 2 A (LED strip draws up to 1 A at full brightness)

Wiring

LED Strip

ESP32 LED Strip
GPIO 18 DATA
GND GND
5 V rail +5 V

TFT Display (ST7789)

ESP32 Display pin Notes
GPIO 23 SDA / DIN MOSI — data
GPIO 14 SCL / CLK SPI clock
GPIO 15 CS Chip select
GPIO 27 DC / RS Data/command
GPIO 4 RES / RST Reset — or tie to 3.3 V and set TFT_RST -1
GPIO 13 BL Backlight PWM
3.3 V VCC
GND GND

All pin numbers can be changed in src/config.h.
Avoid GPIO 2 — can interfere with boot/flash on some boards.
Avoid GPIO 6–11 — connected to internal SPI flash.

WiFi Reset Button

Hold GPIO 0 (the built-in BOOT button on most DevKits) while powering on to erase saved WiFi credentials and open the configuration portal. No extra wiring needed.


Project Structure

F1_Light/
├── src/
│   ├── main.cpp                        — Main application entry point: setup(), loop(), state/display wiring
│   ├── config.h                        — All hardware pins, timing, and colour constants
│   ├── f1_live.h / f1_live.cpp         — Live timing client, schedule fetch, SignalR handling
│   ├── effects.h / effects.cpp         — LED effect declarations and implementations
│   ├── display.h / display.cpp         — ST7789 display declarations and driver
│   ├── web_ui.h / web_ui.cpp           — HTTP settings server and persistent settings
│   ├── f1logo.h / f1logo.cpp           — F1 logo bitmap (RGB565)
│   ├── Formula1_Display_Regular11pt7b.h
│   └── Formula1_Display_Regular7pt7b.h
├── platformio.ini
└── partitions_no_fs.csv

Required Libraries

Managed by PlatformIO via platformio.ini lib_deps:

Library Author
FastLED FastLED
WebSockets Markus Sattler (links2004)
ArduinoJson Benoit Blanchon
WiFiManager tzapu
Adafruit ST7735 and ST7789 Library Adafruit
Adafruit GFX Library Adafruit

If you use PlatformIO, no manual library installation is needed.


Getting Started

1. Install PlatformIO

Use either:

  • VS Code + PlatformIO IDE extension
  • PlatformIO Core CLI (pio / platformio)

2. Configure src/config.h

Adjust GPIO pins if your wiring differs. Set DISPLAY_TZ_POSIX to your local timezone string. Everything else (WiFi credentials) is configured at runtime.

3. Build

From the project root:

platformio run --environment esp32dev

4. Upload

From the project root:

platformio run --target upload --environment esp32dev

For OTA support, use a partition scheme with two app slots, e.g. No FS 4MB (2MB App/OTA) via partitions_no_fs.csv.

5. First-boot WiFi setup

On first boot the display shows a blue SETUP screen. Connect your phone/laptop to the Wi-Fi network named F1-Light-Setup, open a browser, go to 192.168.4.1, and pick your home network. Credentials are saved permanently.

6. Web Settings

After connecting to WiFi, the display briefly shows the web settings URL (e.g. http://192.168.1.42). Open it in a browser to adjust LED brightness, idle style, or test track status effects.

7. Monitor

Open Serial Monitor at 115200 baud to see connection progress, parsed sessions and track status updates.

With PlatformIO CLI:

platformio device monitor --baud 115200

LED Effects

State Effect
WiFi / NTP connecting Breathing white
Idle (no session) All LEDs dim red, last 4 LEDs show battery level (1–4) with top bar pulsing; or static full battery when animation is off
Connecting to SignalR Gentle blue breathing
🟢 Green flag Solid green
🟡 Yellow flag Fast yellow blink
🚗 Safety Car Alternating blue/yellow — grouped 9 / 5 / 4 block pattern
🟠 VSC Slow orange pulse
🟢 VSC Ending Pulsating green (ramps between dim and full brightness)
🔴 Red flag Rapid red flash
Race session overlay Last 4 LEDs show a draining battery bar over race duration; static full battery when animation is off
🏁 Session finished Chequered sweep → 3× white flash → fade (~3 s)

Display Screens

State Screen
WiFi / NTP Grey header + connecting text
OTA during boot Blue OTA header + current OTA stage/status
WiFiManager portal Blue header + AP name + 192.168.4.1
Web settings URL Red header + "WEB SETTINGS" + http://<ip> — shown briefly at boot
Idle — schedule F1 logo header + next race name + up to 3 upcoming sessions with local times
Idle — standings F1 logo header + top 6 driver championship standings
5-min countdown Session name + large countdown timer
Live — Green flag Full-screen green background + "ALL CLEAR"
Live — VSC Ending Full-screen green background + "VSC ENDING"
Live — other flags Full-screen flag-colour background + large status text
Session finished Chequered flag pattern + "FINISHED" text

Configuration Reference

All constants live in src/config.h:

Constant Default Description
LED_PIN 18 GPIO for LED strip data
NUM_LEDS 18 Number of LEDs
MAX_BRIGHTNESS 200 LED brightness cap (0–255); overridden at runtime via web UI
DIM_BRIGHTNESS 50 Reduced LED brightness used for secondary/dim states
IDLE_BASE_RED 180 Red channel level (0–255) for all LEDs in idle state
TFT_BL_DEFAULT 200 Default backlight brightness (0–255); overridden at runtime via web UI
DISPLAY_TZ_POSIX "CET-1CEST,M3.5.0,M10.5.0/3" POSIX timezone string used for local display time
WIFI_MANAGER_AP_NAME "F1-Light-Setup" Config portal AP name
WIFI_MANAGER_TIMEOUT 180 Portal auto-close timeout (seconds)
WIFI_RESET_PIN 0 GPIO held LOW at boot to reset WiFi credentials
F1_POLL_INTERVAL_MS 60000 How often to poll the F1 schedule (ms)
FW_VERSION "1.0.14" Current firmware version used for OTA comparison
OTA_BOOT_CHECK_ENABLED 1 Enable/disable boot-time OTA check
OTA_MANIFEST_URL "https://www.jinx.nl/f1-light/update/manifest.json" Remote OTA manifest URL
OTA_MANIFEST_TIMEOUT_MS 7000 Manifest request timeout (ms)
OTA_FIRMWARE_TIMEOUT_MS 20000 Firmware download timeout (ms)
OTA_ALLOW_INSECURE_TLS 1 1 skips TLS cert validation (dev only); 0 for production cert pinning/validation
F1_PRE_WINDOW_MS 1 800 000 Connect to feed this many ms before session starts
F1_POST_WINDOW_MS 1 800 000 Stay connected this many ms after session ends
RACE_BATTERY_DRAIN_MS 5 400 000 Time for the Race battery overlay to drain from full to empty

Web Settings UI

When connected to WiFi, the device hosts an HTTP server on port 80. The URL is shown on the display briefly after boot.

Open http://<device-ip>/ in a browser to access the settings page:

Setting Description
LED Brightness Slider (0–255). Applies immediately; persisted across reboots.
LCD Brightness Slider (0–255). Controls TFT backlight PWM. Applies immediately; persisted across reboots.
Idle Battery Level Fixed range 1–4; shows that many bars with the top bar pulsing. Only used when battery animation is on. Persisted.
Race Battery Animation Checkbox. On: battery drains over race duration (idle: configured bars with pulse). Off: static full battery (4 bars, no pulse) in both idle and race. Persisted.
Track Test Mode Toggle on to override live data with a chosen track status for previewing effects. Not persisted.
Track Status Dropdown: Clear / Yellow / Safety Car / Red Flag / VSC / VSC End / Session Finished. Active when test mode is on.
Reboot Device Reboots the device from the web UI after confirmation.

Settings are stored in ESP32 NVS (non-volatile storage) and survive power cycles.

OTA Manifest Format

When OTA_BOOT_CHECK_ENABLED is on, the device checks OTA_MANIFEST_URL once during boot.

Expected JSON:

{
	"version": "1.0.5",
	"firmwareUrl": "https://www.jinx.nl/f1-light/update/F1_Light-1.0.5.bin",
	"md5": "optional_md5_hash"
}

Notes:

  • firmwareUrl (or url) is required.
  • md5 is optional but recommended.
  • Upload the app binary (firmware.bin in PlatformIO), not bootloader/partitions binaries.

F1 Live Timing API

This project uses the unofficial but public F1 Live Timing endpoints:

  • Schedule: https://livetiming.formula1.com/static/{year}/Index.json
  • Event tracker fallback: https://api.formula1.com/v1/event-tracker
  • SignalR negotiate: https://livetiming.formula1.com/signalr/negotiate
  • WebSocket: wss://livetiming.formula1.com/signalr/connect
  • Championship standings: https://api.jolpi.ca/ergast/f1/current/driverstandings.json

Schedule fallback order used by firmware:

  1. Index.json (primary)
  2. event-tracker (secondary)

Note: F1 sometimes changes what Index.json or event-tracker include during the season. Index.json only lists rounds F1 has published — early in the year (first 4–6 rounds) future races may be absent, which is why the event-tracker fallback exists.

ESP32 time_t / clock quirks

On ESP32 Arduino core 3.x (ESP-IDF 5.x) time_t is a 64-bit int64_t. The upper 32 bits can contain garbage in two situations:

  1. During or immediately after a TLS sessiontime() returns a corrupt value. Always call time(nullptr) after http.end().
  2. C++ lambda value-captures of time_t — the captured variable prints correctly via (long) cast but the actual 64-bit comparison uses garbage upper bits, causing future sessions to appear past. Use plain static helper functions instead of lambdas.

The firmware works around both issues by storing session timestamps as uint32_t (all F1 dates 2026–2099 fit in 32 bits) and casting time(nullptr) to uint32_t before every comparison.

Track status codes received over the feed:

Code Meaning
1 Green (All Clear)
2 Yellow flag
4 Safety Car
5 Red flag
6 Virtual Safety Car
7 VSC Ending

Used Links


License

MIT

About

This repository contains the Source Code for the F1 Light

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors