Skip to content

Commit ea9acf6

Browse files
committed
updating with most recent approved PR
This file is now updated with the same version as in the Single Flight Private API Example. This should hopefully fix any conflicts.
1 parent 76eca0b commit ea9acf6

File tree

1 file changed

+155
-115
lines changed

1 file changed

+155
-115
lines changed
Lines changed: 155 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +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-
# DJDevon3 ESP32-S3 OpenSkyNetwork_Private_API_Example
3+
# Coded for Circuit Python 9.x
4+
"""OpenSky-Network.org Single Flight Private API Example"""
55

6-
import json
6+
import binascii
77
import os
8-
import ssl
98
import time
109

11-
import circuitpython_base64 as base64
12-
import socketpool
10+
import adafruit_connection_manager
1311
import wifi
1412

1513
import adafruit_requests
@@ -19,135 +17,177 @@
1917
# All active flights JSON: https://opensky-network.org/api/states/all # PICK ONE! :)
2018
# JSON order: transponder, callsign, country
2119
# ACTIVE transpondes only, for multiple "c822af&icao24=cb3993&icao24=c63923"
22-
transponder = "7c6b2d"
20+
TRANSPONDER = "4b1812"
2321

24-
# Initialize WiFi Pool (There can be only 1 pool & top of script)
25-
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
2627

27-
# Time between API refreshes
28+
# API Polling Rate
2829
# 900 = 15 mins, 1800 = 30 mins, 3600 = 1 hour
2930
# OpenSky-Networks IP bans for too many requests, check rate limit.
3031
# https://openskynetwork.github.io/opensky-api/rest.html#limitations
31-
sleep_time = 1800
32+
SLEEP_TIME = 1800
3233

33-
# Get WiFi details, ensure these are setup in settings.toml
34-
ssid = os.getenv("CIRCUITPY_WIFI_SSID")
35-
password = os.getenv("CIRCUITPY_WIFI_PASSWORD")
36-
osnu = os.getenv("OSN_Username")
37-
osnp = os.getenv("OSN_Password")
38-
39-
osn_cred = str(osnu) + ":" + str(osnp)
40-
bytes_to_encode = b" " + str(osn_cred) + " "
41-
base64_string = base64.encodebytes(bytes_to_encode)
42-
base64cred = repr(base64_string)[2:-1]
43-
44-
Debug_Auth = False # STREAMER WARNING this will show your credentials!
45-
if Debug_Auth:
46-
osn_cred = str(osnu) + ":" + str(osnp)
47-
bytes_to_encode = b" " + str(osn_cred) + " "
48-
print(repr(bytes_to_encode))
49-
base64_string = base64.encodebytes(bytes_to_encode)
50-
print(repr(base64_string)[2:-1])
51-
base64cred = repr(base64_string)[2:-1]
52-
print("Decoded Bytes:", str(base64cred))
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)
42+
43+
# -- Base64 Conversion --
44+
OSN_CREDENTIALS = str(osnusername) + ":" + str(osnpassword)
45+
# base64 encode and strip appended \n from bytearray
46+
OSN_CREDENTIALS_B = binascii.b2a_base64(OSN_CREDENTIALS.encode()).strip()
47+
BASE64_STRING = OSN_CREDENTIALS_B.decode() # bytearray
48+
49+
50+
if DEBUG:
51+
print("Base64 ByteArray: ", BASE64_STRING)
5352

5453
# Requests URL - icao24 is their endpoint required for a transponder
5554
# example https://opensky-network.org/api/states/all?icao24=a808c5
56-
# OSN private requires your username:password to be base64 encoded
57-
osn_header = {"Authorization": "Basic " + str(base64cred)}
58-
OPENSKY_SOURCE = "https://opensky-network.org/api/states/all?" + "icao24=" + transponder
55+
# OSN private: requires your website username:password to be base64 encoded
56+
OPENSKY_HEADER = {"Authorization": "Basic " + BASE64_STRING}
57+
OPENSKY_SOURCE = "https://opensky-network.org/api/states/all?" + "icao24=" + TRANSPONDER
5958

6059

