FlightRadar
This is a real-time flight radar script for AWTRIX-NG that uses adsb.fi to retrieve and display information about the three nearest aircraft, including flight number, distance, altitude, speed, and direction, with alerts for overhead aircraft and emergenc
About this flow
| System | AWTRIX NG Scripts |
|---|---|
| AWTRIX version | AWTRIX NG |
| Topic | News |
| Built by | Anthony |
| File | lVAkm0aR5EvW.ax · 13.5 KB |
| Icons | — |
| Published | 6 Sep 2026 · updated 7 Sep 2026 |
| Downloads | 23 |
Is this your flow?
If you created this flow, open your saved edit link to add it to your account. You can then manage it whenever you sign in. Adding it to your account replaces the edit link.
Flow description
FlightRadar
A real-time flight radar script for AWTRIX-NG that retrieves nearby aircraft data from the adsb.fi API and displays it directly on your AWTRIX device.
Features
Real-Time Aircraft Tracking
The script finds and displays the three nearest aircraft within a configurable search radius.
Displayed Information
For each detected aircraft, the display can show:
- Flight number or aircraft hex ID
- Distance
- Altitude
- Ground speed
- Flight direction
Automatic Refresh
Aircraft data is refreshed automatically at a configurable interval.
You can adjust the refresh interval directly in the script settings.
Overhead Aircraft Alert
When the nearest aircraft comes within the configured overhead distance, the script sends a notification to the AWTRIX-NG device.
This can be used to alert you when an aircraft is flying close to your location.
Emergency Alerts
The script detects standard aviation emergency squawk codes:
- 7500 — Hijacking / unlawful interference
- 7600 — Radio communication failure
- 7700 — General emergency
When one of these emergency squawk codes is detected, AWTRIX-NG displays a red emergency alert notification.
Display Behavior
Aircraft information is displayed using rotating pages.
Each page includes:
- An animated airplane icon
- Scrolling aircraft information
- Automatic rotation between nearby aircraft
Customization
The following settings can be configured:
- Latitude
- Longitude
- Search radius
- Aircraft data refresh interval
- Page duration
- Overhead alert distance
- Notification duration
- Airplane color
Data Source
Aircraft data is retrieved from the adsb.fi API.
Requirements
- Internet connection
- Access to the adsb.fi API
- Correct latitude and longitude configured for your location
lVAkm0aR5EvW.ax
# @name FlightRadar
# @desc Nearest 3 aircraft via adsb.fi
# @version 1.5-lite
# @config lat text "Latitude" default="31.2304" maxlen=16
# @config lon text "Longitude" default="121.4737" maxlen=16
# @config radius number "Radius" default=100 min=5 max=450 step=5 unit=km
# @config refresh number "Refresh Interval" default=30 min=15 max=300 unit=s
# @config page number "Page Duration" default=3 min=2 max=8 unit=s
# @config overhead number "Overhead Distance" default=5 min=1 max=30 unit=km
# @config alert bool "Overhead Alert" default=true
# @config emergency bool "Emergency Alert" default=true
# @config alertsec number "Notification Duration" default=8 min=3 max=30 unit=s
# @config tint color "Aircraft Color" default=#33AAFF
class FlightRadar
var url
var ticks
var busy
var pages
var count
var status
var error
var shown
var page_ms
var color
var nhex
var nflight
var ndist
var nalt
var nspd
var ntrk
var ndir
var last_over
var last_emg
var opts
def init()
var km = store.get("radius")
if km == nil km = 100 end
if km < 5 km = 5 end
if km > 463 km = 463 end
var nm = int(km / 1.852)
if nm < 1 nm = 1 end
if nm > 250 nm = 250 end
self.url = "https://opendata.adsb.fi/api/v3/lat/" +
store.get("lat") + "/lon/" + store.get("lon") +
"/dist/" + str(nm)
self.ticks = 0
self.busy = false
self.pages = []
self.count = 0
self.status = "SCAN..."
self.error = false
self.shown = now_ms()
self.page_ms = store.get("page") * 1000
self.color = store.get("tint")
if self.color == nil self.color = 0x33AAFF end
self.nhex = nil
self.nflight = nil
self.ndist = nil
self.nalt = nil
self.nspd = nil
self.ntrk = nil
self.ndir = ""
self.last_over = nil
self.last_emg = nil
self.opts = {
"mode":"wrap",
"speed":75,
"holdMs":500
}
shared.set("active", false)
shared.set("count", 0)
shared.set("status", "scan")
end
def dir(v)
if v == nil return "" end
if v >= 337.5 || v < 22.5 return "N" end
if v < 67.5 return "NE" end
if v < 112.5 return "E" end
if v < 157.5 return "SE" end
if v < 202.5 return "S" end
if v < 247.5 return "SW" end
if v < 292.5 return "W" end
return "NW"
end
def emg(s)
if s == "7500" return "HIJACK" end
if s == "7600" return "RADIO" end
if s == "7700" return "EMERG" end
return nil
end
def km1(v)
var n = int(v * 10 + 0.5)
return str(int(n / 10)) + "." + str(n % 10) + "KM"
end
def on_body(body, st)
self.busy = false
if st == 0
self.error = true
self.status = "NET ERR"
shared.set("status", "network")
return
end
if st != 200
self.error = true
self.status = "HTTP " + str(st)
shared.set("status", self.status)
return
end
if body == nil
self.pages = []
self.count = 0
self.status = "NO FLT"
self.error = false
self.nhex = nil
self.last_over = nil
self.last_emg = nil
shared.set("active", false)
shared.set("count", 0)
shared.set("status", "empty")
return
end
var ps = re.matchall(
"[{][^{}]*\"hex\":\"[A-Za-z0-9]+\"[^{}]*[}]",
body
)
if ps == nil || size(ps) == 0
self.pages = []
self.count = 0
self.status = "NO FLT"
self.error = false
shared.set("active", false)
shared.set("count", 0)
shared.set("status", "empty")
return
end
var bo = [nil,nil,nil]
var bd = [999999.0,999999.0,999999.0]
var fb = []
var ehex = nil
var eflight = nil
var esq = nil
for p : ps
if size(fb) < 3
fb.push(p)
end
var q = re.search(
"\"squawk\":\"([0-9]+)\"",
p
)
if q != nil &&
self.emg(q[1]) != nil &&
esq == nil
esq = q[1]
var eh = re.search(
"\"hex\":\"([A-Za-z0-9]+)",
p
)
if eh != nil
ehex = eh[1]
end
var ef = re.search(
"\"flight\":\"[ ]*([A-Za-z0-9]+)",
p
)
if ef != nil
eflight = ef[1]
else
eflight = ehex
end
end
var md = re.search(
"\"dst\":([0-9.]+)",
p
)
if md != nil
var d = num(md[1])
if d != nil
if d < bd[0]
bd[2] = bd[1]
bo[2] = bo[1]
bd[1] = bd[0]
bo[1] = bo[0]
bd[0] = d
bo[0] = p
elif d < bd[1]
bd[2] = bd[1]
bo[2] = bo[1]
bd[1] = d
bo[1] = p
elif d < bd[2]
bd[2] = d
bo[2] = p
end
end
end
end
if bo[0] == nil
var j = 0
while j < size(fb) && j < 3
bo[j] = fb[j]
bd[j] = -1
j += 1
end
end
var out = []
var c = 0
var i = 0
self.nhex = nil
self.nflight = nil
self.ndist = nil
self.nalt = nil
self.nspd = nil
self.ntrk = nil
self.ndir = ""
while i < 3
var p = bo[i]
if p != nil
var mh = re.search(
"\"hex\":\"([A-Za-z0-9]+)",
p
)
if mh != nil
var hx = mh[1]
var mf = re.search(
"\"flight\":\"[ ]*([A-Za-z0-9]+)",
p
)
var fl = hx
if mf != nil
fl = mf[1]
end
var dist = nil
if bd[i] >= 0
dist = bd[i] * 1.852
end
var alt = nil
var ma = re.search(
"\"alt_baro\":([-0-9.]+)",
p
)
if ma != nil
alt = num(ma[1])
else
ma = re.search(
"\"alt_geom\":([-0-9.]+)",
p
)
if ma != nil
alt = num(ma[1])
end
end
var sp = nil
var ms = re.search(
"\"gs\":([0-9.]+)",
p
)
if ms != nil
sp = num(ms[1])
end
var tr = nil
var mt = re.search(
"\"track\":([0-9.]+)",
p
)
if mt != nil
tr = num(mt[1])
end
var di = self.dir(tr)
# Page 1: flight + distance
var p1 =
str(i + 1) + " " + fl
if dist != nil
p1 =
p1 + " " +
self.km1(dist)
end
# Page 2: altitude + speed + direction
var p2 = str(i + 1)
if alt != nil
if alt >= 1000
p2 =
p2 + " " +
str(
int(
(alt + 500) /
1000
)
) +
"K"
else
p2 =
p2 + " " +
str(int(alt)) +
"FT"
end
end
if sp != nil
p2 =
p2 + " " +
str(int(sp)) +
"KT"
end
if di != ""
p2 =
p2 + " " +
di
end
out.push(p1)
out.push(p2)
c += 1
# Nearest aircraft
if i == 0
self.nhex = hx
self.nflight = fl
self.ndist = dist
self.nalt = alt
self.nspd = sp
self.ntrk = tr
self.ndir = di
end
end
end
i += 1
end
self.pages = out
self.count = c
self.error = false
if c > 0
self.status = "LIVE"
shared.set("status", "ok")
else
self.status = "NO FLT"
shared.set("status", "empty")
end
shared.set("active", c > 0)
shared.set("count", c)
# Shared: nearest aircraft
if self.nhex != nil
shared.set(
"flight",
self.nflight
)
shared.set(
"hex",
self.nhex
)
if self.ndist != nil
shared.set(
"distance_km",
self.ndist
)
else
shared.set(
"distance_km",
-1
)
end
if self.nalt != nil
shared.set(
"altitude_ft",
self.nalt
)
else
shared.set(
"altitude_ft",
-1
)
end
if self.nspd != nil
shared.set(
"speed_kt",
self.nspd
)
else
shared.set(
"speed_kt",
-1
)
end
if self.ntrk != nil
shared.set(
"heading_deg",
self.ntrk
)
else
shared.set(
"heading_deg",
-1
)
end
shared.set(
"direction",
self.ndir
)
end
# ==========================================
# Overhead aircraft alert
# ==========================================
if store.get("alert") &&
self.nhex != nil &&
self.ndist != nil &&
self.ndist <= store.get("overhead")
if self.nhex != self.last_over
notify({
"text":
"OVERHEAD " +
self.nflight +
" " +
self.km1(self.ndist),
"textColor":
0xFFFF00,
"durationMs":
store.get("alertsec") *
1000,
"wakeup":
true,
"stack":
false
})
self.last_over =
self.nhex
end
elif self.ndist == nil ||
self.ndist > store.get("overhead")
self.last_over = nil
end
# ==========================================
# 7500 / 7600 / 7700
# ==========================================
if esq != nil &&
store.get("emergency")
var eid =
ehex + ":" + esq
if eid != self.last_emg
notify({
"text":
self.emg(esq) +
" " +
esq +
" " +
eflight,
"textColor":
0xFF0000,
"durationMs":
store.get("alertsec") *
1000,
"wakeup":
true,
"stack":
false
})
self.last_emg = eid
end
else
self.last_emg = nil
end
end
# ============================================
# Periodically fetch aircraft data
# ============================================
def loop()
if self.ticks <= 0
var r = store.get("refresh")
if r == nil || r < 15
r = 30
end
self.ticks = r
if !self.busy
self.busy = true
if self.count == 0 &&
!self.error
self.status =
"SCAN..."
end
http.get(
self.url,
/ b, st ->
self.on_body(b, st),
{
"find":
"\"ac\":[",
"keep":
8192,
"headers":{
"User-Agent":
"AWTRIX-NG/FlightRadar",
"Accept":
"application/json"
}
}
)
end
end
self.ticks -= 1
end
def on_show()
self.shown = now_ms()
end
# Show all aircraft pages before switching to the next app
def duration()
var n = size(self.pages)
if n < 1
return self.page_ms
end
return self.page_ms * n
end
# ============================================
# Aircraft icon
# ============================================
def draw_plane()
var x =
int(now_ms() / 500) % 2
# Fuselage
line(
x + 3,
0,
x + 3,
7,
self.color
)
# Wings
line(
x,
3,
x + 6,
3,
self.color
)
pixel(
x + 1,
2,
self.color
)
pixel(
x + 5,
2,
self.color
)
# Tail
line(
x + 2,
6,
x + 4,
6,
self.color
)
# Red flashing light
if now_ms() % 1000 < 150
pixel(
x + 6,
3,
0xFF0000
)
end
end
# ============================================
# Rendering
# ============================================
def draw()
clear()
self.draw_plane()
if self.error
pixel(
width() - 1,
0,
0xFF0000
)
end
var label =
self.status
var col =
0x666666
var n =
size(self.pages)
if n > 0
var p =
int(
(now_ms() - self.shown) /
self.page_ms
) % n
label =
self.pages[p]
col =
settings.get("textColor")
if col == nil
col = 0xFFFFFF
end
elif self.error
col = 0xFF4444
end
scroll_text(
8,
6,
width() - 8,
label,
col,
self.opts
)
end
end
return FlightRadar()
Install it on your AWTRIX NG
Add this flow to your AWTRIX NG. It will start appearing on your display after installation.
Unable to connect? Download the flow and add it in the Scripts section of your AWTRIX. Advanced users can also use this command:
Discussion 0
Ask a question, suggest a change or share how you use it.
No comments yet. Start the conversation.
More flows for AWTRIX NG Scripts or News
Something wrong with this flow? Report it.
Have an idea?
Sign in to ask questions and join the conversation.