-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
346853c
commit af3fc99
Showing
7 changed files
with
201 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,88 @@ | ||
from fastapi import FastAPI | ||
from fastapi import FastAPI, HTTPException | ||
from skyfield.api import load, EarthSatellite | ||
from datetime import datetime, timedelta | ||
|
||
app = FastAPI(root_path="/api") | ||
|
||
# Define TLE data for Landsat 8 (this can be updated periodically) | ||
landsat_8_tle = [ | ||
"1 39084U 13008A 23270.47419877 .00000029 00000-0 27947-4 0 9999", | ||
"2 39084 98.2045 221.3107 0001356 98.0138 262.1118 14.57109887552706" | ||
] | ||
|
||
# Load timescale and define the satellite | ||
satellite_db = { | ||
"landsat_8": EarthSatellite(landsat_8_tle[0], landsat_8_tle[1], "Landsat 8", load.timescale()) | ||
} | ||
|
||
|
||
@app.get("/satellite/") | ||
def get_all_satellites(): | ||
""" | ||
Returns the names of all available satellites. | ||
""" | ||
return {"satellites": list(satellite_db.keys())} | ||
|
||
@app.get("/satellite/{satellite_name}") | ||
def get_satellite_info(satellite_name: str): | ||
""" | ||
Returns the current location and information of the specified satellite. | ||
""" | ||
# Check if the requested satellite exists in our database | ||
satellite = satellite_db.get(satellite_name.lower()) | ||
if not satellite: | ||
raise HTTPException(status_code=404, detail="Satellite not found") | ||
|
||
# Get the current position of the satellite | ||
t = load.timescale().now() | ||
geocentric = satellite.at(t) | ||
subpoint = geocentric.subpoint() | ||
|
||
# Return the satellite information | ||
return { | ||
"name": satellite_name, | ||
"timestamp": datetime.utcnow().isoformat(), | ||
"latitude": subpoint.latitude.degrees, | ||
"longitude": subpoint.longitude.degrees, | ||
"altitude_km": subpoint.elevation.km | ||
} | ||
|
||
@app.get("/satellite/{satellite_name}/forecast") | ||
def get_satellite_forecast(satellite_name: str, hours: int = 1): | ||
""" | ||
Returns the forecasted location of the satellite over the next specified hours. | ||
""" | ||
# Check if the requested satellite exists in our database | ||
satellite = satellite_db.get(satellite_name.lower()) | ||
if not satellite: | ||
raise HTTPException(status_code=404, detail="Satellite not found") | ||
|
||
# Generate times over the next 'hours' hours at 15-minute intervals | ||
ts = load.timescale() | ||
t0 = ts.now() | ||
t1 = ts.utc(t0.utc_datetime() + timedelta(hours=hours)) | ||
num_intervals = hours * 16 + 1 # Every 15 minutes | ||
times = ts.linspace(t0, t1, num_intervals) | ||
|
||
# Compute positions at each time | ||
positions = [] | ||
for t in times: | ||
geocentric = satellite.at(t) | ||
subpoint = geocentric.subpoint() | ||
positions.append({ | ||
"timestamp": t.utc_iso(), | ||
"latitude": subpoint.latitude.degrees, | ||
"longitude": subpoint.longitude.degrees, | ||
"altitude_km": subpoint.elevation.km | ||
}) | ||
|
||
# Return the forecast data | ||
return { | ||
"name": satellite_name, | ||
"forecast": positions | ||
} | ||
|
||
@app.get("/") | ||
def read_root(): | ||
return {"message": "Hello World!"} | ||
|
||
@app.get("/items/{item_id}") | ||
def read_item(item_id: int): | ||
return {"item_id": item_id} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
fastapi | ||
uvicorn | ||
skyfield |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
"use client"; | ||
|
||
import { useEffect, useState } from "react"; | ||
import { LatLngTuple } from "leaflet"; | ||
import { Marker, Polyline } from "react-leaflet"; | ||
import { Icon, IconOptions, DivIcon } from "leaflet"; | ||
|
||
interface SatelliteLayerProps { | ||
customIcon: Icon<IconOptions> | DivIcon | undefined; | ||
} | ||
|
||
export default function SatelliteLayer({ customIcon }: SatelliteLayerProps) { | ||
// State for the Landsat 8 satellite position and trajectory | ||
const [satellitePosition, setSatellitePosition] = useState<LatLngTuple | null>(null); | ||
const [satelliteTrajectory, setSatelliteTrajectory] = useState<LatLngTuple[]>([]); | ||
const [forecastTrajectory, setForecastTrajectory] = useState<LatLngTuple[]>([]); // New state for forecast | ||
|
||
// Fetch the current position of Landsat 8 periodically | ||
useEffect(() => { | ||
const fetchSatellitePosition = async () => { | ||
try { | ||
const response = await fetch("/api/satellite/landsat_8"); | ||
const data = await response.json(); | ||
if (data.latitude && data.longitude) { | ||
const currentPosition: LatLngTuple = [data.latitude, data.longitude]; | ||
setSatellitePosition(currentPosition); | ||
|
||
// Append current position to trajectory for visualization | ||
setSatelliteTrajectory((prevTrajectory) => { | ||
// Limit the length of the trajectory for performance | ||
const updatedTrajectory = [...prevTrajectory, currentPosition]; | ||
return updatedTrajectory.length > 100 ? updatedTrajectory.slice(1) : updatedTrajectory; | ||
}); | ||
} | ||
} catch (error) { | ||
console.error("Error fetching satellite position:", error); | ||
} | ||
}; | ||
|
||
// Fetch position every 10 seconds | ||
fetchSatellitePosition(); | ||
const interval = setInterval(fetchSatellitePosition, 10000); | ||
|
||
return () => clearInterval(interval); | ||
}, []); | ||
|
||
// Fetch the forecasted trajectory | ||
useEffect(() => { | ||
const fetchForecastTrajectory = async () => { | ||
try { | ||
const response = await fetch("/api/satellite/landsat_8/forecast"); | ||
const data = await response.json(); | ||
if (data.forecast && Array.isArray(data.forecast)) { | ||
const forecastPositions: LatLngTuple[] = data.forecast.map((point: { longitude: number, latitude: number }) => [point.latitude, point.longitude]); | ||
setForecastTrajectory(forecastPositions); | ||
} | ||
} catch (error) { | ||
console.error("Error fetching satellite forecast trajectory:", error); | ||
} | ||
}; | ||
|
||
fetchForecastTrajectory(); | ||
|
||
// Optionally, refresh the forecast periodically | ||
const interval = setInterval(fetchForecastTrajectory, 3600000); // Refresh every hour | ||
|
||
return () => clearInterval(interval); | ||
}, []); | ||
|
||
return ( | ||
<> | ||
{/* Render the Landsat 8 satellite position */} | ||
{satellitePosition && <Marker position={satellitePosition} icon={customIcon} />} | ||
|
||
{/* Render the Landsat 8 satellite trajectory */} | ||
{satelliteTrajectory.length > 1 && ( | ||
<Polyline positions={satelliteTrajectory} color="red" /> | ||
)} | ||
|
||
{/* Render the forecasted trajectory */} | ||
{forecastTrajectory.length > 1 && ( | ||
<Polyline positions={forecastTrajectory} color="blue" /> | ||
)} | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters