Skip to content

jduanen/FlightScanner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

51 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FlightScanner for LilyGO T-Encoder Pro

This is a modification of the work in https://github.com/yashmulgaonkar/FlightScnr.

Go there for all information about the original project and buy him a coffee:

Buy Me a Coffee

Firmware is released under CC BY-NC-SA 4.0 (see LICENSE) instead of MIT. Permissive MIT licensing on similar projects has made it easy for vendors to ship closed derivatives without keeping firmware open to the community. This license keeps the source shareable for hobbyists and open-source builders while discouraging proprietary takeaways.

Modifications to the original project and their motivations

I attempted to leave as much as possible of the excellent original project intact, while adding support for my local services and implementation choices.

One of the bigger changes to the project is to make the device battery-powered so that it can be carried around the house with me. To this end, I added a battery with a Qi-based wireless charging capability.

I added a Sparkfun Electronics Battery Babysitter board which allows the LilyGO device to remain powered on while the battery is being charged. This battery management board has a LiPo fuel gauge function available over I2C, that provides a series of metrics on the battery (e.g., its charge/discharge state, percentage of total charge remaining, etc.). I added a display page with this information, as well as adding the battery information to the Settings web page.

I want the device to stay powered on at all times so that it will provide instant information. I also want the battery and display to last as long as possible, so I want to implement a screen blanking function that triggers after some period of time (or whenever the device is placed on a wireless charger). Whenever the display is blanked, tapping the touchscreen (or removing it from the charger) with result in the display being instantly turned back on.

I added a screen-blanking function that turns the display on whenever the screen is touched (or the device is removed from the charger) and starts a timer that is reset every time the device is touched again. When this timer expires, the display is turned off. The display is turned on at boot time, when the screen is touched, or when the device is removed from the charging pad. The display remains on until a given time interval after the last time it was touched.

I added a REST API to allow programmatic changes to the settings offered in the application's Settings web page.

I added an in-RAM log capture that collects all diagnostic output since boot and makes it available via a browser page and REST endpoint, so the device can be debugged over Wi-Fi without a USB cable.

Use local ADS-B and Route Service

I have my own (unfiltered, 1080MHz and 980MHz) ADS-B receiver as well as a LAN-based service that provides additional information on flights (such as airline, route, airport, etc.) that I would like to use instead of the built in web-based services in the original project. The information server handles caching as well as falling back to different cloud-based APIs for this, as well as other applications in my home.

See AircraftRoute for more information about this service.

Add support for Sparkfun Battery Babysitter

The Sparkfun Battery Babysitter board's BQ27441-G1A fuel gauge is connected via the T-Encoder Pro's Qwiic port. The Qwiic connector's SDA/SCL pins are GPIO16/GPIO15 respectively (the ESP32-S3's XTAL_32K_N/XTAL_32K_P pads, repurposed as GPIO since no 32 kHz crystal is fitted). These are on a separate I2C bus (Wire1) from the internal touch controller bus (Wire, GPIO5/GPIO6).

The BQ27441 driver polls the gauge every 10 seconds and calls displayBlankingNotifyCharging() / displayBlankingNotifyUncharging() on charging-state transitions, so the display blanks when placed on the charger and wakes when removed.

Add time-based screen blanking

The blanking timeout is configurable via the settings web page ("Screen blanking" dropdown). Available options are Never, 30 seconds, 1 minute, 2 minutes, 5 minutes, and 10 minutes. The default is 1 minute. The setting is stored in NVS under the key blank_to_s and survives reboots.

Behavior:

  • The idle timer starts when setup completes (after Wi-Fi connects and the boot splash appears).
  • Any touch, swipe, knob press, or encoder rotation resets the timer. If the display was off, the triggering input wakes the display but is otherwise discarded — no accidental navigation occurs on wake.
  • The radar sweep animation is paused while the display is off to avoid unnecessary SPI writes.
  • hardware::displayBlankingNotifyCharging() and hardware::displayBlankingNotifyUncharging() are called by the BQ27441 driver whenever a charging-state transition is detected.

Add in-RAM log capture

All diagnostic output (every Log.printf / Log.println call in the firmware) is written to both the USB serial port and a 16 KB in-RAM buffer. The buffer is cleared on reboot and is not persisted to flash.

The buffer is exposed two ways:

  • http://flightscanner.local/log — browser page with a live-updating log viewer that auto-refreshes every 5 seconds and scrolls to the most recent entry.
  • GET /api/log — raw text/plain endpoint returning the full buffer, suitable for scripting (see REST API section below).

When the buffer is full, new output continues to reach the serial port but is no longer appended to the buffer. The /log page displays "(buffer full)" in the status line when this happens.

The global Log object (a Print-derived LogCapture class in include/services/log_capture.h) replaces all direct Serial.printf / Serial.println calls in the firmware. To add a log statement in new code:

#include "services/log_capture.h"
Log.printf("[module] message: %d\n", value);

Add a REST API to Settings

All settings on the flightscanner.local page are also accessible via a REST API served on port 80. Unlike the HTML form, API writes take effect immediately without a reboot (brightness is applied live; route server URL takes effect on the next lookup).

GET /api/settings

