ADS-B Radar Display

Your own real-time information display for flights overhead

Now that you have your own ADS-B receiver, and you’re running ADS-B Radar on your Mac, perhaps it would be great to know what airplane is currently overhead when you’re getting a coffee 🙂

The Raspberry Pico W and the Pico Display from Pimoroni come to the rescue. Although the display is really small, it has a super low power consumption and you can easily place it somewhere discrete.

 

 

What will you need:

  • Pico WH (WiFi version with header) – Approx. 9 EUR
  • Pimoroni Pico Display Pack unit – Approx. 18 EUR

As we are already processing ADS-B signals with a Raspberry Pi Zero and dump1090, we will use this to pre-process the data we need for the Pico W. This will make it easier on the small Pico, which has limited capabilities.

There are two options, use FR24 or use a public API adsbdb.com.

#1: FR24:

To retrieve more interesting data, we need to use the FR24 API.
PS: It seems the API is offline or no longer for free.
Install like this on your Pi that feeds FR24:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
pip3 install FlightRadar24
pip3 install FlightRadar24
pip3 install FlightRadar24

Then we create a little shell script named “overhead.sh” which we will run every two minutes once we’re ready:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/bin/bash
python3 /home/pi/overhead.py
chmod 777 /tmp/overhead.json
#!/bin/bash python3 /home/pi/overhead.py chmod 777 /tmp/overhead.json
#!/bin/bash
python3 /home/pi/overhead.py
chmod 777 /tmp/overhead.json

This will be the main Python script to process the JSON file from FR24, name it “overhead.py”. Make sure to enter the correct LAT & LON of your home receiver and figure out the search area, which is a rectangle defined by a top left and bottom right LAT/LON coordinate. You can use Apple Maps and drop a pin to get these:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/usr/bin/env python3
# Find closest airplane flying overhead
# (c) JF Nutbroek
# 08/10/2023
from FlightRadar24 import FlightRadar24API
from urllib.request import urlopen
from datetime import datetime
from datetime import timezone
import math
import json
# User defined
url = "http://localhost/dump1090/data/aircraft.json"
lathome = 45.9 # Position ADS-B receiver
lonhome = 6.3 # Position ADS-B receiver
zone = {"tl_y": 46.23, "tl_x": 5.93, "br_y": 45.66, "br_x": 6.83} # Search area topleft x bottomright
### Start
# Haversine formula example in Python
# Author: Wayne Dyck
def distance(origin, destination):
lat1, lon1 = origin
lat2, lon2 = destination
radius = 6371 # km earth radius
dlat = math.radians(lat2-lat1)
dlon = math.radians(lon2-lon1)
a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(lat1)) \
* math.cos(math.radians(lat2)) * math.sin(dlon/2) * math.sin(dlon/2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
d = radius * c
return d
# Convert timestamp to UTC
def process_timestamp(timestamp):
if timestamp and timestamp != 0:
date = datetime.fromtimestamp(timestamp, timezone.utc)
utc = date.strftime("%H:%M")
else:
utc = ""
return utc
# Find flights in specified zone
def find_flight(inzone, flightid):
fr_api = FlightRadar24API()
bounds = fr_api.get_bounds(inzone)
flights = fr_api.get_flights(bounds=bounds)
for thisflight in flights:
if flightid in thisflight.callsign.replace(" ", "").upper():
flightdetails = fr_api.get_flight_details(thisflight.id)
return thisflight, flightdetails
return None, None
# Write JSON for Pico W
def writeresult(flightdict):
json_object = json.dumps(flightdict)
with open("/tmp/overhead.json", "w", encoding="utf-8") as outfile:
outfile.write(json_object)
### Find the closest airplane
aircraft = []
try:
response = urlopen(url)
data_json = json.loads(response.read())
aircraft = data_json['aircraft']
except:
exit()
closest = 1000 # km distance of closest plane
closestflight = '' # Will hold flight number
dictionary = {"flight":"none"} # Empty dictionary
speed = 0
vert_rate = 0
altitude = 0
compass = ["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW","N"]
track = 0
heading = ""
newflight = True
for airplane in aircraft:
if 'lat' in airplane:
if 'lon' in airplane:
if 'flight' in airplane:
if 'altitude' in airplane:
altitude = int(airplane['altitude'])
if 'vert_rate' in airplane:
vert_rate = int(airplane['vert_rate'])
if 'speed' in airplane:
speed = int(airplane['speed'])
if 'track' in airplane:
track = int(airplane['track'])
heading = str(track) + " degrees " + compass[min(round((track % 360) / 22.5), 16)]
flightdis = distance((lathome, lonhome), (airplane['lat'], airplane['lon']))
flighthgt = altitude * 0.0003048
dis = math.floor(math.sqrt(flightdis**2 + flighthgt**2))
if dis < closest:
closest = dis
closestflight = airplane['flight'].replace(" ", "").upper()
if closestflight != '':
rangekm = distance((zone["tl_y"], zone["tl_x"]), (zone["br_y"], zone["br_x"])) / 2
if closest < rangekm:
flight, details = find_flight(zone, closestflight)
if flight != None:
dictionary = {
"flight": flight.number,
"airline": details["airline"]["name"],
"altitude": str(altitude),
"vert_rate": str(vert_rate),
"speed": str(speed),
"origin_iata": flight.origin_airport_iata,
"destination_iata": flight.destination_airport_iata,
"model": details["aircraft"]["model"]["text"],
"origin": details["airport"]["origin"]["name"],
"destination": details["airport"]["destination"]["name"],
"departure": process_timestamp(details["time"]["real"]["departure"]),
"eta": process_timestamp(details["time"]["other"]["eta"]),
"distance": str(closest),
"track": heading
}
writeresult(dictionary)
else:
writeresult(dictionary)
else:
writeresult(dictionary)
else:
writeresult(dictionary)
#!/usr/bin/env python3 # Find closest airplane flying overhead # (c) JF Nutbroek # 08/10/2023 from FlightRadar24 import FlightRadar24API from urllib.request import urlopen from datetime import datetime from datetime import timezone import math import json # User defined url = "http://localhost/dump1090/data/aircraft.json" lathome = 45.9 # Position ADS-B receiver lonhome = 6.3 # Position ADS-B receiver zone = {"tl_y": 46.23, "tl_x": 5.93, "br_y": 45.66, "br_x": 6.83} # Search area topleft x bottomright ### Start # Haversine formula example in Python # Author: Wayne Dyck def distance(origin, destination): lat1, lon1 = origin lat2, lon2 = destination radius = 6371 # km earth radius dlat = math.radians(lat2-lat1) dlon = math.radians(lon2-lon1) a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(lat1)) \ * math.cos(math.radians(lat2)) * math.sin(dlon/2) * math.sin(dlon/2) c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)) d = radius * c return d # Convert timestamp to UTC def process_timestamp(timestamp): if timestamp and timestamp != 0: date = datetime.fromtimestamp(timestamp, timezone.utc) utc = date.strftime("%H:%M") else: utc = "" return utc # Find flights in specified zone def find_flight(inzone, flightid): fr_api = FlightRadar24API() bounds = fr_api.get_bounds(inzone) flights = fr_api.get_flights(bounds=bounds) for thisflight in flights: if flightid in thisflight.callsign.replace(" ", "").upper(): flightdetails = fr_api.get_flight_details(thisflight.id) return thisflight, flightdetails return None, None # Write JSON for Pico W def writeresult(flightdict): json_object = json.dumps(flightdict) with open("/tmp/overhead.json", "w", encoding="utf-8") as outfile: outfile.write(json_object) ### Find the closest airplane aircraft = [] try: response = urlopen(url) data_json = json.loads(response.read()) aircraft = data_json['aircraft'] except: exit() closest = 1000 # km distance of closest plane closestflight = '' # Will hold flight number dictionary = {"flight":"none"} # Empty dictionary speed = 0 vert_rate = 0 altitude = 0 compass = ["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW","N"] track = 0 heading = "" newflight = True for airplane in aircraft: if 'lat' in airplane: if 'lon' in airplane: if 'flight' in airplane: if 'altitude' in airplane: altitude = int(airplane['altitude']) if 'vert_rate' in airplane: vert_rate = int(airplane['vert_rate']) if 'speed' in airplane: speed = int(airplane['speed']) if 'track' in airplane: track = int(airplane['track']) heading = str(track) + " degrees " + compass[min(round((track % 360) / 22.5), 16)] flightdis = distance((lathome, lonhome), (airplane['lat'], airplane['lon'])) flighthgt = altitude * 0.0003048 dis = math.floor(math.sqrt(flightdis**2 + flighthgt**2)) if dis < closest: closest = dis closestflight = airplane['flight'].replace(" ", "").upper() if closestflight != '': rangekm = distance((zone["tl_y"], zone["tl_x"]), (zone["br_y"], zone["br_x"])) / 2 if closest < rangekm: flight, details = find_flight(zone, closestflight) if flight != None: dictionary = { "flight": flight.number, "airline": details["airline"]["name"], "altitude": str(altitude), "vert_rate": str(vert_rate), "speed": str(speed), "origin_iata": flight.origin_airport_iata, "destination_iata": flight.destination_airport_iata, "model": details["aircraft"]["model"]["text"], "origin": details["airport"]["origin"]["name"], "destination": details["airport"]["destination"]["name"], "departure": process_timestamp(details["time"]["real"]["departure"]), "eta": process_timestamp(details["time"]["other"]["eta"]), "distance": str(closest), "track": heading } writeresult(dictionary) else: writeresult(dictionary) else: writeresult(dictionary) else: writeresult(dictionary)
#!/usr/bin/env python3
# Find closest airplane flying overhead
# (c) JF Nutbroek
# 08/10/2023

from FlightRadar24 import FlightRadar24API
from urllib.request import urlopen
from datetime import datetime
from datetime import timezone

import math
import json

# User defined

url     = "http://localhost/dump1090/data/aircraft.json"
lathome = 45.9  # Position ADS-B receiver
lonhome = 6.3   # Position ADS-B receiver
zone    = {"tl_y": 46.23, "tl_x": 5.93, "br_y": 45.66, "br_x": 6.83} # Search area topleft x bottomright

### Start

# Haversine formula example in Python
# Author: Wayne Dyck
def distance(origin, destination):
    lat1, lon1 = origin
    lat2, lon2 = destination
    radius = 6371 # km earth radius
    dlat = math.radians(lat2-lat1)
    dlon = math.radians(lon2-lon1)
    a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(lat1)) \
        * math.cos(math.radians(lat2)) * math.sin(dlon/2) * math.sin(dlon/2)
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
    d = radius * c
    return d

# Convert timestamp to UTC
def process_timestamp(timestamp):
    if timestamp and timestamp != 0:
        date = datetime.fromtimestamp(timestamp, timezone.utc)
        utc = date.strftime("%H:%M")
    else:
        utc = ""
    return utc

# Find flights in specified zone
def find_flight(inzone, flightid):
    fr_api  = FlightRadar24API()
    bounds  = fr_api.get_bounds(inzone)
    flights = fr_api.get_flights(bounds=bounds)
    for thisflight in flights:
        if flightid in thisflight.callsign.replace(" ", "").upper():
            flightdetails = fr_api.get_flight_details(thisflight.id)
            return thisflight, flightdetails
    return None, None

# Write JSON for Pico W
def writeresult(flightdict):
    json_object = json.dumps(flightdict)
    with open("/tmp/overhead.json", "w", encoding="utf-8") as outfile:
        outfile.write(json_object)

### Find the closest airplane

aircraft = []

try:
    response = urlopen(url)
    data_json = json.loads(response.read())
    aircraft = data_json['aircraft']
except:
    exit()

closest       = 1000               # km distance of closest plane
closestflight = ''                 # Will hold flight number
dictionary    = {"flight":"none"}  # Empty dictionary
speed         = 0
vert_rate     = 0
altitude      = 0
compass       = ["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW","N"]
track         = 0
heading       = ""
newflight     = True

for airplane in aircraft:
    if 'lat' in airplane:
        if 'lon' in airplane:
            if 'flight' in airplane:
                if 'altitude' in airplane:
                    altitude = int(airplane['altitude'])
                    if 'vert_rate' in airplane:
                        vert_rate = int(airplane['vert_rate'])
                    if 'speed' in airplane:
                        speed = int(airplane['speed'])
                    if 'track' in airplane:
                        track = int(airplane['track'])
                        heading =  str(track) + " degrees " + compass[min(round((track % 360) / 22.5), 16)]
                    flightdis = distance((lathome, lonhome), (airplane['lat'], airplane['lon']))
                    flighthgt = altitude * 0.0003048
                    dis = math.floor(math.sqrt(flightdis**2 + flighthgt**2))
                    if dis < closest:
                        closest = dis
                        closestflight = airplane['flight'].replace(" ", "").upper()

if closestflight != '':
    rangekm = distance((zone["tl_y"], zone["tl_x"]), (zone["br_y"], zone["br_x"])) / 2
    if closest < rangekm:
        flight, details = find_flight(zone, closestflight)
        if flight != None:
            dictionary = {
                "flight": flight.number,
                "airline": details["airline"]["name"],
                "altitude": str(altitude),
                "vert_rate": str(vert_rate),
                "speed": str(speed),
                "origin_iata": flight.origin_airport_iata,
                "destination_iata": flight.destination_airport_iata,
                "model": details["aircraft"]["model"]["text"],
                "origin": details["airport"]["origin"]["name"],
                "destination": details["airport"]["destination"]["name"],
                "departure": process_timestamp(details["time"]["real"]["departure"]),
                "eta": process_timestamp(details["time"]["other"]["eta"]),
                "distance": str(closest),
                "track": heading
                }
            writeresult(dictionary)
        else:
            writeresult(dictionary)
    else:
        writeresult(dictionary)
else:
    writeresult(dictionary)

 

#2 Use the adsbdb.com public API:

Independent on the FR24 API (which is not official), you can also use a public API called adsbdb.com. Create a little shell script named “overhead.sh” which we will run every two minutes once we’re ready:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/bin/bash
python3 /home/pi/overhead.py
chmod 777 /tmp/overhead.json
#!/bin/bash python3 /home/pi/overhead.py chmod 777 /tmp/overhead.json
#!/bin/bash
python3 /home/pi/overhead.py
chmod 777 /tmp/overhead.json

This will be the main Python script to process the JSON file from adsbdb.com, name it “overhead.py”:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/usr/bin/env python3
#!/usr/bin/env python3
# Find closest airplane flying overhead
# (c) JF Nutbroek
# 08/10/2023
from urllib.request import urlopen
from datetime import datetime
from datetime import timezone
import math
import json
# User defined
url = "http://localhost/dump1090/data/aircraft.json"
lathome = 45.9 # Position ADS-B receiver
lonhome = 6.3 # Position ADS-B receiver
### Start
# Haversine formula example in Python
# Author: Wayne Dyck
def distance(origin, destination):
lat1, lon1 = origin
lat2, lon2 = destination
radius = 6371 # km earth radius
dlat = math.radians(lat2-lat1)
dlon = math.radians(lon2-lon1)
a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(lat1)) \
* math.cos(math.radians(lat2)) * math.sin(dlon/2) * math.sin(dlon/2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
d = radius * c
return d
# Find flights
def find_adsbdb(flightid, hex):
try:
if hex == "":
response = urlopen("https://api.adsbdb.com/v0/callsign/" + flightid)
else:
response = urlopen("https://api.adsbdb.com/v0/aircraft/" + hex + "?callsign=" + flightid)
data_json = json.loads(response.read())
aircraft = data_json['response']
if flightid in aircraft['flightroute']['callsign_icao']:
return flightid, aircraft
else:
return None, None
except:
return None, None
# Write JSON for Pico W
def writeresult(flightdict):
json_object = json.dumps(flightdict)
with open("/tmp/overhead.json", "w", encoding="utf-8") as outfile:
outfile.write(json_object)
### Find the closest airplane
aircraft = []
try:
response = urlopen(url)
data_json = json.loads(response.read())
aircraft = data_json['aircraft']
except:
exit()
closest = 1000 # km distance of closest plane
closestflight = '' # Will hold flight number
dictionary = {"flight":"none"} # Empty dictionary
speed = 0
vert_rate = 0
altitude = 0
compass = ["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW","N"]
track = 0
heading = ""
newflight = True
hex = ""
for airplane in aircraft:
if 'lat' in airplane:
if 'lon' in airplane:
if 'flight' in airplane:
if 'altitude' in airplane:
altitude = int(airplane['altitude'])
if 'hex' in airplane:
hex = airplane['hex']
if 'vert_rate' in airplane:
vert_rate = int(airplane['vert_rate'])
if 'speed' in airplane:
speed = int(airplane['speed'])
if 'track' in airplane:
track = int(airplane['track'])
heading = str(track) + " degrees " + compass[min(round((track % 360) / 22.5), 16)]
flightdis = distance((lathome, lonhome), (airplane['lat'], airplane['lon']))
flighthgt = altitude * 0.0003048
dis = math.floor(math.sqrt(flightdis**2 + flighthgt**2))
if dis < closest:
closest = dis
closestflight = airplane['flight'].replace(" ", "").upper()
if closestflight != '':
#print(closestflight)
#print(hex)
flight, details = find_adsbdb(closestflight, hex)
if flight != None:
dictionary = {
"flight": flight,
"airline": details["flightroute"]["airline"]["name"],
"altitude": str(altitude),
"vert_rate": str(vert_rate),
"speed": str(speed),
"origin_iata": details["flightroute"]["origin"]["iata_code"],
"destination_iata": details["flightroute"]["destination"]["iata_code"],
"model": details["aircraft"]["type"],
"origin": details["flightroute"]["origin"]["name"],
"destination": details["flightroute"]["destination"]["name"],
"departure": "",
"eta": "",
"distance": str(closest),
"track": heading
}
writeresult(dictionary)
else:
writeresult(dictionary)
else:
writeresult(dictionary)
#!/usr/bin/env python3 #!/usr/bin/env python3 # Find closest airplane flying overhead # (c) JF Nutbroek # 08/10/2023 from urllib.request import urlopen from datetime import datetime from datetime import timezone import math import json # User defined url = "http://localhost/dump1090/data/aircraft.json" lathome = 45.9 # Position ADS-B receiver lonhome = 6.3 # Position ADS-B receiver ### Start # Haversine formula example in Python # Author: Wayne Dyck def distance(origin, destination): lat1, lon1 = origin lat2, lon2 = destination radius = 6371 # km earth radius dlat = math.radians(lat2-lat1) dlon = math.radians(lon2-lon1) a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(lat1)) \ * math.cos(math.radians(lat2)) * math.sin(dlon/2) * math.sin(dlon/2) c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)) d = radius * c return d # Find flights def find_adsbdb(flightid, hex): try: if hex == "": response = urlopen("https://api.adsbdb.com/v0/callsign/" + flightid) else: response = urlopen("https://api.adsbdb.com/v0/aircraft/" + hex + "?callsign=" + flightid) data_json = json.loads(response.read()) aircraft = data_json['response'] if flightid in aircraft['flightroute']['callsign_icao']: return flightid, aircraft else: return None, None except: return None, None # Write JSON for Pico W def writeresult(flightdict): json_object = json.dumps(flightdict) with open("/tmp/overhead.json", "w", encoding="utf-8") as outfile: outfile.write(json_object) ### Find the closest airplane aircraft = [] try: response = urlopen(url) data_json = json.loads(response.read()) aircraft = data_json['aircraft'] except: exit() closest = 1000 # km distance of closest plane closestflight = '' # Will hold flight number dictionary = {"flight":"none"} # Empty dictionary speed = 0 vert_rate = 0 altitude = 0 compass = ["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW","N"] track = 0 heading = "" newflight = True hex = "" for airplane in aircraft: if 'lat' in airplane: if 'lon' in airplane: if 'flight' in airplane: if 'altitude' in airplane: altitude = int(airplane['altitude']) if 'hex' in airplane: hex = airplane['hex'] if 'vert_rate' in airplane: vert_rate = int(airplane['vert_rate']) if 'speed' in airplane: speed = int(airplane['speed']) if 'track' in airplane: track = int(airplane['track']) heading = str(track) + " degrees " + compass[min(round((track % 360) / 22.5), 16)] flightdis = distance((lathome, lonhome), (airplane['lat'], airplane['lon'])) flighthgt = altitude * 0.0003048 dis = math.floor(math.sqrt(flightdis**2 + flighthgt**2)) if dis < closest: closest = dis closestflight = airplane['flight'].replace(" ", "").upper() if closestflight != '': #print(closestflight) #print(hex) flight, details = find_adsbdb(closestflight, hex) if flight != None: dictionary = { "flight": flight, "airline": details["flightroute"]["airline"]["name"], "altitude": str(altitude), "vert_rate": str(vert_rate), "speed": str(speed), "origin_iata": details["flightroute"]["origin"]["iata_code"], "destination_iata": details["flightroute"]["destination"]["iata_code"], "model": details["aircraft"]["type"], "origin": details["flightroute"]["origin"]["name"], "destination": details["flightroute"]["destination"]["name"], "departure": "", "eta": "", "distance": str(closest), "track": heading } writeresult(dictionary) else: writeresult(dictionary) else: writeresult(dictionary)
#!/usr/bin/env python3
#!/usr/bin/env python3
# Find closest airplane flying overhead
# (c) JF Nutbroek
# 08/10/2023

from urllib.request import urlopen
from datetime import datetime
from datetime import timezone

import math
import json

# User defined

url     = "http://localhost/dump1090/data/aircraft.json"
lathome = 45.9  # Position ADS-B receiver
lonhome = 6.3   # Position ADS-B receiver

### Start

# Haversine formula example in Python
# Author: Wayne Dyck
def distance(origin, destination):
    lat1, lon1 = origin
    lat2, lon2 = destination
    radius = 6371 # km earth radius
    dlat = math.radians(lat2-lat1)
    dlon = math.radians(lon2-lon1)
    a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(lat1)) \
        * math.cos(math.radians(lat2)) * math.sin(dlon/2) * math.sin(dlon/2)
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
    d = radius * c
    return d

# Find flights
def find_adsbdb(flightid, hex):
    try:
        if hex == "":
            response = urlopen("https://api.adsbdb.com/v0/callsign/" + flightid)
        else:
            response = urlopen("https://api.adsbdb.com/v0/aircraft/" + hex + "?callsign=" + flightid)
        data_json = json.loads(response.read())
        aircraft = data_json['response']
        if flightid in aircraft['flightroute']['callsign_icao']:
            return flightid, aircraft
        else:
            return None, None
    except:
        return None, None

# Write JSON for Pico W
def writeresult(flightdict):
    json_object = json.dumps(flightdict)
    with open("/tmp/overhead.json", "w", encoding="utf-8") as outfile:
        outfile.write(json_object)

### Find the closest airplane

aircraft = []

try:
    response = urlopen(url)
    data_json = json.loads(response.read())
    aircraft = data_json['aircraft']
except:
    exit()

closest       = 1000               # km distance of closest plane
closestflight = ''                 # Will hold flight number
dictionary    = {"flight":"none"}  # Empty dictionary
speed         = 0
vert_rate     = 0
altitude      = 0
compass       = ["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW","N"]
track         = 0
heading       = ""
newflight     = True
hex           = ""

for airplane in aircraft:
    if 'lat' in airplane:
        if 'lon' in airplane:
            if 'flight' in airplane:
                if 'altitude' in airplane:
                    altitude = int(airplane['altitude'])
                    if 'hex' in airplane:
                        hex = airplane['hex']
                    if 'vert_rate' in airplane:
                        vert_rate = int(airplane['vert_rate'])
                    if 'speed' in airplane:
                        speed = int(airplane['speed'])
                    if 'track' in airplane:
                        track = int(airplane['track'])
                        heading =  str(track) + " degrees " + compass[min(round((track % 360) / 22.5), 16)]
                    flightdis = distance((lathome, lonhome), (airplane['lat'], airplane['lon']))
                    flighthgt = altitude * 0.0003048
                    dis = math.floor(math.sqrt(flightdis**2 + flighthgt**2))
                    if dis < closest:
                        closest = dis
                        closestflight = airplane['flight'].replace(" ", "").upper()