61-
# Converts seconds to human readable minutes/hours/days
62-
def time_calc(input_time): # input_time in seconds
60+
def time_calc(input_time):
61+
"""Converts seconds to minutes/hours/days"""
6362
if input_time < 60:
64-
sleep_int = input_time
65-
time_output = f"{sleep_int:.0f} seconds"
66-
elif 60 <= input_time < 3600:
67-
sleep_int = input_time / 60
68-
time_output = f"{sleep_int:.0f} minutes"
69-
elif 3600 <= input_time < 86400:
70-
sleep_int = input_time / 60 / 60
71-
time_output = f"{sleep_int:.1f} hours"
72-
else:
73-
sleep_int = input_time / 60 / 60 / 24
74-
time_output = f"{sleep_int:.1f} days"
75-
return time_output
63+
return f"{input_time:.0f} seconds"
64+
if input_time < 3600:
65+
return f"{input_time / 60:.0f} minutes"
66+
if input_time < 86400:
67+
return f"{input_time / 60 / 60:.0f} hours"
68+
return f"{input_time / 60 / 60 / 24:.1f} days"
7669

7770

7871
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,
72+
return (
73+
f"{datetime.tm_mon:02}/"
74+
+ f"{datetime.tm_mday:02}/"
75+
+ f"{datetime.tm_year:02} "
76+
+ f"{datetime.tm_hour:02}:"
77+
+ f"{datetime.tm_min:02}:"
78+
+ f"{datetime.tm_sec:02}"
8679
)
8780

8881

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:
82+
while True:
83+
# Connect to Wi-Fi
84+
print("\nConnecting to WiFi...")
85+
while not wifi.radio.ipv4_address:
86+
try:
87+
wifi.radio.connect(ssid, password)
88+
except ConnectionError as e:
89+
print("❌ Connection Error:", e)
90+
print("Retrying in 10 seconds")
91+
print("✅ Wifi!")
92+
9493
try:
95-
wifi.radio.connect(ssid, password)
96-
except ConnectionError as e:
97-
print("Connection Error:", e)
98-
print("Retrying in 10 seconds")
99-
time.sleep(10)
100-
print("Connected!\n")
94+
print(" | Attempting to GET OpenSky-Network Single Private Flight JSON!")
95+
print(" | Website Credentials Required! Allows more daily calls than Public.")
96+
try:
97+
opensky_response = requests.get(url=OPENSKY_SOURCE, headers=OPENSKY_HEADER)
98+
opensky_json = opensky_response.json()
99+
except ConnectionError as e:
100+
print("Connection Error:", e)
101+
print("Retrying in 10 seconds")
101102

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("===============================")
103+
print(" | ✅ OpenSky-Network JSON!")
109104

110-
print("\nAttempting to GET OpenSky-Network Data!")
111-
opensky_response = request.get(url=OPENSKY_SOURCE, headers=osn_header).json()
105+
if DEBUG:
106+
print("Full API GET URL: ", OPENSKY_SOURCE)
107+
print("Full API GET Header: ", OPENSKY_HEADER)
108+
print(opensky_json)
112109

113-
# Print Full JSON to Serial (doesn't show credentials)
114-
debug_response = False # Set True to see full response
115-
if debug_response:
116-
dump_object = json.dumps(opensky_response)
117-
print("JSON Dump: ", dump_object)
110+
# ERROR MESSAGE RESPONSES
111+
if "timestamp" in opensky_json:
112+
osn_timestamp = opensky_json["timestamp"]
113+
print(f"❌ Timestamp: {osn_timestamp}")
118114

