Skip to content

Commit 30e4bf0

Browse files
committed
Added scrolling text to JSON requests
Filtered out dupes Added origin and destination flight properties Loaded Airline icons Todo: Update 26x26 icons vertically Update bounding box coordinates The scrolling texts should load behind icons
1 parent bf30dd6 commit 30e4bf0

1 file changed

Lines changed: 220 additions & 59 deletions

File tree

  • MatrixPortal_S3_Flight_Proximity_Tracker

MatrixPortal_S3_Flight_Proximity_Tracker/code.py

Lines changed: 220 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@
2727

2828
quotes_url = "https://www.adafruit.com/api/quotes.php"
2929

30+
ICON_WIDTH = 26 # Adjust according to your actual icon width
31+
TEXT_START_X = ICON_WIDTH + 4
32+
3033
THRESHOLD_DISTANCE = 150 # 5 miles
3134

35+
3236
# font = bitmap_font.load_font("/tom-thumb.pcf")
3337
font = terminalio.FONT
3438
text_color = 0xFC6900 # e.g., Retro Orange
@@ -80,101 +84,258 @@
8084
)
8185

8286
# --- Drawing setup ---
87+
#font = bitmap_font.load_font("/tom-thumb.pcf")
88+
font = terminalio.FONT
89+
text_color = 0xFC6900 # e.g., Retro Orange
90+
colors = [0xFC6900, 0xDD8000]
91+
8392
group = Group()
8493
# Associate the RGB matrix with a Display
8594
display = framebufferio.FramebufferDisplay(matrix, auto_refresh=False)
86-
# display.show(icon_group)
8795

96+
# --- Icon Positioning ---
97+
ICON_HEIGHT = 26 # Height of the icon
98+
GAP_BETWEEN_ICONS = 12 # Gap between the icons
99+
NUMBER_OF_ICONS = 2 # Number of icons to display
100+
total_icons_height = (ICON_HEIGHT * NUMBER_OF_ICONS) + (GAP_BETWEEN_ICONS * (NUMBER_OF_ICONS - 1))
101+
102+
# Calculate the starting y-position for the first icon to center them vertically
103+
start_y = (DISPLAY_HEIGHT - total_icons_height) // 2
104+
105+
106+
# Create icon group
107+
icon_group = Group()
108+
109+
110+
gap_between_lines = 12
111+
112+
display.show(icon_group)
113+
114+
def scroll_icons(icon_tile):
115+
icon_tile.x -= 1
116+
if icon_tile.x < -64: # Assuming each icon is 64 pixels wide
117+
icon_tile.x = 128 # Reset position to the rightmost
118+
119+
120+
121+
122+
123+
124+
# Function to scroll the icons
125+
TEXT_RESET_X = 170
126+
127+
128+
# Function to scroll objects
129+
def scroll_text_labels(text_labels):
130+
for label in text_labels:
131+
label.x -= 1 # Move label left.
132+
if label.x < -256: # If label has moved off screen.
133+
label.x = TEXT_RESET_X
88134

89-
def degrees_to_cardinal(d):
90-
dirs = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]
91-
ix = round(d / 45)
92-
return dirs[ix % 8]
93135

94136

95137
seen_flight_numbers = set() # To keep track of processed flight numbers
96138

97139
bounding_box = {
98-
"min_latitude": 44.953469,
99-
"max_latitude": 40.962321,
100-
"min_longitude": -111.045360 ,
101-
"max_longitude": -104.046577,
140+
"min_latitude": 40.962321, # Southernmost latitude
141+
"max_latitude": 44.953469, # Northernmost latitude
142+
"min_longitude": -111.045360, # Westernmost longitude
143+
"max_longitude": -104.046570, # Easternmost longitude
102144
}
103145

104146
# curl -X GET "https://aeroapi.flightaware.com/aeroapi/flights/search?query=-latlong+%2244.953469+-111.045360+40.962321+-104.046577%22&max_pages=1" \
105147
# -H "Accept: application/json; charset=UTF-8" \
106148
# -H "x-apikey: -AN API KEY-"
107149

108-
api_url = "https://aeroapi.flightaware.com/aeroapi/flights/search"
109-
username = "A-Name"
110-
api_key = "API-KEY"
150+
def degrees_to_cardinal(d):
151+
dirs = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]
152+
ix = round(d / 45)
153+
return dirs[ix % 8]
111154

112155

113156
def construct_query_string(params):
114157
return "&".join(f"{key}={value}" for key, value in params.items())
115158

159+
def update_flight_labels(flights_data):
160+
for i, flight in enumerate(flights_data[:4]): # Update up to 4 flights
161+
flight_text = f"{flight['icao']} | {flight['country']} | {flight['altitude']} | {flight['direction']}"
162+
labels[i].text = flight_text # Assuming you have a list of Label objects
163+
164+
# Call this function with fetched flight data
165+
166+
167+
#anA5AXJkYlfC2SNgWghB27mkNO9RRaTI
116168