if closestflight != '':
    #print(closestflight)
    #print(hex)
    flight, details = find_adsbdb(closestflight, hex)
    if flight != None:
        dictionary = {
            "flight": flight,
            "airline": details["flightroute"]["airline"]["name"],
            "altitude": str(altitude),
            "vert_rate": str(vert_rate),
            "speed": str(speed),
            "origin_iata": details["flightroute"]["origin"]["iata_code"],
            "destination_iata": details["flightroute"]["destination"]["iata_code"],
            "model": details["aircraft"]["type"],
            "origin": details["flightroute"]["origin"]["name"],
            "destination": details["flightroute"]["destination"]["name"],
            "departure": "",
            "eta": "",
            "distance": str(closest),
            "track": heading
        }
        writeresult(dictionary)
    else:
        writeresult(dictionary)
else:
    writeresult(dictionary)

 

The following is the same for either FR24 or adsbdb.com:

To create a 2 minute crontab use this (note: there is a limit on the amount of requests you can send, a 2 minute interval should keep you below it):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Nano /etc/crontab
*/2 * * * * root sh /home/pi/overhead.sh
Nano /etc/crontab */2 * * * * root sh /home/pi/overhead.sh
Nano /etc/crontab
*/2 *     * * *   root    sh /home/pi/overhead.sh

We need to make the JSON file we created accessible to the local internet for the Pico W to download:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
cd /var/www/html/
sudo ln -s /tmp/overhead.json overhead.json
cd /var/www/html/ sudo ln -s /tmp/overhead.json overhead.json
cd /var/www/html/
sudo ln -s /tmp/overhead.json overhead.json

To prepare the Pico you can press the display on the header, do it gently and make sure the USB side is indeed on the USB side of the Pico.

Now we can connect the Pico W with Display and with an official USB Pico cable (most cables will not work!) to your Mac. Install Thonny for macOS and you will be able to connect to the Pico.

Download & install the Pimoroni custom MicroPython for the "Pico W" version (keep the boot select button pressed and then plug it into the Mac) - copy the file over and unplug & replug the Pico in the Mac. Then use Thonny to create two files on the Pico. The first one is named "secrets.py" and will hold your WiFi networks name and password:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SSID = "Your Wi-Fi Network"
PASS = "Your Password"
SSID = "Your Wi-Fi Network" PASS = "Your Password"
SSID = "Your Wi-Fi Network"
PASS = "Your Password"

The next file should be named "main.py" and will run every time the Pico has power and boots up:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# (c) JF Nutbroek
# 08/10/2023
from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY
from pimoroni import RGBLED
import network
import secrets
import urequests
from time import sleep
from math import floor, pi, sin, cos
from machine import Timer, WDT
# User defined input
# URL to local json file using http
url = "http://192.168.68.120/overhead.json"
pollinterval = 10 # Interval in seconds for a new JSON poll
brightness = 0.5 # Brightness of the display
sleepafter = 10 # Number of JSON polls without aircraft
# ********* Start
display = PicoGraphics(display=DISPLAY_PICO_DISPLAY, rotate=0)
display.set_font("bitmap8")
display.set_backlight(brightness)
# Colors
BLACK = display.create_pen(0, 0, 0)
GREEN = display.create_pen(50, 205, 50)
RED = display.create_pen(200, 0, 0)
BLUE = display.create_pen(0, 191, 255)
WHITE = display.create_pen(255, 255, 255)
ORANGE = display.create_pen(255, 140, 0)
YELLOW = display.create_pen(255, 255, 0)
# Switch LED off
led = RGBLED(6, 7, 8)
led.set_rgb(0, 0, 0)
# Overhead info
flightinfo = {"flight":"none"}
flight = ""
airline = ""
altitude = ""
vert_rate = ""
speed = ""
origin_iata = ""
destination_iata = ""
model = ""
origin = ""
destination = ""
departure = ""
eta = ""
distradar = ""
heading = ""
xpos = 20
textpos = 0
infopos = 0
timedout = 0
# Write text centered or right aligned
def writetext(text, y, center, size, color):
width = display.measure_text(text, size)
display.set_pen(color)
if center:
display.text(text, floor((240 - width) / 2), y, 300, size)
else:
display.text(text, 240 - width, y, 240, size)
def radar(steps, rounds, message):
for _ in range(rounds):
for n in range(0, steps):
display.set_pen(BLACK)
display.clear()
for y in range(60, 0, -10):
display.set_pen(GREEN)
display.circle(120, 68, y)
display.set_pen(BLACK)
display.circle(120, 68, y - 3)
x1 = 120 + (cos(2 * pi * (n / steps)) * 65)
y1 = 68 + (sin(2 * pi * (n / steps)) * 65)
display.line(120, 68, int(x1), int(y1), 5)
if message != "":
display.set_pen(WHITE)
display.text(message, 0, 0, 240, 2)
display.update()
# Read JSON
def readjson():
global flightinfo, timedout
flightinfo = {"flight":"none"}
led.set_rgb(138, 43, 226)
try:
if wlan.isconnected():
flightinfo = urequests.get(url).json()
led.set_rgb(0, 0, 0)
else:
led.set_rgb(255, 0, 0)
radar(180, 1)
except:
led.set_rgb(255, 0, 0)
if 'flight' in flightinfo:
if flightinfo['flight'] == "none":
timedout += 1
else:
timedout = 0
def resetwdTimer(wdTimer):
global wd
wd.feed()
# Read JSON
def update_display(myTimer):
if timedout < sleepafter:
readjson()
# Startup
radar(180, 1, "v1.1")
# Connect to WiFi
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(secrets.SSID, secrets.PASS)
sleep(1)
# First JSON download
if wlan.isconnected():
readjson()
else:
radar(180, 5, "No WiFi")
readjson()
# Start the timers
myTimer = Timer()
myTimer.init(period = pollinterval * 1000, mode = Timer.PERIODIC, callback = update_display)
wdTimer = Timer()
wdTimer.init(period = 5000, mode = Timer.PERIODIC, callback = resetwdTimer)
# Automatic reboot after 6 seconds of inactivity
wd = WDT(timeout = 6000)
while True:
# Sleep Mode when no new data is received
if timedout == sleepafter:
display.set_pen(BLACK)
display.clear()
display.update()
display.set_backlight(0.0)
if timedout >= sleepafter:
sleep(pollinterval * 10)
readjson()
if timedout == 0:
display.set_backlight(brightness)
else:
continue
# Start drawing
display.set_pen(BLACK)
display.clear()
if 'flight' in flightinfo:
flight = flightinfo['flight']
if flight == "none":
radar(180, 4, "Nothing")
continue
if 'airline' in flightinfo:
airline = flightinfo['airline']
if 'altitude' in flightinfo:
altitude = flightinfo['altitude']
if 'vert_rate' in flightinfo:
vert_rate = flightinfo['vert_rate']
if 'speed' in flightinfo:
speed = flightinfo['speed']
if 'origin_iata' in flightinfo:
origin_iata = flightinfo['origin_iata']
if 'destination_iata' in flightinfo:
destination_iata = flightinfo['destination_iata']
if 'model' in flightinfo:
model = flightinfo['model']
if 'origin' in flightinfo:
origin = flightinfo['origin']
if 'destination' in flightinfo:
destination = flightinfo['destination']
if 'departure' in flightinfo:
departure = flightinfo['departure']
if 'eta' in flightinfo:
eta = flightinfo['eta']
if 'distance' in flightinfo:
distradar = flightinfo['distance']
if 'track' in flightinfo:
heading = flightinfo['track']
# Show main flight info
display.set_pen(YELLOW)
display.text(origin_iata, 0, 0, 240, 3)
writetext(destination_iata, 0, False, 3, YELLOW)
display.set_pen(ORANGE)
display.text(departure, 0, 48, 240, 2)
writetext(eta, 48, False, 2, ORANGE)
if flight != "N/A":
writetext(flight, 0, True, 3, ORANGE)
# Draw animation
if xpos < 220:
xpos += 1
else:
xpos = 20
display.set_pen(BLUE)
display.line(20, 35, xpos, 35, 2)
display.circle(25, 35, 8)
if xpos > 210:
display.set_pen(WHITE)
display.circle(225, 35, 8)
display.set_pen(GREEN)
display.triangle(xpos, 25, xpos, 45, xpos + 10, 35)
# Write airline name - shorten if it is too long
airline_width = display.measure_text(airline, 2)
timing_width = display.measure_text(departure + eta, 2)
if (airline_width + timing_width) > 230:
shorten = airline_width / (230 - timing_width)
stripped = min(12, len(airline) - int(len(airline) * shorten) - 3)
writetext(airline[0:stripped] + "..", 48, True, 2, WHITE)
else:
writetext(airline, 48, True, 2, WHITE)
# Write scrolling text for full airport names
longname = origin + " to " + destination
longwidth = display.measure_text(longname, 2)
display.set_pen(GREEN)
display.text(origin + " -> " + destination, 240 - textpos, 78, 1000, 2)
textpos += 2
if textpos > (longwidth + 240):
textpos = 0
# Write scrolling text for all other details
longinfo = model + ", Altitude " + str(int(int(altitude) * 0.0003048)) + " km, Speed " + str(int(int(speed) * 1.852)) + " kmh, "
if ((int(vert_rate) > -64) and (int(vert_rate) < 64)):
longinfo += "Level Flight, "
elif int(vert_rate) < -64:
longinfo += "Descending, "
else:
longinfo += "Ascending, "
longinfo += distradar + " km distance, " + heading
longinfowidth = display.measure_text(longinfo, 3)
display.set_pen(BLUE)
display.text(longinfo, 240 - infopos, 111, 5000, 3)
infopos += 3
if infopos > (longinfowidth + 240):
infopos = 0
# Update everything to the screen
display.update()
sleep(0.01)
# (c) JF Nutbroek # 08/10/2023 from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY from pimoroni import RGBLED import network import secrets import urequests from time import sleep from math import floor, pi, sin, cos from machine import Timer, WDT # User defined input # URL to local json file using http url = "http://192.168.68.120/overhead.json" pollinterval = 10 # Interval in seconds for a new JSON poll brightness = 0.5 # Brightness of the display sleepafter = 10 # Number of JSON polls without aircraft # ********* Start display = PicoGraphics(display=DISPLAY_PICO_DISPLAY, rotate=0) display.set_font("bitmap8") display.set_backlight(brightness) # Colors BLACK = display.create_pen(0, 0, 0) GREEN = display.create_pen(50, 205, 50) RED = display.create_pen(200, 0, 0) BLUE = display.create_pen(0, 191, 255) WHITE = display.create_pen(255, 255, 255) ORANGE = display.create_pen(255, 140, 0) YELLOW = display.create_pen(255, 255, 0) # Switch LED off led = RGBLED(6, 7, 8) led.set_rgb(0, 0, 0) # Overhead info flightinfo = {"flight":"none"} flight = "" airline = "" altitude = "" vert_rate = "" speed = "" origin_iata = "" destination_iata = "" model = "" origin = "" destination = "" departure = "" eta = "" distradar = "" heading = "" xpos = 20 textpos = 0 infopos = 0 timedout = 0 # Write text centered or right aligned def writetext(text, y, center, size, color): width = display.measure_text(text, size) display.set_pen(color) if center: display.text(text, floor((240 - width) / 2), y, 300, size) else: display.text(text, 240 - width, y, 240, size) def radar(steps, rounds, message): for _ in range(rounds): for n in range(0, steps): display.set_pen(BLACK) display.clear() for y in range(60, 0, -10): display.set_pen(GREEN) display.circle(120, 68, y) display.set_pen(BLACK) display.circle(120, 68, y - 3) x1 = 120 + (cos(2 * pi * (n / steps)) * 65) y1 = 68 + (sin(2 * pi * (n / steps)) * 65) display.line(120, 68, int(x1), int(y1), 5) if message != "": display.set_pen(WHITE) display.text(message, 0, 0, 240, 2) display.update() # Read JSON def readjson(): global flightinfo, timedout flightinfo = {"flight":"none"} led.set_rgb(138, 43, 226) try: if wlan.isconnected(): flightinfo = urequests.get(url).json() led.set_rgb(0, 0, 0) else: led.set_rgb(255, 0, 0) radar(180, 1) except: led.set_rgb(255, 0, 0) if 'flight' in flightinfo: if flightinfo['flight'] == "none": timedout += 1 else: timedout = 0 def resetwdTimer(wdTimer): global wd wd.feed() # Read JSON def update_display(myTimer): if timedout < sleepafter: readjson() # Startup radar(180, 1, "v1.1") # Connect to WiFi wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect(secrets.SSID, secrets.PASS) sleep(1) # First JSON download if wlan.isconnected(): readjson() else: radar(180, 5, "No WiFi") readjson() # Start the timers myTimer = Timer() myTimer.init(period = pollinterval * 1000, mode = Timer.PERIODIC, callback = update_display) wdTimer = Timer() wdTimer.init(period = 5000, mode = Timer.PERIODIC, callback = resetwdTimer) # Automatic reboot after 6 seconds of inactivity wd = WDT(timeout = 6000) while True: # Sleep Mode when no new data is received if timedout == sleepafter: display.set_pen(BLACK) display.clear() display.update() display.set_backlight(0.0) if timedout >= sleepafter: sleep(pollinterval * 10) readjson() if timedout == 0: display.set_backlight(brightness) else: continue # Start drawing display.set_pen(BLACK) display.clear() if 'flight' in flightinfo: flight = flightinfo['flight'] if flight == "none": radar(180, 4, "Nothing") continue if 'airline' in flightinfo: airline = flightinfo['airline'] if 'altitude' in flightinfo: altitude = flightinfo['altitude'] if 'vert_rate' in flightinfo: vert_rate = flightinfo['vert_rate'] if 'speed' in flightinfo: speed = flightinfo['speed'] if 'origin_iata' in flightinfo: origin_iata = flightinfo['origin_iata'] if 'destination_iata' in flightinfo: destination_iata = flightinfo['destination_iata'] if 'model' in flightinfo: model = flightinfo['model'] if 'origin' in flightinfo: origin = flightinfo['origin'] if 'destination' in flightinfo: destination = flightinfo['destination'] if 'departure' in flightinfo: departure = flightinfo['departure'] if 'eta' in flightinfo: eta = flightinfo['eta'] if 'distance' in flightinfo: distradar = flightinfo['distance'] if 'track' in flightinfo: heading = flightinfo['track'] # Show main flight info display.set_pen(YELLOW) display.text(origin_iata, 0, 0, 240, 3) writetext(destination_iata, 0, False, 3, YELLOW) display.set_pen(ORANGE) display.text(departure, 0, 48, 240, 2) writetext(eta, 48, False, 2, ORANGE) if flight != "N/A": writetext(flight, 0, True, 3, ORANGE) # Draw animation if xpos < 220: xpos += 1 else: xpos = 20 display.set_pen(BLUE) display.line(20, 35, xpos, 35, 2) display.circle(25, 35, 8) if xpos > 210: display.set_pen(WHITE) display.circle(225, 35, 8) display.set_pen(GREEN) display.triangle(xpos, 25, xpos, 45, xpos + 10, 35) # Write airline name - shorten if it is too long airline_width = display.measure_text(airline, 2) timing_width = display.measure_text(departure + eta, 2) if (airline_width + timing_width) > 230: shorten = airline_width / (230 - timing_width) stripped = min(12, len(airline) - int(len(airline) * shorten) - 3) writetext(airline[0:stripped] + "..", 48, True, 2, WHITE) else: writetext(airline, 48, True, 2, WHITE) # Write scrolling text for full airport names longname = origin + " to " + destination longwidth = display.measure_text(longname, 2) display.set_pen(GREEN) display.text(origin + " -> " + destination, 240 - textpos, 78, 1000, 2) textpos += 2 if textpos > (longwidth + 240): textpos = 0 # Write scrolling text for all other details longinfo = model + ", Altitude " + str(int(int(altitude) * 0.0003048)) + " km, Speed " + str(int(int(speed) * 1.852)) + " kmh, " if ((int(vert_rate) > -64) and (int(vert_rate) < 64)): longinfo += "Level Flight, " elif int(vert_rate) < -64: longinfo += "Descending, " else: longinfo += "Ascending, " longinfo += distradar + " km distance, " + heading longinfowidth = display.measure_text(longinfo, 3) display.set_pen(BLUE) display.text(longinfo, 240 - infopos, 111, 5000, 3) infopos += 3 if infopos > (longinfowidth + 240): infopos = 0 # Update everything to the screen display.update() sleep(0.01)
# (c) JF Nutbroek
# 08/10/2023

from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY
from pimoroni import RGBLED

import network
import secrets
import urequests

from time import sleep
from math import floor, pi, sin, cos
from machine import Timer, WDT

# User defined input

# URL to local json file using http
url = "http://192.168.68.120/overhead.json"

pollinterval = 10    # Interval in seconds for a new JSON poll
brightness   = 0.5   # Brightness of the display
sleepafter   = 10    # Number of JSON polls without aircraft

# ********* Start

display = PicoGraphics(display=DISPLAY_PICO_DISPLAY, rotate=0)
display.set_font("bitmap8")
display.set_backlight(brightness)

# Colors
BLACK  = display.create_pen(0, 0, 0)
GREEN  = display.create_pen(50, 205, 50)
RED    = display.create_pen(200, 0, 0)
BLUE   = display.create_pen(0, 191, 255)
WHITE  = display.create_pen(255, 255, 255)
ORANGE = display.create_pen(255, 140, 0)
YELLOW = display.create_pen(255, 255, 0)    
    
# Switch LED off
led = RGBLED(6, 7, 8)
led.set_rgb(0, 0, 0)

# Overhead info
flightinfo       = {"flight":"none"}
flight           = ""
airline          = ""
altitude         = ""
vert_rate        = ""
speed            = ""
origin_iata      = ""
destination_iata = ""     
model            = ""
origin           = ""
destination      = ""
departure        = ""
eta              = ""
distradar        = ""
heading          = ""
xpos             = 20
textpos          = 0
infopos          = 0
timedout         = 0

# Write text centered or right aligned
def writetext(text, y, center, size, color):
    width = display.measure_text(text, size)
    display.set_pen(color)
    if center:
        display.text(text, floor((240 - width) / 2), y, 300, size)
    else:
        display.text(text, 240 - width, y, 240, size)        

