Skip to content

Commit

Permalink
Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
crnicholson committed Dec 2, 2024
1 parent 42df597 commit 1eb55e0
Show file tree
Hide file tree
Showing 2 changed files with 212 additions and 11 deletions.
32 changes: 32 additions & 0 deletions Code/groundStation/uploader/data/KC1SFR_to_glider.csv
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,35 @@ tLat,tLon,abort
42.307,-71.335,1.0
42.307,-71.335,0.0
42.307,-71.335,1.0
42334.0,7198.0,1.0
42356.0,71234.0,1.0
42356.0,71234.0,1.0
42356.0,71234.0,1.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
42.307,-71.335,0.0
191 changes: 180 additions & 11 deletions Code/groundStation/uploader/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
import os
import datetime
import threading
from flask import Flask, request, jsonify
from flask_cors import CORS
import numpy as np

PORT = 41773 # Match this with the port in your ESP32 code.
WEBSOCKET_PORT = 41773 # Match this with the port in your ESP32 code.
HTTP_PORT = 5000
COMMENT = "StratoSoar MK3 high altitude glider."
ANTENNA = "Wire monopole"
RADIO = "SX1278 LoRa module"
Expand All @@ -17,6 +21,9 @@

last_print = 0

app = Flask(__name__)
CORS(app)


# Handler for incoming WebSocket connections.
async def handle_connection(websocket):
Expand Down Expand Up @@ -69,7 +76,7 @@ async def handle_connection(websocket):
microsecond=0,
)
utc_time_str = utc_time.strftime("%Y-%m-%dT%H:%M:%SZ")

print(f"\nReceived data from {call_sign} at {utc_time_str}")

df = pd.DataFrame()
Expand Down Expand Up @@ -139,8 +146,10 @@ async def handle_connection(websocket):
"Uploader alt": u_alt,
"ID": id,
}

print(f"Lat: {lat}, lon: {lon}, alt: {alt}, target lat: {t_lat}, target lon: {t_lon}, yaw: {yaw}, pitch: {pitch}, roll: {roll}, time: {utc_time_str}, temp: {temp}, pressure: {pressure}, humidity: {humidity}, volts: {volts}, received abort: {received_abort}, tx count: {tx_count}, rx count: {rx_count}, rssi: {rssi}, snr: {snr}, uploader lat: {u_lat}, uploader lon: {u_lon}, uploader alt: {u_alt}, id: {id}")

print(
f"Lat: {lat}, lon: {lon}, alt: {alt}, target lat: {t_lat}, target lon: {t_lon}, yaw: {yaw}, pitch: {pitch}, roll: {roll}, time: {utc_time_str}, temp: {temp}, pressure: {pressure}, humidity: {humidity}, volts: {volts}, received abort: {received_abort}, tx count: {tx_count}, rx count: {rx_count}, rssi: {rssi}, snr: {snr}, uploader lat: {u_lat}, uploader lon: {u_lon}, uploader alt: {u_alt}, id: {id}"
)

df = pd.DataFrame([data])

Expand Down Expand Up @@ -227,13 +236,21 @@ def input_thread():
while True:
try:
print("\nAvialable call signs:")
print([file.replace(".csv", "") for file in os.listdir(f"{os.getcwd()}/data") if "glider" not in file])
print(
[
file.replace(".csv", "")
for file in os.listdir(f"{os.getcwd()}/data")
if "glider" not in file
]
)
s_call_sign = input("Enter the call sign you would like to change:\n")
if s_call_sign + ".csv" in os.listdir(f"{cwd}/data"):
df = pd.read_csv(f"{cwd}/data/{s_call_sign}.csv")

print(f"\nData for {s_call_sign}:")
print(f"Lat: {df.iloc[-1]['Lat']}, lon: {df.iloc[-1]['Lon']}, alt: {df.iloc[-1]['Alt']}, last received at {df.iloc[-1]['Time']}, voltage: {df.iloc[-1]['Voltage']}")
print(
f"Lat: {df.iloc[-1]['Lat']}, lon: {df.iloc[-1]['Lon']}, alt: {df.iloc[-1]['Alt']}, last received at {df.iloc[-1]['Time']}, voltage: {df.iloc[-1]['Voltage']}"
)
print(f"Abort status: {df.iloc[-1]['Received abort']}")
print(f"Target latitude: {df.iloc[-1]['Target lat']}")
print(f"Target longitude: {df.iloc[-1]['Target lon']}")
Expand Down Expand Up @@ -302,13 +319,165 @@ def input_thread():
)


# Main WebSocket server coroutine.
@app.route("/api/get-stations", methods=["POST"])
def get_stations():
df = pd.read_csv(f"{cwd}/stations.csv")
recent_stations = []

for i in range(len(df)):
station_time = datetime.datetime.strptime(
df.loc[i, "Time"], "%Y-%m-%dT%H:%M:%SZ"
)
time_diff = datetime.datetime.now(datetime.timezone.utc) - station_time

