MatixYo/ESP32-Plane-Radar

Open-source ESP32 firmware for a 1.28″ round display that shows live ADS-B aircraft around your location as a sonar-style plane radar.

981

stars

24

commits

C++

primary language

Aug 31, 2026

updated

README

Plane Radar

plane-radar

3D printed case (STL + assembly): MakerWorld · Firmware: Releases

Firmware for an ESP32-C3 Super Mini and a 1.28″ round GC9A01 display (240×240). Shows a circular ADS-B radar around your configured location, with WiFiManager for first-time setup.

What it does

  1. Wi‑Fi setup (if needed) — captive portal on AP PlaneRadar-Setup
  2. Radar — live aircraft from adsb.fi on a sonar-style grid

After Wi‑Fi is saved, the device reconnects automatically; the radar runs in the main loop with periodic ADS-B updates (~5 s).

Controls (BOOT, GPIO 9, active LOW)

ActionEffect
Short tapCycle range preset (5 → 10 → 15 → 25 km); saved to flash
Hold 3 sClear Wi‑Fi, location, and units; reboot into setup portal

During setup you can also hold BOOT at power-on to force a credential reset (same as the long press).

Wi‑Fi setup portal

First-time setup (no saved Wi‑Fi):

  1. Connect to PlaneRadar-Setup
  2. Open http://plane-radar.local (preferred) or http://192.168.4.1 — both are shown on the yellow setup screen; captive portal may open automatically
  3. Set home Wi‑Fi, then save

Reconfigure anytime (after the device is on your network):

  1. Open http://plane-radar.local or http://<device-ip> (e.g. from your router or serial log at boot)
  2. Change Wi‑Fi, location, units, or runway overlay; save

The same portal runs on the setup AP and on the device’s LAN IP while connected to Wi‑Fi. mDNS hostname is plane-radarplane-radar.local (kPortalHostname in config.h). Some clients resolve .local slowly; use the IP if needed.

Custom fields (stored in NVS):

FieldPurpose
Latitude / LongitudeRadar center and ADS-B query position (defaults in config.h until set)
Display distances in milesRing scale label in mi instead of km (e.g. 6mi vs 10km)
Show airport runwaysMajor-airport runway overlay on the radar (off to hide)

After a reset, the device reboots and shows the setup screen immediately (no “Connecting” loop on stale credentials).

Radar display

Grid

  • Dark blue background, subdued green rings and crosshairs
  • White N / S / E / W at the bezel; range label on the east spoke (ring 3 = ¾ of outer radius)
  • White center dot

Layout and colors: include/ui/radar_theme.h.

Range presets

Ring 3 labelOuter radius (aircraft scale)
5 km / 3 mi~6.7 km
10 km / 6 mi~13.3 km (default)
15 km / 9 mi~20 km
25 km / 16 mi~33.3 km

Preset and miles/km choice persist across reboot (planeradar NVS namespace).

Runways

  • Major airports from OurAirports (large_airport); all open runway strips in range (helipads excluded)
  • Teal runway lines with one ICAO label per airport (e.g. KJFK); toggle in the Wi‑Fi setup portal
  • Update the embedded list: python3 scripts/build_large_airports.py

Aircraft

  • Inside the outer ring — red heading triangle, magenta speed vector (clipped at the ring), callsign / type / altitude tags
  • Outside the ring (still within ADS-B fetch) — small red dot on the screen rim at the correct bearing (direction cue; not distance-accurate past the ring)
  • Tags — placed toward the center: west (left) → tag on the right of the symbol; east (right) → tag on the left

As range decreases (or aircraft approach), targets move inward; beyond-ring dots become full symbols when they cross the outer ring.

ADS-B

  • Source: https://opendata.adsb.fi/api/v3/
  • Fetch radius: ui::radar::fetchRadiusKm() — scales with the active preset to roughly the screen edge (so rim dots have data)
  • Poll interval: kAdsbFetchIntervalMs (5 s) in config.h
  • Ground aircraft hidden by default (kAdsbShowGroundAircraft)

Configuration

Edit include/config.h for hardware and behavior:

AreaKeys / notes
PortalkPortalApName, kPortalIp, kPortalHostname / kPortalHostUrl (mDNS; needs -DWM_MDNS in platformio.ini)
Wi‑Fi timingconnect attempts, reconnect grace, portal timeout (0 = no timeout)
BOOTkBootPin, kBootResetHoldMs, kBootTapMinMs
Display SPIpins, kDisplayInvert, kDisplayRgbOrder, kDisplaySpiWriteHz
Default locationkDefaultRadarLat, kDefaultRadarLon (until portal overrides)
ADS-BkAdsbFetchIntervalMs, kAdsbShowGroundAircraft