117169
def fetch_flight_data():
170+
print("Running fetch_flight_data")
118171
base_url = "https://aeroapi.flightaware.com/aeroapi/flights/search"
119172
params = {
120173
"query": f"-latlong+\"{bounding_box['min_latitude']}+{bounding_box['min_longitude']}+{bounding_box['max_latitude']}+{bounding_box['max_longitude']}\"",
121174
"max_pages": "1"
122175
}
123176
headers = {
124177
"Accept": "application/json; charset=UTF-8",
125-
"x-apikey": "anA5AXJkYlfC2SNgWghB27mkNO9RRaTI" # Make sure to replace API_KEY with your actual API key
178+
"x-apikey": "anA5AXJkYlfC2SNgWghB27mkNO9RRaTI" # Replace with your actual API key
126179
}
127-
128-
# Construct the full URL with the query string
129180
full_url = f"{base_url}?{construct_query_string(params)}"
130-
131-
# Use the requests object that was initialized with a session
132181
response = requests.get(full_url, headers=headers)
133182

134-
135183
if response.status_code == 200:
136-
print("in da loop")
137-
flights = response.json()['flights']
138-
for flight in flights:
139-
print("Flight Properties:")
140-
print(f"Ident: {flight.get('ident', 'N/A')}")
141-
print(f"FA Flight ID: {flight.get('fa_flight_id', 'N/A')}")
142-
print(f"Origin: {flight.get('origin', {}).get('code', 'N/A')}")
143-
print(f"Destination: {flight.get('destination', {}).get('code', 'N/A')}")
144-
print(f"Altitude: {flight.get('last_position', {}).get('altitude', 'N/A')}00 ft")
145-
print(f"Groundspeed: {flight.get('last_position', {}).get('groundspeed', 'N/A')} knots")
146-
print(f"Heading: {flight.get('last_position', {}).get('heading', 'N/A')}")
147-
print(f"Latitude: {flight.get('last_position', {}).get('latitude', 'N/A')}")
148-
print(f"Longitude: {flight.get('last_position', {}).get('longitude', 'N/A')}")
149-
print(f"Timestamp: {flight.get('last_position', {}).get('timestamp', 'N/A')}")
150-
print("------")
151-
# Print only one flight's properties for brevity; remove the break to print all
152-
break
153-
else:
154-
print(f"Request failed with status code {response.status_code}")
155-
156-
157-
def requestTest():
184+
json_response = response.json() # Parse JSON only once
185+
return process_flight_data(json_response) # Process flights and return
186+
else:
187+
print(f"Request failed with status code {response.status_code}")
188+
if response.content:
189+
print(f"Response content: {response.content}")
190+
return [] # Return an empty list if the request failed
191+
192+
def process_flight_data(json_data):
193+
# Initialize an empty list to hold processed flight data
194+
processed_flights = []
195+
196+
for flight in json_data.get('flights', []):
197+
# Use 'get' with default values to avoid KeyError
198+
flight_info = {
199+
'ident': flight.get('ident', 'N/A'),
200+
'ident_icao': flight.get('ident_icao', 'N/A'),
201+
'fa_flight_id': flight.get('fa_flight_id', 'N/A'),
202+
'actual_off': flight.get('actual_off', 'N/A'),
203+
'actual_on': flight.get('actual_on', 'N/A'),
204+
'origin_code': flight.get('origin', {}).get('code', 'Unknown'),
205+
'origin_city': flight.get('origin', {}).get('city', 'Unknown'),
206+
'origin_country': flight.get('origin', {}).get('country', 'Unknown'),
207+
'destination_code': flight.get('destination', {}).get('code', 'Unknown') if flight.get('destination') else 'Unknown',
208+
'destination_city': flight.get('destination', {}).get('city', 'Unknown') if flight.get('destination') else 'Unknown',
209+
'destination_country': flight.get('destination', {}).get('country', 'Unknown') if flight.get('destination') else 'Unknown',
210+
'altitude': flight.get('last_position', {}).get('altitude', 'N/A'),
211+
'groundspeed': flight.get('last_position', {}).get('groundspeed', 'N/A'),
212+
'heading': flight.get('last_position', {}).get('heading', 'N/A'),
213+
'latitude': flight.get('last_position', {}).get('latitude', 'N/A'),
214+
'longitude': flight.get('last_position', {}).get('longitude', 'N/A'),
215+
'timestamp': flight.get('last_position', {}).get('timestamp', 'N/A'),
216+
'aircraft_type': flight.get('aircraft_type', 'N/A'),
217+
}
218+
# Only add flight_info if the 'ident_icao' is present and not 'N/A'
219+
if flight_info['ident_icao'] != 'N/A':
220+
processed_flights.append(flight_info)
221+
222+
return processed_flights
223+
224+
225+
226+
227+
228+
def create_text_labels(flight_data, display_group):
229+
text_labels = []
230+
for i, flight in enumerate(flight_data):
231+
y_position = i * gap_between_lines + 15
232+
233+
# Since 'country' is not present, we'll use 'origin_city' and 'destination_code' instead
234+
# Construct the display text for each flight without 'country'
235+
236+
origin_city = flight.get('origin_city', 'Unknown City')
237+
origin_country = flight.get('origin_country', 'Unknown Country')
238+
destination_city = flight.get('destination_city', 'Unknown City')
239+
destination_country = flight.get('destination_country', 'Unknown Country')
240+
241+
# Format from and to locations with city and country
242+
from_location = f"{origin_city}, {origin_country}"
243+
to_location = f"{destination_city}, {destination_country}"
244+
245+
# Construct the display text for each flight
246+
single_line_text = f"{flight['ident']} | From: {from_location} To: {to_location}"
247+
248+
text_label = adafruit_display_text.label.Label(
249+
font,
250+
color=text_color,
251+
x=TEXT_START_X,
252+
y=y_position,
253+
text=single_line_text
254+
)
255+
display_group.append(text_label)
256+
text_labels.append(text_label)
257+
return text_labels
258+
259+
260+
def create_icon_tilegrid(ident):
261+
airline_code = ident[:3].upper() # Use the first three characters of 'ident'
262+
icon_path = f"/airline_logos/{airline_code}.bmp"
158263
try:
159-
# pings adafruit quotes
160-
print("Fetching text from %s" % quotes_url)
161-
# gets the quote from adafruit quotes
162-
response = requests.get(quotes_url)
163-
print("-" * 40)
164-
# prints the response to the REPL
165-
print("Text Response: ", response.text)
166-
print("-" * 40)
167-
response.close()
168-
# delays for 1 minute
169-
time.sleep(60)
170-
# pylint: disable=broad-except
171-
except Exception as e:
172-
print("Error:\n", str(e))
173-
print("Resetting microcontroller in 10 seconds")
174-
time.sleep(1200)
175-
microcontroller.reset()
264+
icon_bitmap = OnDiskBitmap(open(icon_path, "rb"))
265+
icon_tilegrid = TileGrid(icon_bitmap, pixel_shader=icon_bitmap.pixel_shader, x=0, y=0)
266+
return icon_tilegrid
267+
except OSError:
268+
print(f"Icon for {airline_code} not found.")
269+
return None
176270