Returns all current settings as JSON.

GET http://flightscanner.local/api/settings
curl -X GET http://flightscanner.local/api/settings | jq '.'
{
  "radar_center": "37.619770, -122.372270",
  "use_miles": false,
  "show_cardinals": true,
  "show_sweep": true,
  "detail_timeout": 10,
  "bright_pct": 80,
  "blank_timeout": 60,
  "ui_beep": true,
  "beep_tone": "B",
  "min_height": 500,
  "range_idx": 2,
  "route_server_url": "http://192.168.1.x:5000"
}

POST /api/settings

Updates one or more settings. Send a JSON body with only the fields you want to change. Returns the full settings object after applying changes.

POST http://flightscanner.local/api/settings
Content-Type: application/json

{"bright_pct": 85, "blank_timeout": 120}
curl -X POST http://flightscanner.local/api/settings -H 'Content-Type: application/json' -d '{"bright_pct": 85, "blank_timeout": 120}'
Field Type Values
radar_center string "lat, lon" decimal degrees
use_miles bool
show_cardinals bool
show_sweep bool
detail_timeout int 0 (manual), 10, 20, 30
bright_pct int 20, 40, 60, 80, 100
blank_timeout int 0 (never), 30, 60, 120, 300, 600
ui_beep bool
beep_tone string "A""E"
min_height int feet, 0 = off
range_idx int 0N-1 (see radar scale bands)
route_server_url string base URL, e.g. "http://192.168.1.x:5000"

Invalid or out-of-range values for a field are silently ignored (the field is left unchanged).

GET /log

Live log viewer (browser page). See the in-RAM log capture section for full details.

GET /api/log

Returns the full log buffer as text/plain.

curl http://flightscanner.local/api/log

GET /api/battery

Returns the current state of the BQ27441-G1A fuel gauge. If the gauge is not detected, only "present": false is returned.

GET http://flightscanner.local/api/battery
curl -X GET http://flightscanner.local/api/battery | jq '.'
{
  "present": true,
  "soc": 85,
  "voltage_mv": 3987,
  "current_ma": 450,
  "remain_mah": 1020,
  "full_mah": 1200,
  "time_to_empty_min": 0,
  "charging": true,
  "full": false
}
Field Type Description
present bool false if gauge not detected; remaining fields absent
soc int State of charge, 0–100%
voltage_mv int Battery voltage in mV
current_ma int Average current in mA; positive = charging, negative = discharging
remain_mah int Remaining capacity in mAh
full_mah int Full charge capacity in mAh
time_to_empty_min int Estimated minutes to empty (0 when charging or unknown)
charging bool true while charging current is positive
full bool true when FC flag is set

POST /api/reboot

Triggers a clean reboot. Use this after changes that require it (e.g. Wi-Fi settings).

POST http://flightscanner.local/api/reboot
{"status": "rebooting"}

Hardware

The hardware that I'm using a LilyGO T-Encoder Pro with a Sparkfun Battery Babysitter, a Qi Wireless Charging Receiver, and a LiPo battery. I also 3D modeled and printed an enclosure for these components.

LilyGO T-Encoder Pro

  • Key Features
    • ESP32-S3 R8
    • Flash: 16 MB
    • PSRAM: 8 MB
    • WiFi and BTLE5
    • 2x Qwiic 4x pin
    • USB-C
    • 1.2" 390x390 AMOLED Display (CO5300)
      • QSPI interface
    • CST816 Touchscreen Controller and Rotary Encoder
    • Buzzer
    • 5V @ 500mA

LilyGO T-Encoder Pro

Power Supply

Sparkfun Battery Babysitter

  • Key Features

    • allows charging of battery and suppling the output load with 5V
    • ????
    • the board includes a BQ27441-G1A LiPo fuel gauge
  • BQ27441-G1A LiPo Fuel Gauge

    • the LiPo fuel gauge has a (3.3V and 5V tolerant) I2C interface that is used to:
      • measure a battery's:
        • voltage (mV)
        • state-of-charge (%)
        • current (mA)
        • power (mW)
        • estimated remaining capacity (mAh)
      • set the battery's full-charge capacity
    • the I2C address of this device is 0x55
    • the LiPo fuel gauge has a programmable output, GPOUT, that can be used to signal:
      • low battery alert
      • change in state-of-charge

image here

Qi Wireless Charging Receiver

The wireless charging receiver unit consists of a coil and a small PCB. Most models also provide a self-adhesive-backed sheet of magnetic material to put on the back of the coil to improve the energy transfer and reduce the field effects on the colocated electronics.

image here

License

Firmware license

Original application code, tools, and documentation in this repository, as well as all modifications to it, are licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (LICENSE).

  • Attribution: credit the author and link to the license when you share or adapt this work.
  • NonCommercial: you may not use this material for commercial purposes without separate permission.
  • ShareAlike: adaptations must be released under the same license.

Vendored libraries (lib/Arduino_GFX, lib/SensorLib, and PlatformIO registry dependencies) remain under their own licenses (GPL, MIT, etc.). Combining them into a binary does not re-license those components. Comply with each upstream license when you distribute builds.


About

Modified version of FlightScnr by yashmulgaonkar

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors