Skip to content

Commit 231e2eb

Browse files
committed
Update Open-Sky Network Single Flight Public API Example with Connection Manager
1 parent 8a34d2a commit 231e2eb

File tree

1 file changed

+146
-103
lines changed

1 file changed

+146
-103
lines changed
Lines changed: 146 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
# SPDX-FileCopyrightText: 2023 DJDevon3
1+
# SPDX-FileCopyrightText: 2024 DJDevon3
22
# SPDX-License-Identifier: MIT
3-
# Coded for Circuit Python 8.1
4-
# Adafruit Feather ESP32-S3 OpenSkyNetwork_Public_API_Example
5-
import json
3+
# Coded for Circuit Python 8.2.x
4+
"""OpenSky-Network.org Public API Example"""
5+
# pylint: disable=import-error
6+
67
import os
7-
import ssl
88
import time
99

10-
import socketpool
10+
import adafruit_connection_manager
1111
import wifi
1212

1313
import adafruit_requests
@@ -17,121 +17,164 @@
1717
# All active flights JSON: https://opensky-network.org/api/states/all PICK ONE!
1818
# JSON order: transponder, callsign, country
1919
# ACTIVE transpondes only, for multiple "c822af&icao24=cb3993&icao24=c63923"
20-
transponder = "ab1644"
20+
TRANSPONDER = "3c5ef8"
2121

22-
# Initialize WiFi Pool (There can be only 1 pool & top of script)
23-
pool = socketpool.SocketPool(wifi.radio)
22+
# Get WiFi details, ensure these are setup in settings.toml
23+
ssid = os.getenv("CIRCUITPY_WIFI_SSID")
24+
password = os.getenv("CIRCUITPY_WIFI_PASSWORD")
25+
osnusername = os.getenv("OSN_USERNAME") # Website Credentials
26+
osnpassword = os.getenv("OSN_PASSWORD") # Website Credentials
2427

25-
# Time between API refreshes
28+
# API Polling Rate
2629
# 900 = 15 mins, 1800 = 30 mins, 3600 = 1 hour
27-
# OpenSky-Networks will temp ban your IP for too many daily requests.
30+
# OpenSky-Networks IP bans for too many requests, check rate limit.
2831
# https://openskynetwork.github.io/opensky-api/rest.html#limitations
29-
sleep_time = 1800
32+
SLEEP_TIME = 1800
3033

31-
# Get WiFi details, ensure these are setup in settings.toml
32-
ssid = os.getenv("CIRCUITPY_WIFI_SSID")
33-
password = os.getenv("CIRCUITPY_WIFI_PASSWORD")
34+
# Set debug to True for full JSON response.
35+
# WARNING: makes credentials visible
36+
DEBUG = False
37+
38+
# Initalize Wifi, Socket Pool, Request Session
39+
pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
40+
ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
41+
requests = adafruit_requests.Session(pool, ssl_context)
3442

3543
# Requests URL - icao24 is their endpoint required for a transponder
3644
# example https://opensky-network.org/api/states/all?icao24=a808c5
37-
OPENSKY_SOURCE = "https://opensky-network.org/api/states/all?" + "icao24=" + transponder
45+
OPENSKY_SOURCE = "https://opensky-network.org/api/states/all?" + "icao24=" + TRANSPONDER
3846

3947

40-
# Converts seconds to human readable minutes/hours/days
41-
def time_calc(input_time): # input_time in seconds
48+
def time_calc(input_time):
49+
"""Converts seconds to minutes/hours/days"""
4250
if input_time < 60:
43-
sleep_int = input_time
44-
time_output = f"{sleep_int:.0f} seconds"
45-
elif 60 <= input_time < 3600:
46-
sleep_int = input_time / 60
47-
time_output = f"{sleep_int:.0f} minutes"
48-
elif 3600 <= input_time < 86400:
49-
sleep_int = input_time / 60 / 60
50-
time_output = f"{sleep_int:.1f} hours"
51-
else:
52-
sleep_int = input_time / 60 / 60 / 24
53-
time_output = f"{sleep_int:.1f} days"
54-
return time_output
51+
return f"{input_time:.0f} seconds"
52+
if input_time < 3600:
53+
return f"{input_time / 60:.0f} minutes"
54+
if input_time < 86400:
55+
return f"{input_time / 60 / 60:.0f} hours"
56+
return f"{input_time / 60 / 60 / 24:.1f} days"
5557

