Skip to content

Commit f149297

Browse files
committed
added OpenSky Geographic Area
Shows all flight traffic in a lat/lon area. This one is really neat!
1 parent 02b5f85 commit f149297

File tree

1 file changed

+187
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)