Skip to content

Commit 1259b73

Browse files
authored
Merge pull request #133 from DJDevon3/WorkingBranch
Add OpenSky-Network API example
2 parents c40cb25 + 72a3536 commit 1259b73

3 files changed

+471
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# SPDX-FileCopyrightText: 2023 DJDevon3
2+
# SPDX-License-Identifier: MIT
3+
# Coded for Circuit Python 8.1
4+
# DJDevon3 ESP32-S3 OpenSkyNetwork_Private_API_Example
5+
6+
import os
7+
import time
8+
import ssl
9+
import json
10+
import wifi
11+
import socketpool
12+
import circuitpython_base64 as base64
13+
import adafruit_requests
14+
15+
# OpenSky-Network.org Login required for this API
16+
# REST API: https://openskynetwork.github.io/opensky-api/rest.html
17+
# All active flights JSON: https://opensky-network.org/api/states/all # PICK ONE! :)
18+
# JSON order: transponder, callsign, country
19+
# ACTIVE transpondes only, for multiple "c822af&icao24=cb3993&icao24=c63923"
20+
transponder = "7c6b2d"
21+
22+
# Initialize WiFi Pool (There can be only 1 pool & top of script)
23+
pool = socketpool.SocketPool(wifi.radio)
24+
25+
# Time between API refreshes
26+
# 900 = 15 mins, 1800 = 30 mins, 3600 = 1 hour
27+
# OpenSky-Networks IP bans for too many requests, check rate limit.
28+
# https://openskynetwork.github.io/opensky-api/rest.html#limitations
29+
sleep_time = 1800
30+
31+
# this example uses settings.toml for credentials
32+
# timezone offset is in seconds plus or minus GMT
33+
ssid = os.getenv("AP_SSID")
34+
appw = os.getenv("AP_PASSWORD")
35+
osnu = os.getenv("OSN_Username")
36+
osnp = os.getenv("OSN_Password")
37+
38+
osn_cred = str(osnu) + ":" + str(osnp)
39+
bytes_to_encode = b" " + str(osn_cred) + " "
40+
base64_string = base64.encodebytes(bytes_to_encode)
41+
base64cred = repr(base64_string)[2:-1]
42+
43+
Debug_Auth = False # STREAMER WARNING this will show your credentials!
44+
if Debug_Auth:
45+
osn_cred = str(osnu) + ":" + str(osnp)
46+
bytes_to_encode = b" " + str(osn_cred) + " "
47+
print(repr(bytes_to_encode))
48+
base64_string = base64.encodebytes(bytes_to_encode)
49+
print(repr(base64_string)[2:-1])
50+
base64cred = repr(base64_string)[2:-1]
51+
print("Decoded Bytes:", str(base64cred))
52+
53+
# Requests URL - icao24 is their endpoint required for a transponder
54+
# example https://opensky-network.org/api/states/all?icao24=a808c5
55+
# OSN private requires your username:password to be base64 encoded
56+
osn_header = {"Authorization": "Basic " + str(base64cred)}
57+
OPENSKY_SOURCE = "https://opensky-network.org/api/states/all?" + "icao24=" + transponder
58+
59+
60+
# Converts seconds to human readable minutes/hours/days
61+
def time_calc(input_time): # input_time in seconds
62+
if input_time < 60:
63+
sleep_int = input_time
64+
time_output = f"{sleep_int:.0f} seconds"
65+
elif 60 <= input_time < 3600:
66+
sleep_int = input_time / 60
67+
time_output = f"{sleep_int:.0f} minutes"
68+
elif 3600 <= input_time < 86400:
69+
sleep_int = input_time / 60 / 60
70+
time_output = f"{sleep_int:.1f} hours"
71+
else:
72+
sleep_int = input_time / 60 / 60 / 24
73+
time_output = f"{sleep_int:.1f} days"
74+
return time_output
75+
76+
77+
def _format_datetime(datetime):
78+
return "{:02}/{:02}/{} {:02}:{:02}:{:02}".format(
79+
datetime.tm_mon,
80+
datetime.tm_mday,
81+
datetime.tm_year,
82+
datetime.tm_hour,
83+
datetime.tm_min,
84+
datetime.tm_sec,
85+
)
86+
87+
88+
# Connect to Wi-Fi
89+
print("\n===============================")
90+
print("Connecting to WiFi...")
91+
request = adafruit_requests.Session(pool, ssl.create_default_context())
92+
while not wifi.radio.ipv4_address:
93+
try:
94+
wifi.radio.connect(ssid, appw)
95+
except ConnectionError as e:
96+
print("Connection Error:", e)
97+
print("Retrying in 10 seconds")
98+
time.sleep(10)
99+
print("Connected!\n")
100+
101+
while True:
102+
# STREAMER WARNING this will show your credentials!
103+
debug_request = False # Set True to see full request
104+
if debug_request:
105+
print("Full API HEADER: ", str(osn_header))
106+
print("Full API GET URL: ", OPENSKY_SOURCE)
107+
print("===============================")
108+
109+
print("\nAttempting to GET OpenSky-Network Data!")
110+
opensky_response = request.get(url=OPENSKY_SOURCE, headers=osn_header).json()
111+
112+
# Print Full JSON to Serial (doesn't show credentials)
113+
debug_response = False # Set True to see full response
114+
if debug_response:
115+
dump_object = json.dumps(opensky_response)
116+
print("JSON Dump: ", dump_object)
117+
118+
# Key:Value Serial Debug (doesn't show credentials)
119+
osn_debug_keys = True # Set True to print Serial data
120+
if osn_debug_keys:
121+
try:
122+
osn_flight = opensky_response["time"]
123+
print("Current Unix Time: ", osn_flight)
124+
125+
current_struct_time = time.localtime(osn_flight)
126+
current_date = "{}".format(_format_datetime(current_struct_time))
127+
print(f"Unix to Readable Time: {current_date}")
128+
129+
# Current flight data for single callsign (right now)
130+
osn_single_flight_data = opensky_response["states"]
131+
132+
if osn_single_flight_data is not None:
133+
print("Flight Data: ", osn_single_flight_data)
134+
transponder = opensky_response["states"][0][0]
135+
print("Transponder: ", transponder)
136+
callsign = opensky_response["states"][0][1]
137+
print("Callsign: ", callsign)
138+
country = opensky_response["states"][0][2]
139+
print("Flight Country: ", country)
140+
else:
141+
print("Flight has no active data or you're polling too fast.")
142+
143+
print("\nFinished!")
144+
print("Board Uptime: ", time_calc(time.monotonic()))
145+
print("Next Update: ", time_calc(sleep_time))
146+
time.sleep(sleep_time)
147+
print("===============================")
148+
149+
except (ConnectionError, ValueError, NameError) as e:
150+
print("OSN Connection Error:", e)
151+
print("Next Retry: ", time_calc(sleep_time))
152+
time.sleep(sleep_time)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# SPDX-FileCopyrightText: 2023 DJDevon3
2+
# SPDX-License-Identifier: MIT
3+
# Coded for Circuit Python 8.1
4+
# DJDevon3 ESP32-S3 OpenSkyNetwork_Private_Area_API_Example
5+
6+
import os
7+
import time
8+
import ssl
9+
import json
10+
import wifi
11+
import socketpool
12+
import circuitpython_base64 as base64
13+
import adafruit_requests
14+
15+
# OpenSky-Network.org Website Login required for this API
16+
# REST API: https://openskynetwork.github.io/opensky-api/rest.html
17+
18+
# Retrieves all traffic within a geographic area (Orlando example)
19+
latmin = "27.22" # east bounding box
20+
latmax = "28.8" # west bounding box
21+
lonmin = "-81.46" # north bounding box
22+
lonmax = "-80.40" # south bounding box
23+
24+
# Initialize WiFi Pool (There can be only 1 pool & top of script)
25+
pool = socketpool.SocketPool(wifi.radio)
26+
27+
# Time between API refreshes
28+
# 900 = 15 mins, 1800 = 30 mins, 3600 = 1 hour
29+
# OpenSky-Networks IP bans for too many requests, check rate limit.
30+
# https://openskynetwork.github.io/opensky-api/rest.html#limitations
31+
sleep_time = 1800
32+
33+
# this example uses settings.toml for credentials
34+
# No token required, only website login
35+
ssid = os.getenv("AP_SSID")
36+
appw = os.getenv("AP_PASSWORD")
37+
osnu = os.getenv("OSN_Username")
38+
osnp = os.getenv("OSN_Password")
39+
40+
osn_cred = str(osnu) + ":" + str(osnp)
41+
bytes_to_encode = b" " + str(osn_cred) + " "
42+
base64_string = base64.encodebytes(bytes_to_encode)
43+
base64cred = repr(base64_string)[2:-1]
44+
45+
Debug_Auth = False # STREAMER WARNING this will show your credentials!
46+
if Debug_Auth:
47+
osn_cred = str(osnu) + ":" + str(osnp)
48+
bytes_to_encode = b" " + str(osn_cred) + " "
49+
print(repr(bytes_to_encode))
50+
base64_string = base64.encodebytes(bytes_to_encode)
51+
print(repr(base64_string)[2:-1])
52+
base64cred = repr(base64_string)[2:-1]
53+
print("Decoded Bytes:", str(base64cred))
54+
55+
# OSN requires your username:password to be base64 encoded
56+
# so technically it's not transmitted in the clear but w/e
57+
osn_header = {"Authorization": "Basic " + str(base64cred)}
58+
59+
# Example request of all traffic over Florida, geographic areas cost less per call.
60+
# https://opensky-network.org/api/states/all?lamin=25.21&lomin=-84.36&lamax=30.0&lomax=-78.40
61+
OPENSKY_SOURCE = (
62+
"https://opensky-network.org/api/states/all?"
63+
+ "lamin="
64+
+ latmin
65+
+ "&lomin="
66+
+ lonmin
67+
+ "&lamax="
68+
+ latmax
69+
+ "&lomax="
70+
+ lonmax
71+
)
72+
73+
74+
# Converts seconds to human readable minutes/hours/days
75+
def time_calc(input_time): # input_time in seconds
76+
if input_time < 60:
77+
sleep_int = input_time
78+
time_output = f"{sleep_int:.0f} seconds"
79+
elif 60 <= input_time < 3600:
80+
sleep_int = input_time / 60
81+
time_output = f"{sleep_int:.0f} minutes"
82+
elif 3600 <= input_time < 86400:
83+
sleep_int = input_time / 60 / 60
84+
time_output = f"{sleep_int:.1f} hours"
85+
else:
86+
sleep_int = input_time / 60 / 60 / 24
87+
time_output = f"{sleep_int:.1f} days"
88+
return time_output
89+
90+
91+
def _format_datetime(datetime):
92+
return "{:02}/{:02}/{} {:02}:{:02}:{:02}".format(
93+
datetime.tm_mon,
94+
datetime.tm_mday,
95+
datetime.tm_year,
96+
datetime.tm_hour,
97+
datetime.tm_min,
98+
datetime.tm_sec,
99+
)
100+
101+
102+
# Connect to Wi-Fi
103+
print("\n===============================")
104+
print("Connecting to WiFi...")
105+
request = adafruit_requests.Session(pool, ssl.create_default_context())
106+
while not wifi.radio.ipv4_address:
107+
try:
108+
wifi.radio.connect(ssid, appw)
109+
except ConnectionError as e:
110+
print("Connection Error:", e)
111+
print("Retrying in 10 seconds")
112+
time.sleep(10)
113+
print("Connected!\n")
114+
115+
while True:
116+
# STREAMER WARNING this will show your credentials!
117+
debug_request = False # Set True to see full request
118+
if debug_request:
119+
print("Full API HEADER: ", str(osn_header))
120+
print("Full API GET URL: ", OPENSKY_SOURCE)
121+
print("===============================")
122+
123+
print("\nAttempting to GET OpenSky-Network Data!")
124+
opensky_response = request.get(url=OPENSKY_SOURCE, headers=osn_header).json()
125+
126+
# Print Full JSON to Serial (doesn't show credentials)
127+
debug_response = False # Set True to see full response
128+
if debug_response:
129+
dump_object = json.dumps(opensky_response)
130+
print("JSON Dump: ", dump_object)
131+
132+
# Key:Value Serial Debug (doesn't show credentials)
133+
osn_debug_keys = True # Set True to print Serial data
134+
if osn_debug_keys:
135+
try:
136+
osn_flight = opensky_response["time"]
137+
print("Current Unix Time: ", osn_flight)
138+
139+
current_struct_time = time.localtime(osn_flight)
140+
current_date = "{}".format(_format_datetime(current_struct_time))
141+
print(f"Unix to Readable Time: {current_date}")
142+
143+
# Current flight data for single callsign (right now)
144+
osn_all_flights = opensky_response["states"]
145+
146+
if osn_all_flights is not None:
147+
# print("Flight Data: ", osn_all_flights)
148+
for flights in osn_all_flights:
149+
osn_t = f"Trans:{flights[0]} "
150+
osn_c = f"Sign:{flights[1]} "
151+
osn_o = f"Origin:{flights[2]} "
152+
osn_tm = f"Time:{flights[3]} "
153+
osn_l = f"Last:{flights[4]} "
154+
osn_lo = f"Lon:{flights[5]} "
155+
osn_la = f"Lat:{flights[6]} "
156+
osn_ba = f"BaroAlt:{flights[7]} "
157+
osn_g = f"Ground:{flights[8]} "
158+
osn_v = f"Vel:{flights[9]} "
159+
osn_h = f"Head:{flights[10]} "
160+
osn_vr = f"VertRate:{flights[11]} "
161+
osn_s = f"Sens:{flights[12]} "
162+
osn_ga = f"GeoAlt:{flights[13]} "
163+
osn_sq = f"Squawk:{flights[14]} "
164+
osn_pr = f"Task:{flights[15]} "
165+
osn_ps = f"PosSys:{flights[16]} "
166+
osn_ca = f"Cat:{flights[16]} "
167+
# This is just because pylint complains about long lines
168+
string1 = f"{osn_t}{osn_c}{osn_o}{osn_tm}{osn_l}{osn_lo}"
169+
string2 = f"{osn_la}{osn_ba}{osn_g}{osn_v}{osn_h}{osn_vr}"
170+
string3 = f"{osn_s}{osn_ga}{osn_sq}{osn_pr}{osn_ps}{osn_ca}"
171+
print(f"{string1}{string2}{string3}")
172+
else:
173+
print("Flight has no active data or you're polling too fast.")
174+
175+
print("\nFinished!")
176+
print("Board Uptime: ", time_calc(time.monotonic()))
177+
print("Next Update: ", time_calc(sleep_time))
178+
time.sleep(sleep_time)
179+
print("===============================")
180+
181+
except (ConnectionError, ValueError, NameError) as e:
182+
print("OSN Connection Error:", e)
183+
print("Next Retry: ", time_calc(sleep_time))
184+
time.sleep(sleep_time)

0 commit comments

Comments
 (0)