def radar(steps, rounds, message):
    for _ in range(rounds):
        for n in range(0, steps):
            display.set_pen(BLACK)
            display.clear()
            for y in range(60, 0, -10):
                display.set_pen(GREEN)
                display.circle(120, 68, y)
                display.set_pen(BLACK)
                display.circle(120, 68, y - 3)
            x1 = 120 + (cos(2 * pi * (n / steps)) * 65)
            y1 = 68 + (sin(2 * pi * (n / steps)) * 65)    
            display.line(120, 68, int(x1), int(y1), 5)
            if message != "":
                display.set_pen(WHITE)
                display.text(message, 0, 0, 240, 2)
            display.update()

# Read JSON
def readjson():
    global flightinfo, timedout
    flightinfo = {"flight":"none"}
    led.set_rgb(138, 43, 226)
    try:
        if wlan.isconnected():
            flightinfo = urequests.get(url).json()
            led.set_rgb(0, 0, 0)
        else:
            led.set_rgb(255, 0, 0)
            radar(180, 1)
    except:
        led.set_rgb(255, 0, 0)
    if 'flight' in flightinfo:
        if flightinfo['flight'] == "none":
            timedout += 1
        else:
            timedout = 0

def resetwdTimer(wdTimer):
    global wd
    wd.feed()
    
# Read JSON
def update_display(myTimer):
    if timedout < sleepafter:
        readjson()
    
# Startup
radar(180, 1, "v1.1")

# Connect to WiFi
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(secrets.SSID, secrets.PASS)
sleep(1)

# First JSON download
if wlan.isconnected():
    readjson()
else:
    radar(180, 5, "No WiFi")
    readjson()

# Start the timers
myTimer = Timer()
myTimer.init(period = pollinterval * 1000, mode = Timer.PERIODIC, callback = update_display)
wdTimer = Timer()
wdTimer.init(period = 5000, mode = Timer.PERIODIC, callback = resetwdTimer)
# Automatic reboot after 6 seconds of inactivity
wd = WDT(timeout = 6000)

while True:
        
    # Sleep Mode when no new data is received
    if timedout == sleepafter:
        display.set_pen(BLACK)
        display.clear()
        display.update()
        display.set_backlight(0.0)
    if timedout >= sleepafter:
        sleep(pollinterval * 10)
        readjson()
        if timedout == 0:
            display.set_backlight(brightness)
        else:
            continue
    
    # Start drawing
    display.set_pen(BLACK)
    display.clear()
        
    if 'flight' in flightinfo:
      flight = flightinfo['flight']
      
    if flight == "none":
        radar(180, 4, "Nothing")
        continue
    
    if 'airline' in flightinfo:
      airline = flightinfo['airline']
    
    if 'altitude' in flightinfo:
      altitude = flightinfo['altitude']
      
    if 'vert_rate' in flightinfo:
      vert_rate = flightinfo['vert_rate']
      
    if 'speed' in flightinfo:
      speed = flightinfo['speed']
      
    if 'origin_iata' in flightinfo:
      origin_iata = flightinfo['origin_iata']
      
    if 'destination_iata' in flightinfo:
      destination_iata = flightinfo['destination_iata']      
      
    if 'model' in flightinfo:
      model = flightinfo['model']
      
    if 'origin' in flightinfo:
      origin = flightinfo['origin']
      
    if 'destination' in flightinfo:
      destination = flightinfo['destination']
      
    if 'departure' in flightinfo:
      departure = flightinfo['departure']
      
    if 'eta' in flightinfo:
      eta = flightinfo['eta']
      
    if 'distance' in flightinfo:
        distradar = flightinfo['distance']
          
    if 'track' in flightinfo:
        heading = flightinfo['track']
            
    # Show main flight info
    display.set_pen(YELLOW)
    display.text(origin_iata, 0, 0, 240, 3)
    writetext(destination_iata, 0, False, 3, YELLOW)
    display.set_pen(ORANGE)
    display.text(departure, 0, 48, 240, 2)
    writetext(eta, 48, False, 2, ORANGE)
    if flight != "N/A":
        writetext(flight, 0, True, 3, ORANGE)
    
    # Draw animation
    if xpos < 220:
        xpos += 1
    else:
        xpos = 20
    display.set_pen(BLUE)
    display.line(20, 35, xpos, 35, 2)
    display.circle(25, 35, 8)
    if xpos > 210:
        display.set_pen(WHITE)    
    display.circle(225, 35, 8)
    display.set_pen(GREEN)
    display.triangle(xpos, 25, xpos, 45, xpos + 10, 35)

    # Write airline name - shorten if it is too long
    airline_width = display.measure_text(airline, 2)
    timing_width = display.measure_text(departure + eta, 2)
    if (airline_width + timing_width) > 230:
        shorten = airline_width / (230 - timing_width) 
        stripped = min(12, len(airline) - int(len(airline) * shorten) - 3)
        writetext(airline[0:stripped] + "..", 48, True, 2, WHITE)
    else:
        writetext(airline, 48, True, 2, WHITE)
    
    # Write scrolling text for full airport names
    longname = origin + " to " + destination
    longwidth = display.measure_text(longname, 2)
    display.set_pen(GREEN)
    display.text(origin + " -> " + destination, 240 - textpos, 78, 1000, 2)
    textpos += 2
    if textpos > (longwidth + 240):
        textpos = 0
       
    # Write scrolling text for all other details  
    longinfo = model + ", Altitude " + str(int(int(altitude) * 0.0003048)) + " km, Speed " + str(int(int(speed) * 1.852)) + " kmh, "
    if ((int(vert_rate) > -64) and (int(vert_rate) < 64)):
        longinfo += "Level Flight, "
    elif int(vert_rate) < -64:
        longinfo += "Descending, "
    else:
        longinfo += "Ascending, "
    longinfo += distradar + " km distance, " + heading 
    longinfowidth = display.measure_text(longinfo, 3)
    display.set_pen(BLUE)
    display.text(longinfo, 240 - infopos, 111, 5000, 3)
    infopos += 3
    if infopos > (longinfowidth + 240):
        infopos = 0

    # Update everything to the screen
    display.update()
    sleep(0.01)

 

That should be it, now you need to find a place for your new Pico Display with real-time flight info!

Success!