271+
# Update your display update function to include icon creation and text label setup
272+
def update_display_with_flight_data(flight_data, icon_group, display_group):
273+
# Clear previous display items
274+
while len(display_group):
275+
display_group.pop()
177276

277+
278+
279+
# Limit flight data to only 4 flights
280+
flight_data = flight_data[:4]
281+
282+
# Load icons and create text labels for up to 4 flights
283+
for i, flight in enumerate(flight_data):
284+
y_position = i * gap_between_lines + 10
285+
286+
# Load the icon dynamically
287+
icon_tilegrid = create_icon_tilegrid(flight['ident'])
288+
if icon_tilegrid:
289+
icon_tilegrid.y = y_position
290+
icon_group.append(icon_tilegrid)
291+
292+
# Append the icon group to the main display group
293+
display_group.append(icon_group)
294+
295+
# Create and append text labels next to the icons
296+
text_labels = create_text_labels(flight_data, display_group)
297+
298+
# Show the updated group on the display
299+
display.show(display_group)
300+
return text_labels
301+
302+
303+
# Initialize the main display group
304+
main_group = Group()
305+
306+
# Initialize the icon group (this remains static on the display)
307+
static_icon_group = Group()
308+
309+
310+
text_label = adafruit_display_text.label.Label(font, text="Label 1", color=0xFFFFFF, x=DISPLAY_WIDTH, y=1)
311+
text_label2 = adafruit_display_text.label.Label(font, text="Label 2", color=0xFFFFFF, x=DISPLAY_WIDTH, y=3)
312+
text_label3 = adafruit_display_text.label.Label(font, text="Label 3", color=0xFFFFFF, x=DISPLAY_WIDTH, y=6)
313+
text_label4 = adafruit_display_text.label.Label(font, text="Label 4", color=0xFFFFFF, x=DISPLAY_WIDTH, y=15)
314+
315+
# Add labels to a display group
316+
group = displayio.Group()
317+
group.append(text_label)
318+
group.append(text_label2)
319+
group.append(text_label3)
320+
group.append(text_label4)
321+
322+
# Show the group
323+
display.show(group)
324+
325+
flight_data = fetch_flight_data()
326+
327+
# Initialize text labels list
328+
text_labels = []
329+
330+
# Check if we received any flight data
331+
if flight_data:
332+
text_labels = update_display_with_flight_data(flight_data, static_icon_group, main_group)
333+
334+
178335
while True:
179-
fetch_flight_data()
180-
time.sleep (1200)
336+
scroll_text_labels(text_labels)
337+
338+
# Refresh the display
339+
display.refresh(minimum_frames_per_second=0)
340+
341+
time.sleep (120000)

0 commit comments

Comments
 (0)