Range presets: include/ui/radar_range.h (kRangePresets).

Project layout

include/
  config.h
  hardware/
    lgfx_config.hpp
    display.h
    display_font.h
  data/
    large_airports.h
  ui/
    radar_theme.h
    radar_range.h
    radar_display.h
    runway_overlay.h
    status_screens.h
  services/
    wifi_setup.h
    radar_location.h
    adsb_client.h
data/
  ui_font.vlw              — embedded smooth UI font (Noto Sans Bold)
scripts/
  build_large_airports.py
src/
  main.cpp
  data/
    large_airports_data.cpp
  hardware/
  ui/
  services/

Wiring (GC9A01 ↔ ESP32-C3 Super Mini)

DisplayESP32-C3
VCC3V3
GNDGND
RSTGPIO 0
CSGPIO 1
DCGPIO 10
SDA (MOSI)GPIO 3
SCL (SCLK)GPIO 4
BOOT (user)GPIO 9

Build

pio run -t upload
pio device monitor
  • PlatformIO env: supermini
  • Serial: 115200 baud
  • USB CDC on boot enabled in platformio.ini for the Super Mini

Web-flashable release image

Single .bin for esptool-js and similar tools (ESP32-C3, 4 MB, flash at 0x0):

chmod +x scripts/merge-firmware.sh   # once
./scripts/merge-firmware.sh

Writes release/plane-radar-merged.bin. Skip rebuild if firmware is already built:

./scripts/merge-firmware.sh --no-build

Or via PlatformIO only (output: .pio/build/supermini/firmware-merged.bin):

pio run -e supermini
pio run -t merge -e supermini

Put the board in download mode (hold BOOT, tap RESET), then flash with Chrome/Edge over USB.

CI and releases (GitHub Actions)

WorkflowWhenOutput
BuildPush / PR to mainArtifact plane-radar-supermini (merged + split .bin files, ~90 days)
ReleaseGit tag v* (e.g. v1.0.0)GitHub Release asset plane-radar-v1.0.0.bin + .sha256

To ship a version users can download:

git tag v1.0.0
git push origin v1.0.0

The release workflow builds firmware in CI and attaches the merged image to the release. Download from Releases on GitHub, then flash at 0x0 (ESP32-C3, 4 MB).

Dependencies

Contributors

MatixYo

22 commits

schrockwell

1 commits

WatskeBart

1 commits

MatixYo/ESP32-Plane-Radar

Open-source ESP32 firmware for a 1.28″ round display that shows live ADS-B aircraft around your location as a sonar-style plane radar.

981

stars

24

commits

C++

primary language

Aug 31, 2026

updated

README

Plane Radar

plane-radar

3D printed case (STL + assembly): MakerWorld · Firmware: Releases

Firmware for an ESP32-C3 Super Mini and a 1.28″ round GC9A01 display (240×240). Shows a circular ADS-B radar around your configured location, with WiFiManager for first-time setup.

What it does

  1. Wi‑Fi setup (if needed) — captive portal on AP PlaneRadar-Setup
  2. Radar — live aircraft from adsb.fi on a sonar-style grid

After Wi‑Fi is saved, the device reconnects automatically; the radar runs in the main loop with periodic ADS-B updates (~5 s).

Controls (BOOT, GPIO 9, active LOW)

ActionEffect
Short tapCycle range preset (5 → 10 → 15 → 25 km); saved to flash
Hold 3 sClear Wi‑Fi, location, and units; reboot into setup portal

During setup you can also hold BOOT at power-on to force a credential reset (same as the long press).

Wi‑Fi setup portal

First-time setup (no saved Wi‑Fi):

  1. Connect to PlaneRadar-Setup
  2. Open http://plane-radar.local (preferred) or http://192.168.4.1 — both are shown on the yellow setup screen; captive portal may open automatically
  3. Set home Wi‑Fi, then save

Reconfigure anytime (after the device is on your network):

  1. Open http://plane-radar.local or http://<device-ip> (e.g. from your router or serial log at boot)
  2. Change Wi‑Fi, location, units, or runway overlay; save

The same portal runs on the setup AP and on the device’s LAN IP while connected to Wi‑Fi. mDNS hostname is plane-radarplane-radar.local (kPortalHostname in config.h). Some clients resolve .local slowly; use the IP if needed.

Custom fields (stored in NVS):

FieldPurpose
Latitude / LongitudeRadar center and ADS-B query position (defaults in config.h until set)
Display distances in milesRing scale label in mi instead of km (e.g. 6mi vs 10km)
Show airport runwaysMajor-airport runway overlay on the radar (off to hide)

After a reset, the device reboots and shows the setup screen immediately (no “Connecting” loop on stale credentials).

Radar display