119-
# Key:Value Serial Debug (doesn't show credentials)
120-
osn_debug_keys = True # Set True to print Serial data
121-
if osn_debug_keys:
122-
try:
123-
osn_flight = opensky_response["time"]
124-
print("Current Unix Time: ", osn_flight)
125-
126-
current_struct_time = time.localtime(osn_flight)
127-
current_date = "{}".format(_format_datetime(current_struct_time))
128-
print(f"Unix to Readable Time: {current_date}")
129-
130-
# Current flight data for single callsign (right now)
131-
osn_single_flight_data = opensky_response["states"]
132-
133-
if osn_single_flight_data is not None:
134-
print("Flight Data: ", osn_single_flight_data)
135-
transponder = opensky_response["states"][0][0]
136-
print("Transponder: ", transponder)
137-
callsign = opensky_response["states"][0][1]
138-
print("Callsign: ", callsign)
139-
country = opensky_response["states"][0][2]
140-
print("Flight Country: ", country)
115+
if "message" in opensky_json:
116+
osn_message = opensky_json["message"]
117+
print(f"❌ Message: {osn_message}")
118+
119+
if "error" in opensky_json:
120+
osn_error = opensky_json["error"]
121+
print(f"❌ Error: {osn_error}")
122+
123+
if "path" in opensky_json:
124+
osn_path = opensky_json["path"]
125+
print(f"❌ Path: {osn_path}")
126+
127+
if "status" in opensky_json:
128+
osn_status = opensky_json["status"]
129+
print(f"❌ Status: {osn_status}")
130+
131+
# Current flight data for single callsign (right now)
132+
osn_single_flight_data = opensky_json["states"]
133+
134+
if osn_single_flight_data is not None:
135+
if DEBUG:
136+
print(f" | | Single Private Flight Data: {osn_single_flight_data}")
137+
138+
last_contact = opensky_json["states"][0][4]
139+
# print(f" | | Last Contact Unix Time: {last_contact}")
140+
lc_struct_time = time.localtime(last_contact)
141+
lc_readable_time = f"{_format_datetime(lc_struct_time)}"
142+
print(f" | | Last Contact: {lc_readable_time}")
143+
144+
flight_transponder = opensky_json["states"][0][0]
145+
print(f" | | Transponder: {flight_transponder}")
146+
147+
callsign = opensky_json["states"][0][1]
148+
print(f" | | Callsign: {callsign}")
149+
150+
squawk = opensky_json["states"][0][14]
151+
print(f" | | Squawk: {squawk}")
152+
153+
country = opensky_json["states"][0][2]
154+
print(f" | | Origin: {country}")
155+
156+
longitude = opensky_json["states"][0][5]
157+
print(f" | | Longitude: {longitude}")
158+
159+
latitude = opensky_json["states"][0][6]
160+
print(f" | | Latitude: {latitude}")
161+
162+
# Return Air Flight data if not on ground
163+
on_ground = opensky_json["states"][0][8]
164+
if on_ground is True:
165+
print(f" | | On Ground: {on_ground}")
141166
else:
142-
print("Flight has no active data or you're polling too fast.")
143-
144-
print("\nFinished!")
145-
print("Board Uptime: ", time_calc(time.monotonic()))
146-
print("Next Update: ", time_calc(sleep_time))
147-
time.sleep(sleep_time)
148-
print("===============================")
149-
150-
except (ConnectionError, ValueError, NameError) as e:
151-
print("OSN Connection Error:", e)
152-
print("Next Retry: ", time_calc(sleep_time))
153-
time.sleep(sleep_time)
167+
altitude = opensky_json["states"][0][7]
168+
print(f" | | Barometric Altitude: {altitude}")
169+
170+
velocity = opensky_json["states"][0][9]
171+
if velocity != "null":
172+
print(f" | | Velocity: {velocity}")
173+
174+
vertical_rate = opensky_json["states"][0][11]
175+
if vertical_rate != "null":
176+
print(f" | | Vertical Rate: {vertical_rate}")
177+
178+
else:
179+
print(" | | ❌ Flight has no active data or you're polling too fast.")
180+
181+
opensky_response.close()
182+
print("✂️ Disconnected from OpenSky-Network API")
183+
184+
print("\nFinished!")
185+
print(f"Board Uptime: {time_calc(time.monotonic())}")
186+
print(f"Next Update: {time_calc(SLEEP_TIME)}")
187+
print("===============================")
188+
189+
except (ValueError, RuntimeError) as e:
190+
print(f"Failed to get data, retrying\n {e}")
191+
time.sleep(60)
192+
break
193+
time.sleep(SLEEP_TIME)

0 commit comments

Comments
 (0)