Adds a live radar canvas to the web UI (above the flight logbook),
switches night dimming from a fixed 22:00-06:00 window to the actual
sunrise/sunset at the active location, and gives Heavy-category
aircraft (A380/B747/B777-class) their own marker instead of sharing
the orange "notable" ring.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Night dimming now uses the actual sunrise/sunset at the active
location (classic Almanac algorithm) instead of a fixed 22:00-06:00
window, with a fallback to that fixed window while location or time
isn't known yet. Applies to both the backlight (main.cpp) and the
radar's own color dimming (radar_screen.cpp).
Heavy-category aircraft (ADS-B emitter category "A5") now get a
distinct marker (larger circle with an outer ring, plus the usual
heading line) instead of sharing the orange "notable" ring, on both
the device display and the WebUI radar.
Note: the orange "notable" ring itself (military/government callsign
prefixes) remains unimplemented - Config::NOTABLE_CALLSIGN_PREFIXES
has never been defined anywhere in this project. The WebUI radar's
"notable" field is hardcoded false until that's actually specified;
on the device it was never wired up in the first place.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The WebUI home page now shows a live radar canvas above the flight
logbook, polling a new /radar.json endpoint every 3 seconds. It
mirrors the device display: distance rings, aircraft colored by
altitude, ground vehicles as squares, rotorcraft as diamonds, and
emergency/watchlist/heavy-category rings in that priority. Applies
the same range, hide-ground-vehicles, and airline filters as the
device radar.
AirlineFilter and AircraftWatchlist gain proper mutex protection
around their in-memory arrays (previously only guarded around SD
file I/O) since the new /lists WebUI pages reach them from Core 0
(NetTask) in addition to their existing Core 1 (menu screen)
callers.
Note: the "notable aircraft" military/government callsign-prefix
marker is not implemented - Config::NOTABLE_CALLSIGN_PREFIXES was
never defined anywhere in this project, on the device display or
here. The "notable" ring currently fires on heavy-category aircraft
only.
Also documents the OTA-testing exception to the auto-flash rule in
CLAUDE.md (build-only during Push & Release, so the test device stays
on the previous version for OTA testing).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fixes OTA downloads (GitHub's asset redirect wasn't followed before,
so every download failed), reworks the update success/failure
screens to require explicit confirmation instead of auto-vanishing
or auto-restarting, and drops the release-asset rename step in favor
of just uploading firmware.bin directly.
Replaces the screen-timeout tap-cycling with a drag slider (1-15
minutes, then "Never"); the idle screensaver toggle moves into this
same screen since it only affects what happens when the timeout
fires.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the repeated-tap timeout cycling (0-10, one tap per minute)
with a dedicated screen and slider (1-15 minutes, then "Never"). The
screensaver toggle moves from its own System-menu row into this
screen, directly below the slider, since it only determines what
happens when the timeout fires.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
OTA downloads always failed because GitHub's browser_download_url
returns a 301/302 redirect to a signed objects.githubusercontent.com
URL, which HTTPUpdate doesn't follow by default. Now sets
HTTPC_STRICT_FOLLOW_REDIRECTS before downloading.
Update results (success and failure) are now shown as a persistent
info screen requiring an explicit tap to dismiss, instead of a
1.2-1.5s auto-vanishing message followed by an automatic restart -
a firmware update result is important enough that it shouldn't be
missable. Also fixes long dynamic titles (e.g. "Update available:
v3.5.0") and the installing-progress label overflowing the screen
edge in some languages.
Release workflow no longer renames the build artifact to
CYD-flightradar.bin before upload; the release asset is just
firmware.bin now, matching what OtaUpdate::checkForUpdate() looks
for. CLAUDE.md's release workflow updated to match.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a "Check for update" menu entry that checks the latest GitHub
release and installs it directly on the device over WiFi, and an
"Screensaver" toggle that shows a dimmed starfield with a clock
after the inactivity timeout instead of turning the display off
completely. Requires switching to the min_spiffs partition scheme
for OTA's dual app partitions.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Radar rendering, sweep tick, and status-line updates ran regardless
of screensaver state, so each aircraft-update cycle or sweep tick
repainted the full radar over the dimmed starfield while the clock
kept redrawing on top - visible as flicker between the two. Both
drawing blocks now skip entirely while screensaverShowing is true;
updateProximityAlert() (LED/sound only, no display writes) keeps
running unaffected.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New "Screensaver" toggle in Menu > System (off by default). When the
inactivity timeout fires with it enabled, the display shows a dimmed
starfield with a large centered clock instead of turning the
backlight fully off; a tap wakes it and redraws normally. Off keeps
the existing behavior unchanged.
Also fixes OtaUpdate::checkForUpdate() to look for the release asset
"CYD-flightradar.bin" (the actual filename used by the release
workflow) instead of the placeholder "firmware.bin" it was checking
for before.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New "Check for update" entry in Menu > System checks the latest
GitHub release's tag against the running version and, if newer,
downloads and flashes its firmware.bin asset directly over WiFi -
no cable or web flasher needed. Requires switching the partition
scheme to min_spiffs (two OTA-capable app partitions instead of a
single non-OTA one), which needs a full reflash.
confirmWarningScreen() now takes title/body as strings instead of
StringIds so it can show a dynamically composed message (the target
version number) for the update confirmation, with an accent color
parameter so the OTA confirmation can use green instead of the
red used for the existing destructive-action confirmations.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Removes the experimental Sound/beep feature after hardware testing
revealed unfixable electrical interference noise synced to the
radar-sweep SPI traffic. Adds progress-dot feedback on the Settings
Backup/Restore buttons so they no longer look frozen during the SD
copy. Chains three independent free flight-route lookup sources
instead of relying on adsbdb.com alone, which had poor real-world
coverage (~80% "unknown").
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
adsbdb.com alone returned "unknown" for ~80% of routes in real-world
testing. Now tries a VRS standing-data mirror first, then hexdb.io's
route endpoint, then adsbdb.com as a last fallback - same
independent-sources-with-fallback pattern already used for the
aircraft-model lookup above it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The SD-bound copy in SettingsBackup::backup()/restore() blocked
noticeably with no visual feedback, making the button look frozen.
Both functions now accept an optional callback invoked before each
of the two file copies, which menu_screen.cpp uses to append dots to
the button label in place.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Root-caused to SPI bus crosstalk from TFT/touch during radar-sweep
redraws - muting the software output did not silence the residual
hiss, confirming this is hardware EMI rather than a firmware logic
bug. All Sound-related files, settings, i18n strings, and menu
entries have been removed.
Unrelated fixes from the same session are kept: newly created
location presets (via address search, manual coordinates, or the
nearest-airport ticker) now activate immediately instead of leaving
the previous location active; the WebUI QR code moved from a
separate sub-screen onto the main info screen, centered under the
explanatory text.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Detail panel now shows origin/destination via adsbdb.com callsign
lookup. Rotorcraft (ADS-B category A7) get a distinct rotor-cross
marker instead of a heading arrowhead, same rationale as the existing
ground-vehicle marker. WebUI info screen gets a QR button (when WiFi
is connected) that renders the local WebUI URL as a scannable code.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bundles several small local follow-ups since v3.3.0:
- Radar screen aircraft detail panel: long lines (model name, distance
with km/nm/mi) now scroll horizontally instead of being cut off with
"..." (up to 9 independent scrolling lines, reusing the existing
InfoMarquee pattern).
- "Setup complete" screen: small centered "Tap to skip" hint below the
countdown button, translated into all 6 languages.
- Location Presets screen: long preset names/coordinates in the list
now scroll left-aligned instead of being truncated with "...".
- Address search confirmation screen: the found place name is no
longer hard-cut at 150 characters - it's now a vertically scrollable
paragraph (same pattern as the existing Location Presets info
screen), since it's multi-line wrapped text rather than a single
overflowing line.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bumps the web flasher version display to v3.3.0 and refreshes
firmware.bin and partitions.bin to match the v3.3.0 build output -
partitions.bin changed because this release switches to the no_ota.csv
partition scheme.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
## New
- "Welcome" screen shown on first-time setup (before touch
calibration), with the splash screen's animated radar graphic and a
Start button.
- The "Setup complete" screen now counts down 7 seconds with a button
matching the Welcome screen's style, then automatically continues
into the app (previously required a tap).
- System menu "Backup & Reset" page (Backup, Restore, and a new
"Reset settings" option that wipes the on-device data and re-runs
first-time setup - useful for testing or handing the device to
someone else).
- Touch calibration targets are now green mini radar reticles instead
of red crosshairs.
## Improved
- The SD card's data folder is now only created after tapping Start
on the Welcome screen, instead of on every boot regardless.
- Flash partition layout changed to free up roughly 850 KB of
firmware space (no OTA update slot needed, since firmware is always
flashed via cable/USB) - lowers flash usage from ~95% to ~59%.
## Fixed
- The Start button and the WiFi scanning screen now show a loading
indicator instead of appearing frozen during SD-card/WiFi
operations.
- A touch-input bug during first-time setup that could corrupt touch
calibration and cause taps to land on the wrong on-screen element
afterward (most noticeable in the WiFi network selection list).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Shows a new FirstRunWelcomeScreen right at the very beginning of the
first-time setup flow (isFirstRun), before touch calibration even
runs: hard-coded English title (no language chosen yet at this point),
the splash screen's radar reticle centered below it, and a large
black/green-outlined "Start" button whose text breathes between a
darker and a lighter, slightly whitish green (~2.5s cycle) so it's the
one element that visibly stands out against the otherwise uniform
green UI. The button intentionally stays unfilled (black) so the
twinkling MenuStars background shows through it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Moves the previously standalone "Backup settings"/"Restore settings"
buttons out of the System menu into a new "Backup & Reset" sub-page
(replaced in the System menu by a single folder button, placed
directly above "Info"), and adds a third entry "Reset settings" - a
factory reset for developers/testers that deletes the entire
Flightradar folder from the SD card (settings, logbook, location
presets, WiFi, calibration - everything) and restarts the device. The
next boot picks up isFirstRun automatically (via the missing
SD_SETTINGS_FILE) and runs the full first-time setup again, exactly
like on the very first boot - no need to pull the SD card.
Since this is irreversible, it requires a full-screen red warning
confirmation first, reusing the same overlay previously built only for
the flight-logbook enable warning (confirmLogbookEnable() generalized
to confirmWarningScreen(), taking title/body StringIds as parameters).
New SdStorage::deleteDirectoryRecursive() and
SettingsBackup::factoryReset() implement the actual deletion + restart.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Some users' computers don't detect the CYD's CH340 USB-to-serial chip
without a driver, so no COM/USB port shows up in the web flasher. Adds
a short note with official WCH driver download links right after the
Quick Web Installation steps.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ports the same triangle-wave dim/brighten twinkle formula used by
MenuStars on the device to a lightweight, dependency-free canvas
overlay behind the page content, tying the web flasher's look to the
device UI. Star count scales with viewport area (40-160) instead of a
fixed number. The canvas uses z-index:0 (not negative) and
pointer-events:none so it stacks reliably behind .container without
blocking the ESP Web Tools install button or any links.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bumps the web flasher version display to v3.2.0 and refreshes
firmware.bin to match the v3.2.0 build output.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Documents the twinkling radar-screen stars and the consistently
applied Metric/Imperial unit setting in the README feature list. The
underlying unit-display bugfixes and Region-page button sizing
improvement aren't separately called out - no changelog section
exists in the README (previous bugfix-only releases like v3.0.1
weren't documented there either).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Region page (Language/Units/Back, only 3 entries) used the same
small fixed row height (22px) as pages with far more entries (e.g.
Flight Options: 14 entries), leaving most of the screen empty and the
buttons unnecessarily small. Row height/gap are now computed from the
actually available screen area, same pattern already used by the
System page (SYSTEM_ROW_H).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Mirrors the existing detail-panel star field (updateDetailPanelStars)
with the same twinkle logic, but placed via rejection sampling outside
the radar circle (radius + margin around the center) so it never
collides with the sweep line, aircraft markers, or rings redrawn every
tick(). Star positions are computed once on first tick() and never
redistributed, same as the detail-panel field.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Five places ignored the Units setting (Menu > Units) and always showed
fixed metric values even when Imperial was selected: the radar range
button (now km/nm), the radar's ring distance labels (now km/nm), the
aircraft list's altitude/distance columns (now m+km or ft+nm), the
Location Presets screen's nearest-airport distance (now km/nm), and
the Stats screen's highest-altitude-today line (now m or ft). The
range button had already been touched previously but used "mi"
instead of "nm" - aligned to nm here for consistency with the other
distance displays, which all pair with km rather than miles.
The radar detail panel's simultaneous multi-unit display and the
climb/descent rate (always ft/min, aviation convention) are
intentionally left unchanged.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The yellow (mid-altitude) legend entry was pinned to a fixed 1/3-grid
column like the outer green/red entries, but its label ("3000-9100")
is noticeably longer than the others, making it sit visually too far
right - almost touching the red entry while leaving a lot of empty
space next to the short green label. Green and red keep their fixed
positions; yellow is now centered in the actual gap between them,
computed from gfx.textWidth() so it works correctly in both unit
modes (Metric and Imperial).
Refreshes firmware.bin to match this build.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The header clock now shows 12-hour time with AM/PM when Imperial
units are selected (Menu > Units), instead of always using 24-hour
format - the clock-clear region was widened from 50px to 80px to fully
erase the longer "12:59PM"-style text.
The aircraft detail panel's distance line now also shows miles
alongside km and nautical miles (e.g. "12km / 6nm / 7mi"), since nm
alone wasn't self-explanatory for lay users from Imperial-unit
countries.
Also fixes the radar screen's range button, which still always showed
a fixed "km" label regardless of the Metric/Imperial setting - it now
shows mi (converted) when Imperial is selected, matching the pattern
already used by the altitude legend.
Refreshes firmware.bin to match this build.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Refreshes images/screenshot.jpg with a current capture that includes
the weather icon in the header, and embeds it in the README (it was
previously unused there - only images/radar.jpg was linked).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a note to the "Hide ground vehicles" section about the new blue
square markers and matching legend entry, and refreshes the root
firmware.bin to match the v3.1.0 build output including the ground
vehicle marker feature.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ground vehicles (ADS-B emitter category "C*") now render as filled
blue squares instead of the normal circle+arrowhead aircraft marker,
using a fixed color independent of altitude (they're practically
always at 0ft, which would otherwise collide with the low-altitude
green). A second legend line explains the marker, but only when
ground vehicles are actually visible (Flight Options > "Hide ground
vehicles" off) - the info bar height, and therefore the radar circle
size, is otherwise unchanged from before.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bumps the web flasher version display to v3.1.0 and refreshes
firmware.bin to match the v3.1.0 build output.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
## New
- Native in-device address search for setting your exact location,
using the free OpenStreetMap Nominatim geocoding service - no more
relying on imprecise IP-based location. Reachable both during
first-time setup and anytime via Location Presets ("+").
- Guided first-time setup flow: language selection, followed by an
optional location setup step (skippable) that explains why exact
coordinates give a much better experience than automatic IP-based
location, and a final setup-complete screen confirming everything
is saved and ready.
## Improved
- The address search keyboard now shows a format hint (e.g. "Main
Street 12, 12345 Springfield") and includes punctuation keys
(comma, hyphen, slash, period, apostrophe) so addresses with house
numbers like "45/3" can actually be entered.
- The preset-naming screen (when adding a location preset) now shows
example names (e.g. "Home, Work, Holiday home") so new users
understand what's being asked for.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The preset-name keypad (used both when adding a preset via manual
coordinates and after an address search) only showed "Name
(optional):" with no indication of what kind of name was expected.
Adds a localized hint line with example names (e.g. "Home, Work,
Holiday home") under the title in both runPresetNameKeypad()
(location_presets_screen.cpp) and runNameKeypad()
(address_search_screen.cpp), measuring the header height dynamically
via getCursorY() the same way runAddressKeyboard() already does, so
the input field and keyboard shift down to make room regardless of
translation length.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The address search screen previously gave no hint about the expected
input format and had no punctuation keys at all on either keyboard
page, making addresses like a house number "45/3" impossible to type.
Adds a localized format-hint line under the title, comma/hyphen keys
on the main keyboard, and swaps four rarely-needed accented letters on
the special-character page for "/", ".", "'", "-". The header and
input field position are now measured dynamically (getCursorY())
instead of assuming a fixed pixel offset, so longer translations of
the hint text don't overlap the keyboard.
Adds a new FirstRunCompleteScreen shown after the location setup step
on first boot: confirms setup is done, names the SD card folder all
data is stored in, and notes that WiFi will reconnect automatically
from now on, with a large "Flightradar" button leading into the app.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Shortens the first-run location screen's body text in all 6 languages
and makes its buttons follow the text's actual height instead of a
fixed screen position - the longer German translation previously ran
underneath the "Enter Address"/"Skip" buttons, making it unreadable.
Adds a new info paragraph to the Location Presets "?" screen (all 6
languages) pointing to the native "Search by address" option added in
the previous commit, plus the same tip to the README's Getting Started
section.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a new AddressSearchScreen: enter an address on a dedicated
keyboard (with a special-character page for common European accented
letters), geocode it via the free OpenStreetMap Nominatim service,
confirm the found place, optionally name it, and save it as a new
location preset - no external website needed anymore.
Reachable both from Location Presets > "+" (choice between "by
address" and manual coordinates) and, for new users, from a one-time
FirstRunLocationScreen shown right after the language picker on first
boot, explaining why an exact address beats automatic IP geolocation
and letting them set it up immediately (skippable).
Removes the itilog.com link/tip added in the previous commit (Location
Presets info screen, all 6 languages, and the README) - superseded by
this native in-app flow.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a new info paragraph to the Location Presets "?" screen (all 6
languages) recommending itilog.com for getting exact address
coordinates, since automatic IP-based geolocation can easily be off by
20-30 km - enough to hear a plane while the radar stays empty. Adds
the same tip to the README's Getting Started section, with a
clickable link.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
README, index.html, GitHub release notes, commit messages, and any
other publicly visible description text must always be written in
English, regardless of the conversation language with Alex. The
on-device firmware UI stays multilingual as before (i18n_*.h); this
rule only covers the project's outward-facing presentation.
Bumps the web flasher version display to v3.0.1 and refreshes
firmware.bin to match the v3.0.1 build output.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The trail/tail-line rendering behind each aircraft marker was already
superseded by the heading arrowhead in drawAircraftMarker() but was
never removed, so it kept running in parallel (dimColorForAltitude,
TrailEntry, clearTrails/pruneStaleTrails/findOrCreateTrail/
pushTrailPoint/drawTrail, and their call sites in render(), tick() and
handleTap()) - all removed as dead weight.
The proximity-alert blink-off phase used to paint a flat 40x30px black
rectangle over each nearby aircraft to hide it, which also blacked out
the radar rings/compass lines underneath regardless of altitude color
(the blink logic is purely distance-based). Now redraws the exact same
shapes used for normal rendering (marker, emergency/watchlist ring,
label) in black instead, so only the aircraft itself disappears during
the blink-off phase.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two bugs from the radar info marquee: the line briefly blinked on
every fetch cycle (visible in sync with the heartbeat LED) because
render() clears the line but tick() didn't redraw it for up to 80ms;
fixed by having render() immediately redraw the marquee at its current
scroll state right after clearing.
The "empty sky since..." text never scrolled even as it grew longer,
because needsScroll was only computed once when the marquee was first
set up (with the short "...0s" text) and never re-checked as the text
grew. updateInfoMarqueeText() now re-evaluates needsScroll on every
call.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The bottom info line on the radar screen (tap hint / empty-sky timer)
is now a continuously scrolling marquee instead of static text,
consistent with the nearest-airport ticker on the Location Presets
screen. The text is redrawn every tick() call (80ms) rather than only
on render(), so it scrolls smoothly and the empty-sky second counter
keeps advancing fluidly.
Also clarifies the tap hint in all 6 languages to make it explicit
that you need to tap an aircraft (e.g. "Tap an aircraft for more
details" instead of the more ambiguous "Tap for details").
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Embeds the cookieless GoatCounter base script and marks the ESP Web
Tools install button with data-goatcounter-click/title attributes, so
actual flash-button clicks (not just page views) are counted and
visible at https://eiswolf-bg.goatcounter.com.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bumps the web flasher version display to v3.0.0 and refreshes
firmware.bin to match the v3.0.0 build output.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bumps to v3.0.0. Documents the inactivity screen timeout now turning
the display fully off instead of just dimming it (feature landed in
the previous commit).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>