Skip to content

Commit b642f14

Browse files
committed
Add OpenSkyNetwork Private API
Website login required, uses circuitpython_base64 library for encoding. Allows for 4000 calls per day on any active available transponder in their network (about 40K aircraft). This was a somewhat requested API I took on.. and succeeded.
1 parent 3092a6e commit b642f14

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
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 adafruit_requests
13+
import circuitpython_base64 as base64
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+
basepw = 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+
basepw = repr(base64_string)[2:-1]
51+
print("Decoded Bytes:", str(basepw))
52+
53+
# OSN requires your username:password to be base64 encoded
54+
# so technically it's not transmitted in the clear but w/e
55+
osn_header = {"Authorization": "Basic " + str(basepw)}
56+
OPENSKY_SOURCE = "https://opensky-network.org/api/states/all?" + "icao24=" + transponder
57+
58+
59+
def time_calc(input_time):
60+
if input_time < 60:
61+
sleep_int = input_time
62+
time_output = f"{sleep_int:.0f} seconds"
63+
elif 60 <= input_time < 3600:
64+
sleep_int = input_time / 60
65+
time_output = f"{sleep_int:.0f} minutes"
66+
elif 3600 <= input_time < 86400:
67+
sleep_int = input_time / 60 / 60
68+
time_output = f"{sleep_int:.1f} hours"
69+
elif 86400 <= input_time < 432000:
70+
sleep_int = input_time / 60 / 60 / 24
71+
time_output = f"{sleep_int:.1f} days"
72+
else: # if > 5 days convert float to int & display whole days
73+
sleep_int = input_time / 60 / 60 / 24
74+
time_output = f"{sleep_int:.0f} days"
75+
return time_output
76+
77+
78+
def _format_datetime(datetime):
79+
return "{:02}/{:02}/{} {:02}:{:02}:{:02}".format(
80+
datetime.tm_mon,
81+
datetime.tm_mday,
82+
datetime.tm_year,
83+
datetime.tm_hour,
84+
datetime.tm_min,
85+
datetime.tm_sec,
86+
)
87+
88+
89+
# Connect to Wi-Fi
90+
print("\n===============================")
91+
print("Connecting to WiFi...")
92+
request = adafruit_requests.Session(pool, ssl.create_default_context())
93+
while not wifi.radio.ipv4_address:
94+
try:
95+
wifi.radio.connect(ssid, appw)
96+
except ConnectionError as e:
97+
print("Connection Error:", e)
98+
print("Retrying in 10 seconds")
99+
time.sleep(10)
100+
print("Connected!\n")
101+
102+
while True:
103+
# STREAMER WARNING this will show your credentials!
104+
debug_request = False # Set true to see full request
105+
if debug_request:
106+
print("Full API HEADER: ", str(osn_header))
107+
print("Full API GET URL: ", OPENSKY_SOURCE)
108+
print("===============================")
109+
110+
print("\nAttempting to GET OpenSky-Network Data!")
111+
opensky_response = request.get(url=OPENSKY_SOURCE, headers=osn_header).json()
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+
# Print to Serial
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("You are likely banned for 24 hours")
152+
print("Next Retry: ", time_calc(sleep_time))
153+
time.sleep(sleep_time)

0 commit comments

Comments
 (0)