if time_diff.total_seconds() < 60:
station_data = {
"ID": df.loc[i, "ID"],
"Call sign": df.loc[i, "Call sign"],
"Time": df.loc[i, "Time"],
"SNR": df.loc[i, "SNR"],
"RSSI": df.loc[i, "RSSI"],
}
recent_stations.append(station_data) #
else:
if not recent_stations:
print("No stations received data in the last 60 seconds.")

return jsonify(recent_stations)


@app.route("/api/get-gliders", methods=["POST"])
def get_gliders():
gliders = [
file.replace(".csv", "")
for file in os.listdir(f"{os.getcwd()}/data")
if "glider" not in file
]
return jsonify({"gliders": gliders}), 200


@app.route("/api/get-glider-data", methods=["POST"])
def get_data():
received = request.get_json()
call_sign = received["call_sign"]
if not call_sign:
return jsonify({"error": "Missing call_sign parameter"}), 400

if not os.path.isfile(f"{cwd}/data/{call_sign}.csv"):
return jsonify({"error": f"Data file for {call_sign} not found"}), 404

try:
df = pd.read_csv(f"{cwd}/data/{call_sign}.csv")
except Exception as e:
return jsonify({"error": f"Error reading data file: {str(e)}"}), 500

if df.empty:
return jsonify({"error": "Data file is empty"}), 404

latest_data = df.iloc[-1]

def safe_get(column):
value = latest_data.get(column, None)
if pd.isna(value):
return None
# Convert numpy types to native Python types
if isinstance(value, (np.int64, np.int32)):
return int(value)
elif isinstance(value, (np.float64, np.float32)):
return float(value)
return value

response_data = {
"Lat": safe_get("Lat"),
"Lon": safe_get("Lon"),
"Alt": safe_get("Alt"),
"Target_Lat": safe_get("Target_Lat"),
"Target_Lon": safe_get("Target_Lon"),
"Yaw": safe_get("Yaw"),
"Pitch": safe_get("Pitch"),
"Roll": safe_get("Roll"),
"Time": safe_get("Time"),
"Temp": safe_get("Temp"),
"Pressure": safe_get("Pressure"),
"Humidity": safe_get("Humidity"),
"Volts": safe_get("Voltage"),
"Received_Abort": safe_get("Received_Abort"),
"Tx_Count": safe_get("Tx_Count"),
"Rx_Count": safe_get("Rx_Count"),
"RSSI": safe_get("RSSI"),
"SNR": safe_get("SNR"),
"Uploader_Lat": safe_get("Uploader_Lat"),
"Uploader_Lon": safe_get("Uploader_Lon"),
"Uploader_Alt": safe_get("Uploader_Alt"),
"ID": safe_get("ID"),
}

return jsonify(response_data)


@app.route("/api/change-glider-data", methods=["POST"])
def change_data():
received = request.get_json()
call_sign = received["call_sign"]
abort = received["abort"]
new_t_lat = received["t_lat"]
new_t_lon = received["t_lon"]

if not os.path.isfile(f"{cwd}/data/{call_sign}.csv"):
return jsonify({"error": f"Data file for {call_sign} not found"}), 404

try:
df = pd.read_csv(f"{cwd}/data/{call_sign}.csv")
except Exception as e:
return jsonify({"error": f"Error reading data file: {str(e)}"}), 500

if new_t_lat == 0 or new_t_lon == None:
new_t_lat = df.iloc[-1]["Target lat"]
if new_t_lon == 0 or new_t_lon == None:
new_t_lon = df.iloc[-1]["Target lon"]
if abort == None:
abort = df.iloc[-1]["Received abort"]

if os.path.exists(f"{cwd}/data/{call_sign}_to_glider.csv"):
df = pd.read_csv(f"{cwd}/data/{call_sign}_to_glider.csv")

data = {
"tLat": new_t_lat,
"tLon": new_t_lon,
"abort": abort,
}

df = df._append(data, ignore_index=True)

df.to_csv(f"{cwd}/data/{call_sign}_to_glider.csv", index=False)
else:
data = {
"tLat": new_t_lat,
"tLon": new_t_lon,
"abort": abort,
}

df = pd.DataFrame([data])

file = f"{cwd}/data/{call_sign}_to_glider.csv"
df.to_csv(
file,
mode="a",
header=not pd.io.common.file_exists(file),
index=False,
)

return jsonify({"message": "Success"}), 200


# Main WebSocket server coroutine.
async def main():
print(f"Starting server on ws://0.0.0.0:{PORT}")
async with websockets.serve(handle_connection, "0.0.0.0", PORT):
await asyncio.Future() # Run forever.
print(f"Starting server on ws://0.0.0.0:{WEBSOCKET_PORT}")
async with websockets.serve(handle_connection, "0.0.0.0", WEBSOCKET_PORT):
await asyncio.Future() # Run forever.


if __name__ == "__main__":
app.run(debug=True, port=HTTP_PORT)
threading.Thread(target=input_thread).start()
asyncio.run(main())
asyncio.run(main())

0 comments on commit 1eb55e0

Please sign in to comment.