5658

5759
def _format_datetime(datetime):
58-
return "{:02}/{:02}/{} {:02}:{:02}:{:02}".format(
59-
datetime.tm_mon,
60-
datetime.tm_mday,
61-
datetime.tm_year,
62-
datetime.tm_hour,
63-
datetime.tm_min,
64-
datetime.tm_sec,
60+
"""F-String formatted struct time conversion"""
61+
return (
62+
f"{datetime.tm_mon:02}/"
63+
+ f"{datetime.tm_mday:02}/"
64+
+ f"{datetime.tm_year:02} "
65+
+ f"{datetime.tm_hour:02}:"
66+
+ f"{datetime.tm_min:02}:"
67+
+ f"{datetime.tm_sec:02}"
6568
)
6669

6770

68-
# Connect to Wi-Fi
69-
print("\n===============================")
70-
print("Connecting to WiFi...")
71-
requests = adafruit_requests.Session(pool, ssl.create_default_context())
72-
while not wifi.radio.ipv4_address:
73-
try:
74-
wifi.radio.connect(ssid, password)
75-
except ConnectionError as e:
76-
print("Connection Error:", e)
77-
print("Retrying in 10 seconds")
78-
time.sleep(10)
79-
print("Connected!\n")
80-
8171
while True:
82-
debug_request = True # Set true to see full request
83-
if debug_request:
84-
print("Full API GET URL: ", OPENSKY_SOURCE)
85-
print("===============================")
72+
# Connect to Wi-Fi
73+
print("\nConnecting to WiFi...")
74+
while not wifi.radio.ipv4_address:
75+
try:
76+
wifi.radio.connect(ssid, password)
77+
except ConnectionError as e:
78+
print("❌ Connection Error:", e)
79+
print("Retrying in 10 seconds")
80+
print("✅ Wifi!")
81+
8682
try:
87-
print("\nAttempting to GET OpenSky-Network Stats!")
88-
opensky_response = requests.get(url=OPENSKY_SOURCE)
89-
osn_json = opensky_response.json()
90-
except (ConnectionError, ValueError, NameError) as e:
91-
print("Host No Response Error:", e)
92-
93-
# Print Full JSON to Serial
94-
debug_response = False # Set true to see full response
95-
if debug_response:
96-
dump_object = json.dumps(osn_json)
97-
print("JSON Dump: ", dump_object)
98-
99-
# Print to Serial
100-
osn_debug_keys = True # Set true to print Serial data
101-
if osn_debug_keys:
83+
print(" | Attempting to GET OpenSky-Network Single Flight JSON!")
10284
try:
103-
osn_flight = osn_json["time"]
104-
print("Current Unix Time: ", osn_flight)
105-
106-
current_struct_time = time.localtime(osn_flight)
107-
current_date = "{}".format(_format_datetime(current_struct_time))
108-
print(f"Unix to Readable Time: {current_date}")
109-
110-
osn_single_flight_data = osn_json["states"]
111-
if osn_single_flight_data is not None:
112-
print("Flight Data: ", osn_single_flight_data)
113-
transponder = osn_json["states"][0][0]
114-
print("Transponder: ", transponder)
115-
callsign = osn_json["states"][0][1]
116-
print("Callsign: ", callsign)
117-
country = osn_json["states"][0][2]
118-
print("Flight Country: ", country)
85+
opensky_response = requests.get(url=OPENSKY_SOURCE)
86+
opensky_json = opensky_response.json()
87+
except ConnectionError as e:
88+
print("Connection Error:", e)
89+
print("Retrying in 10 seconds")
90+
91+
print(" | ✅ OpenSky-Network JSON!")
92+
93+
if DEBUG:
94+
print("Full API GET URL: ", OPENSKY_SOURCE)
95+
print(opensky_json)
96+
97+
# ERROR MESSAGE RESPONSES
98+
if "timestamp" in opensky_json:
99+
osn_timestamp = opensky_json["timestamp"]
100+
print(f"❌ Timestamp: {osn_timestamp}")
101+
102+
if "message" in opensky_json:
103+
osn_message = opensky_json["message"]
104+
print(f"❌ Message: {osn_message}")
105+
106+
if "error" in opensky_json:
107+
osn_error = opensky_json["error"]
108+
print(f"❌ Error: {osn_error}")
109+
110+
if "path" in opensky_json:
111+
osn_path = opensky_json["path"]
112+
print(f"❌ Path: {osn_path}")
113+
114+
if "status" in opensky_json:
115+
osn_status = opensky_json["status"]
116+
print(f"❌ Status: {osn_status}")
117+
118+
# Current flight data for single callsign (right now)
119+
osn_single_flight_data = opensky_json["states"]
120+
121+
if osn_single_flight_data is not None:
122+
if DEBUG:
123+
print(f" | | Single Flight Public Data: {osn_single_flight_data}")
124+
125+
last_contact = opensky_json["states"][0][4]
126+
# print(f" | | Last Contact Unix Time: {last_contact}")
127+
lc_struct_time = time.localtime(last_contact)
128+
lc_readable_time = f"{_format_datetime(lc_struct_time)}"
129+
print(f" | | Last Contact: {lc_readable_time}")
130+
131+
flight_transponder = opensky_json["states"][0][0]
132+
print(f" | | Transponder: {flight_transponder}")
133+
134+
callsign = opensky_json["states"][0][1]
135+
print(f" | | Callsign: {callsign}")
136+
137+
squawk = opensky_json["states"][0][14]
138+
print(f" | | Squawk: {squawk}")
139+
140+
country = opensky_json["states"][0][2]
141+
print(f" | | Origin: {country}")
142+
143+
longitude = opensky_json["states"][0][5]
144+
print(f" | | Longitude: {longitude}")
145+
146+
latitude = opensky_json["states"][0][6]
147+
print(f" | | Latitude: {latitude}")
148+
149+
# Return Air Flight data if not on ground
150+
on_ground = opensky_json["states"][0][8]
151+
if on_ground is True:
152+
print(f" | | On Ground: {on_ground}")
119153
else:
120-
print("This flight has no active data or you're polling too fast.")
121-
print(
122-
"Read: https://openskynetwork.github.io/opensky-api/rest.html#limitations"
123-
)
124-
print(
125-
"Public Limits: 10 second max poll rate & 400 weighted calls daily"
126-
)
127-
128-
print("\nFinished!")
129-
print("Board Uptime: ", time_calc(time.monotonic()))
130-
print("Next Update: ", time_calc(sleep_time))
131-
time.sleep(sleep_time)
132-
print("===============================")
133-
134-
except (ConnectionError, ValueError, NameError) as e:
135-
print("OSN Connection Error:", e)
136-
print("Next Retry: ", time_calc(sleep_time))
137-
time.sleep(sleep_time)
154+
altitude = opensky_json["states"][0][7]
155+
print(f" | | Barometric Altitude: {altitude}")
156+
157+
velocity = opensky_json["states"][0][9]
158+
if velocity != "null":
159+
print(f" | | Velocity: {velocity}")
160+
161+
vertical_rate = opensky_json["states"][0][11]
162+
if vertical_rate != "null":
163+
print(f" | | Vertical Rate: {vertical_rate}")
164+
else:
165+
print("This flight has no active data or you're polling too fast.")
166+
print("Public Limits: 10 second max poll & 400 weighted calls daily")
167+
168+
opensky_response.close()
169+
print("✂️ Disconnected from OpenSky-Network API")
170+
171+
print("\nFinished!")
172+
print(f"Board Uptime: {time_calc(time.monotonic())}")
173+
print(f"Next Update: {time_calc(SLEEP_TIME)}")
174+
print("===============================")
175+
176+
except (ValueError, RuntimeError) as e:
177+
print(f"Failed to get data, retrying\n {e}")
178+
time.sleep(60)
179+
break
180+
time.sleep(SLEEP_TIME)

0 commit comments

Comments
 (0)