Grid

  • Dark blue background, subdued green rings and crosshairs
  • White N / S / E / W at the bezel; range label on the east spoke (ring 3 = ¾ of outer radius)
  • White center dot

Layout and colors: include/ui/radar_theme.h.

Range presets

Ring 3 labelOuter radius (aircraft scale)
5 km / 3 mi~6.7 km
10 km / 6 mi~13.3 km (default)
15 km / 9 mi~20 km
25 km / 16 mi~33.3 km

Preset and miles/km choice persist across reboot (planeradar NVS namespace).

Runways

  • Major airports from OurAirports (large_airport); all open runway strips in range (helipads excluded)
  • Teal runway lines with one ICAO label per airport (e.g. KJFK); toggle in the Wi‑Fi setup portal
  • Update the embedded list: python3 scripts/build_large_airports.py

Aircraft

  • Inside the outer ring — red heading triangle, magenta speed vector (clipped at the ring), callsign / type / altitude tags
  • Outside the ring (still within ADS-B fetch) — small red dot on the screen rim at the correct bearing (direction cue; not distance-accurate past the ring)
  • Tags — placed toward the center: west (left) → tag on the right of the symbol; east (right) → tag on the left

As range decreases (or aircraft approach), targets move inward; beyond-ring dots become full symbols when they cross the outer ring.

ADS-B

  • Source: https://opendata.adsb.fi/api/v3/
  • Fetch radius: ui::radar::fetchRadiusKm() — scales with the active preset to roughly the screen edge (so rim dots have data)
  • Poll interval: kAdsbFetchIntervalMs (5 s) in config.h
  • Ground aircraft hidden by default (kAdsbShowGroundAircraft)

Configuration

Edit include/config.h for hardware and behavior:

AreaKeys / notes
PortalkPortalApName, kPortalIp, kPortalHostname / kPortalHostUrl (mDNS; needs -DWM_MDNS in platformio.ini)
Wi‑Fi timingconnect attempts, reconnect grace, portal timeout (0 = no timeout)
BOOTkBootPin, kBootResetHoldMs, kBootTapMinMs
Display SPIpins, kDisplayInvert, kDisplayRgbOrder, kDisplaySpiWriteHz
Default locationkDefaultRadarLat, kDefaultRadarLon (until portal overrides)
ADS-BkAdsbFetchIntervalMs, kAdsbShowGroundAircraft

Range presets: include/ui/radar_range.h (kRangePresets).

Project layout

include/
  config.h
  hardware/
    lgfx_config.hpp
    display.h
    display_font.h
  data/
    large_airports.h
  ui/
    radar_theme.h
    radar_range.h
    radar_display.h
    runway_overlay.h
    status_screens.h
  services/
    wifi_setup.h
    radar_location.h
    adsb_client.h
data/
  ui_font.vlw              — embedded smooth UI font (Noto Sans Bold)
scripts/
  build_large_airports.py
src/
  main.cpp
  data/
    large_airports_data.cpp
  hardware/
  ui/
  services/

Wiring (GC9A01 ↔ ESP32-C3 Super Mini)

DisplayESP32-C3
VCC3V3
GNDGND
RSTGPIO 0
CSGPIO 1
DCGPIO 10
SDA (MOSI)GPIO 3
SCL (SCLK)GPIO 4
BOOT (user)GPIO 9

Build

pio run -t upload
pio device monitor
  • PlatformIO env: supermini
  • Serial: 115200 baud
  • USB CDC on boot enabled in platformio.ini for the Super Mini

Web-flashable release image

Single .bin for esptool-js and similar tools (ESP32-C3, 4 MB, flash at 0x0):

chmod +x scripts/merge-firmware.sh   # once
./scripts/merge-firmware.sh

Writes release/plane-radar-merged.bin. Skip rebuild if firmware is already built:

./scripts/merge-firmware.sh --no-build

Or via PlatformIO only (output: .pio/build/supermini/firmware-merged.bin):

pio run -e supermini
pio run -t merge -e supermini

Put the board in download mode (hold BOOT, tap RESET), then flash with Chrome/Edge over USB.

CI and releases (GitHub Actions)

WorkflowWhenOutput
BuildPush / PR to mainArtifact plane-radar-supermini (merged + split .bin files, ~90 days)
ReleaseGit tag v* (e.g. v1.0.0)GitHub Release asset plane-radar-v1.0.0.bin + .sha256

To ship a version users can download:

git tag v1.0.0
git push origin v1.0.0

The release workflow builds firmware in CI and attaches the merged image to the release. Download from Releases on GitHub, then flash at 0x0 (ESP32-C3, 4 MB).

Dependencies

Contributors

MatixYo

22 commits

schrockwell

1 commits

WatskeBart

1 commits

Languages

C++

95.2%

Python

3.5%