|
27 | 27 |
|
28 | 28 | quotes_url = "https://www.adafruit.com/api/quotes.php" |
29 | 29 |
|
| 30 | +ICON_WIDTH = 26 # Adjust according to your actual icon width |
| 31 | +TEXT_START_X = ICON_WIDTH + 4 |
| 32 | + |
30 | 33 | THRESHOLD_DISTANCE = 150 # 5 miles |
31 | 34 |
|
| 35 | + |
32 | 36 | # font = bitmap_font.load_font("/tom-thumb.pcf") |
33 | 37 | font = terminalio.FONT |
34 | 38 | text_color = 0xFC6900 # e.g., Retro Orange |
|
80 | 84 | ) |
81 | 85 |
|
82 | 86 | # --- 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 | + |
83 | 92 | group = Group() |
84 | 93 | # Associate the RGB matrix with a Display |
85 | 94 | display = framebufferio.FramebufferDisplay(matrix, auto_refresh=False) |
86 | | -# display.show(icon_group) |
87 | 95 |
|
| 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 |
88 | 134 |
|
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] |
93 | 135 |
|
94 | 136 |
|
95 | 137 | seen_flight_numbers = set() # To keep track of processed flight numbers |
96 | 138 |
|
97 | 139 | 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 |
102 | 144 | } |
103 | 145 |
|
104 | 146 | # curl -X GET "https://aeroapi.flightaware.com/aeroapi/flights/search?query=-latlong+%2244.953469+-111.045360+40.962321+-104.046577%22&max_pages=1" \ |
105 | 147 | # -H "Accept: application/json; charset=UTF-8" \ |
106 | 148 | # -H "x-apikey: -AN API KEY-" |
107 | 149 |
|
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] |
111 | 154 |
|
112 | 155 |
|
113 | 156 | def construct_query_string(params): |
114 | 157 | return "&".join(f"{key}={value}" for key, value in params.items()) |
115 | 158 |
|
| 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 |
116 | 168 |
|
117 | 169 | def fetch_flight_data(): |
| 170 | + print("Running fetch_flight_data") |
118 | 171 | base_url = "https://aeroapi.flightaware.com/aeroapi/flights/search" |
119 | 172 | params = { |
120 | 173 | "query": f"-latlong+\"{bounding_box['min_latitude']}+{bounding_box['min_longitude']}+{bounding_box['max_latitude']}+{bounding_box['max_longitude']}\"", |
121 | 174 | "max_pages": "1" |
122 | 175 | } |
123 | 176 | headers = { |
124 | 177 | "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 |
126 | 179 | } |
127 | | - |
128 | | - # Construct the full URL with the query string |
129 | 180 | full_url = f"{base_url}?{construct_query_string(params)}" |
130 | | - |
131 | | - # Use the requests object that was initialized with a session |
132 | 181 | response = requests.get(full_url, headers=headers) |
133 | 182 |
|
134 | | - |
135 | 183 | 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" |
158 | 263 | 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 |
176 | 270 |
|
| 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() |
177 | 276 |
|
| 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 | + |
178 | 335 | 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