Add rotating earth view
commit
23929fdf6c
229
satnogs.py
229
satnogs.py
|
@ -1,4 +1,4 @@
|
|||
from datetime import datetime , timedelta
|
||||
from datetime import datetime, timedelta
|
||||
import requests
|
||||
from tqdm import tqdm
|
||||
from flask import Flask , render_template,redirect,url_for, request
|
||||
|
@ -6,14 +6,15 @@ import json
|
|||
from collections import defaultdict, Counter
|
||||
import random
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from satnogs_api_client import fetch_satellites, DB_BASE_URL,fetch_tle_of_observation ,get_paginated_endpoint
|
||||
from satnogs_api_client import fetch_satellites
|
||||
from satnogs_api_client import DB_BASE_URL, get_paginated_endpoint
|
||||
from satellite_tle import fetch_tles
|
||||
from skyfield.api import EarthSatellite,utc,load
|
||||
from skyfield.api import EarthSatellite, utc, load
|
||||
|
||||
scheduler = BackgroundScheduler()
|
||||
app = Flask(__name__)
|
||||
|
||||
ts = load.timescale()
|
||||
ts = load.timescale()
|
||||
|
||||
|
||||
broken = defaultdict(set)
|
||||
|
@ -29,114 +30,106 @@ StationsPasses = defaultdict(list)
|
|||
SatDescrip = defaultdict(str)
|
||||
CZML = []
|
||||
|
||||
|
||||
def getFuture():
|
||||
print "Getting future Passes"
|
||||
global Sats
|
||||
global TLEs
|
||||
|
||||
observations = defaultdict(dict )
|
||||
|
||||
observations = defaultdict(dict)
|
||||
start = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S%z')
|
||||
end = (datetime.utcnow() + timedelta(hours=4,minutes=30)).strftime('%Y-%m-%dT%H:%M:%S%z')
|
||||
|
||||
end = (datetime.utcnow() + timedelta(hours=4, minutes=30))
|
||||
end = end.strftime('%Y-%m-%dT%H:%M:%S%z')
|
||||
passes = get_paginated_endpoint("https://network.satnogs.org/api/jobs/")
|
||||
obs = get_paginated_endpoint("https://network.satnogs.org/api/observations/?end="+end+"&format=json&start="+start)
|
||||
for x in tqdm(obs):
|
||||
observations[x["id"]] = x
|
||||
ground_stations = {}
|
||||
Sats = defaultdict(list)
|
||||
for x in tqdm(passes):
|
||||
if x["id"] in observations:
|
||||
try:
|
||||
start = datetime.strptime(x["start"],'%Y-%m-%dT%H:%M:%Sz')
|
||||
start = datetime.strptime(x["start"], '%Y-%m-%dT%H:%M:%Sz')
|
||||
start = start.replace(tzinfo=utc)
|
||||
end = datetime.strptime(x["end"],'%Y-%m-%dT%H:%M:%Sz')
|
||||
end = datetime.strptime(x["end"], '%Y-%m-%dT%H:%M:%Sz')
|
||||
end = end.replace(tzinfo=utc)
|
||||
# "transmitter":Transmitters[observations[x["id"]]["norad_cat_id"]][x["transmitter"]]
|
||||
Sats[observations[x["id"]]["norad_cat_id"]].append({"station":x["ground_station"],"transmitter":Transmitters[observations[x["id"]]["norad_cat_id"]][x["transmitter"]],"start":start,"end":end,"id":x["id"]})
|
||||
TLEs[observations[x["id"]]["norad_cat_id"]]=[x["tle0"],x["tle1"],x["tle2"]]
|
||||
StationsPasses[x["ground_station"]].append({"norad":observations[x["id"]]["norad_cat_id"],"transmitter":Transmitters[observations[x["id"]]["norad_cat_id"]][x["transmitter"]],"start":start,"end":end,"id":x["id"]})
|
||||
Sats[observations[x["id"]]["norad_cat_id"]].append({"station": x["ground_station"], "transmitter": Transmitters[observations[x["id"]]["norad_cat_id"]][x["transmitter"]], "start": start, "end": end, "id": x["id"]})
|
||||
TLEs[observations[x["id"]]["norad_cat_id"]] = [x["tle0"], x["tle1"], x["tle2"]]
|
||||
StationsPasses[x["ground_station"]].append({"norad": observations[x["id"]]["norad_cat_id"], "transmitter": Transmitters[observations[x["id"]]["norad_cat_id"]][x["transmitter"]], "start": start, "end": end, "id": x["id"]})
|
||||
except Exception as e:
|
||||
print "Error on observation number: "+str(x["id"])+ " "+str(e)
|
||||
print "Error on observation number: " + str(x["id"]) + " " + str(e)
|
||||
broken[observations[x["id"]]["norad_cat_id"]].update([x["transmitter"]])
|
||||
print str(len(Sats))+" Future passes found."
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def GetGroundStations():
|
||||
print "Getting Ground Stations"
|
||||
|
||||
stations = get_paginated_endpoint("https://network.satnogs.org/api/stations/")
|
||||
|
||||
|
||||
|
||||
|
||||
return stations
|
||||
|
||||
|
||||
|
||||
|
||||
def updateTLE():
|
||||
print "Updating TLE"
|
||||
global TLEs
|
||||
sats = fetch_satellites(None,DB_BASE_URL)
|
||||
sats = fetch_satellites(None, DB_BASE_URL)
|
||||
satnogs_db_norad_ids = set(sat['norad_cat_id'] for sat in sats if sat['status'] != 're-entered')
|
||||
# Remove satellites with temporary norad ids
|
||||
temporary_norad_ids = set(filter(lambda norad_id: norad_id >= 99900, satnogs_db_norad_ids))
|
||||
satnogs_db_norad_ids = satnogs_db_norad_ids - temporary_norad_ids
|
||||
|
||||
# Fetch TLEs for the satellites of interest
|
||||
|
||||
|
||||
tles = fetch_tles(satnogs_db_norad_ids)
|
||||
TLEs = {}
|
||||
for norad_id, (source, tle) in tqdm(tles.items()):
|
||||
TLEs[norad_id] = [str(tle[0]),str(tle[1]),str(tle[2])]
|
||||
TLEs[norad_id] = [str(tle[0]), str(tle[1]), str(tle[2])]
|
||||
print('\nTLEs for {} of {} requested satellites found ({} satellites with temporary norad ids skipped).'.format(len(tles), len(satnogs_db_norad_ids), len(temporary_norad_ids)))
|
||||
|
||||
|
||||
|
||||
@scheduler.scheduled_job('interval',days=5)
|
||||
@scheduler.scheduled_job('interval', days=5)
|
||||
def updateTransmitters():
|
||||
global Transmitters
|
||||
print "Updating Transmitters"
|
||||
temp = requests.get("https://db.satnogs.org/api/transmitters/").json()
|
||||
for x in tqdm(temp):
|
||||
Transmitters[x["norad_cat_id"]][x["uuid"]] = [x["description"],[random.randint(0,255),random.randint(0,255),random.randint(0,255),255]]
|
||||
|
||||
Transmitters[x["norad_cat_id"]][x["uuid"]] = [x["description"], [random.randint(0, 255), random.randint(0, 255), random.randint(0, 255), 255]]
|
||||
|
||||
for x in Transmitters.keys():
|
||||
for y in Transmitters[x].keys():
|
||||
SatDescrip[x] += '<div class="trans" style="background-color:#'+str("%02x" % Transmitters[x][y][1][0])+str("%02x" % Transmitters[x][y][1][1])+str("%02x" % Transmitters[x][y][1][2])+'";>'+Transmitters[x][y][0]+'</div>'
|
||||
|
||||
@scheduler.scheduled_job('interval',hours=1)
|
||||
|
||||
|
||||
@scheduler.scheduled_job('interval', hours=1)
|
||||
def updatePasses():
|
||||
getFuture()
|
||||
|
||||
@scheduler.scheduled_job('interval',hours=1)
|
||||
|
||||
|
||||
@scheduler.scheduled_job('interval', hours=1)
|
||||
def updateStations():
|
||||
global Stations
|
||||
print "Updating Stations"
|
||||
Stations = GetGroundStations()
|
||||
|
||||
@scheduler.scheduled_job('interval',minutes=30)
|
||||
def updateCZML():
|
||||
|
||||
|
||||
@scheduler.scheduled_job('interval', minutes=30)
|
||||
def updateCZML():
|
||||
global CZML
|
||||
CZML=[]
|
||||
CZML = []
|
||||
doc = {}
|
||||
doc["id"] = "document"
|
||||
doc["name"] = "sats"
|
||||
doc["version"]="1.0"
|
||||
doc["clock"]={}
|
||||
doc["clock"]["interval"]="0000-00-00T00:00:00Z/9999-12-31T24:00:00Z"
|
||||
doc["version"] = "1.0"
|
||||
doc["clock"] = {}
|
||||
doc["clock"]["interval"] = "0000-00-00T00:00:00Z/9999-12-31T24:00:00Z"
|
||||
doc["clock"]["step"] = "SYSTEM_CLOCK"
|
||||
CZML.append(doc)
|
||||
|
||||
StationList = {}
|
||||
|
||||
|
||||
for x in tqdm(Stations):
|
||||
color = [0,230,64,255]
|
||||
color = [0, 230, 64, 255]
|
||||
if x["status"] == "Testing":
|
||||
color = [248,148,6,255]
|
||||
color = [248, 148, 6, 255]
|
||||
if x["status"] == "Offline":
|
||||
color = [255,0,0,50]
|
||||
|
||||
color = [255, 0, 0, 50]
|
||||
|
||||
station = {}
|
||||
station["id"] = str(x["id"])
|
||||
station["name"] = x["name"]
|
||||
|
@ -145,61 +138,50 @@ def updateCZML():
|
|||
station["point"]["color"] = {}
|
||||
station["point"]["color"]["rgba"] = color
|
||||
station["point"]["outlineColor"] = {}
|
||||
station["point"]["outlineColor"]["rgba"] = [255,255,255,color[3]]
|
||||
station["point"]["outlineColor"]["rgba"] = [255, 255, 255, color[3]]
|
||||
station["point"]["outlineWidth"] = 2.0
|
||||
station["position"] = {}
|
||||
station["point"]["pixelSize"]=7.0
|
||||
station["position"]["cartographicDegrees"] = [x["lng"],x['lat'],x["altitude"]]
|
||||
station["description"] = "<b>ID: "+str(x["id"])+"</b><br><b>Total Observations: "
|
||||
station["description"]+=str(x["observations"])+"</b><br><b>Status: "+x["status"]+"</b><br><b>QTH: "
|
||||
station["description"]+=x["qthlocator"]+"</b><br></b>Description: </b>"+x["description"]
|
||||
station["point"]["pixelSize"] = 7.0
|
||||
station["position"]["cartographicDegrees"] = [x["lng"], x['lat'], x["altitude"]]
|
||||
station["description"] = "<b>ID: "+str(x["id"]) + "</b><br><b>Total Observations: "
|
||||
station["description"] += str(x["observations"]) + "</b><br><b>Status: " + x["status"] + "</b><br><b>QTH: "
|
||||
station["description"] += x["qthlocator"] + "</b><br></b>Description: </b>" + x["description"]
|
||||
CZML.append(station)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for x in tqdm(Sats.keys()):
|
||||
for y in Sats[x]:
|
||||
sat = {}
|
||||
sat["id"] = str(y["id"])
|
||||
sat["name"] = TLEs[x][0]
|
||||
sat["show"] = True
|
||||
#sat["point"] = {}
|
||||
#sat["point"]["color"] = {}
|
||||
#sat["point"]["color"]["rgba"] = [255,0,0,255]
|
||||
#sat["point"]["pixelSize"]=8.0
|
||||
sat["billboard"] = {"image":"static/sat.png","scale":0.50}
|
||||
sat["billboard"] = {"image": "static/sat.png", "scale": 0.50}
|
||||
sat["position"] = {}
|
||||
sat["position"]["cartographicDegrees"]=[]
|
||||
sat["position"]["cartographicDegrees"] = []
|
||||
sat["description"] = SatDescrip[x]
|
||||
temp = y["start"]
|
||||
satObj = EarthSatellite(TLEs[x][1],TLEs[x][2],TLEs[x][0])
|
||||
satObj = EarthSatellite(TLEs[x][1], TLEs[x][2], TLEs[x][0])
|
||||
time = 0
|
||||
while temp <= y["end"]+timedelta(minutes=1):
|
||||
|
||||
while temp <= y["end"] + timedelta(minutes=1):
|
||||
subpoint = satObj.at(ts.utc(temp)).subpoint()
|
||||
lat = subpoint.latitude.degrees
|
||||
lng = subpoint.longitude.degrees
|
||||
elevation = subpoint.elevation.m
|
||||
sat["position"]["cartographicDegrees"].extend([time,lng,lat,elevation])
|
||||
time+=60
|
||||
temp = temp+timedelta(minutes=1)
|
||||
sat["position"]["cartographicDegrees"].extend([time, lng, lat, elevation])
|
||||
time += 60
|
||||
temp = temp + timedelta(minutes=1)
|
||||
sat["position"]["interpolationAlgorithm"] = "LAGRANGE"
|
||||
sat["position"]["interpolationDegree"] = 5
|
||||
# sat["position"]["referenceFrame"] = "INERTIAL"
|
||||
sat["position"]["epoch"] = (y["start"].isoformat()+"Z").replace("+00:00","")
|
||||
sat["path"] = {"show":{"interval":(y["start"].isoformat()+"Z").replace("+00:00","")+"/"+((y["end"]+timedelta(minutes=1)).isoformat()+"Z").replace("+00:00",""),"boolean":True},"width":2,"material":{"solidColor":{"color":{"rgba":[0,255,0,255]}}},"leadTime":100000,"trailTime":100000 }
|
||||
|
||||
sat["position"]["epoch"] = (y["start"].isoformat()+"Z").replace("+00:00", "")
|
||||
sat["path"] = {"show": {"interval": (y["start"].isoformat()+"Z").replace("+00:00", "") + "/" + ((y["end"] + timedelta(minutes=1)).isoformat()+"Z").replace("+00:00", ""), "boolean": True}, "width": 2, "material": {"solidColor": {"color": {"rgba": [0, 255, 0, 255]}}}, "leadTime": 100000, "trailTime": 100000}
|
||||
CZML.append(sat)
|
||||
for x in tqdm(Sats.keys()):
|
||||
for y in Sats[x]:
|
||||
sat = {}
|
||||
sat["id"] = str(y["id"])+"Link"
|
||||
sat["polyline"] = {"show":{"interval":(y["start"].isoformat()+"Z").replace("+00:00","")+"/"+((y["end"]+timedelta(minutes=1)).isoformat()+"Z").replace("+00:00",""),"boolean":True},"width":2,"material":{"solidColor":{"color":{"rgba":y["transmitter"][1]}}},"followSurface":False,"positions":{"references":[str(y["id"])+"#position",str(y["station"])+"#position"]}}
|
||||
CZML.append(sat)
|
||||
|
||||
|
||||
|
||||
sat["polyline"] = {"show": {"interval": (y["start"].isoformat()+"Z").replace("+00:00", "")+"/"+((y["end"]+timedelta(minutes=1)).isoformat()+"Z").replace("+00:00", ""), "boolean": True}, "width": 2, "material": {"solidColor": {"color": {"rgba": y["transmitter"][1]}}}, "followSurface": False, "positions": {"references": [str(y["id"])+"#position", str(y["station"]) + "#position"]}}
|
||||
CZML.append(sat)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
|
||||
|
@ -217,51 +199,44 @@ def index():
|
|||
def index_station(station_id):
|
||||
Usage.update(request.headers.get("CF-IPCountry"))
|
||||
return render_template("index.html",url="/czml/"+str(station_id))
|
||||
|
||||
|
||||
|
||||
@app.route('/future_sats')
|
||||
def api_future_sats():
|
||||
return json.dumps(Sats)
|
||||
|
||||
|
||||
|
||||
@app.route("/czml")
|
||||
def api_czml():
|
||||
return json.dumps(CZML)
|
||||
|
||||
@app.route("/broken")
|
||||
|
||||
|
||||
@app.route("/broken")
|
||||
def api_broken():
|
||||
output = defaultdict(list)
|
||||
for x in broken.keys():
|
||||
output[x]=list(broken[x])
|
||||
return json.dumps(output)
|
||||
|
||||
@app.route("/usage")
|
||||
def usage():
|
||||
return json.dumps(Usage)
|
||||
|
||||
|
||||
@app.route("/czml/<int:station_id>")
|
||||
@app.route("/czml/<int:station_id>")
|
||||
def api_station(station_id):
|
||||
czml = []
|
||||
doc = {}
|
||||
doc["id"] = "document"
|
||||
doc["name"] = "sats"
|
||||
doc["version"]="1.0"
|
||||
doc["clock"]={}
|
||||
doc["clock"]["interval"]="0000-00-00T00:00:00Z/9999-12-31T24:00:00Z"
|
||||
doc["clock"]["currentTime"] = datetime.utcnow().isoformat()+"Z"
|
||||
doc["version"] = "1.0"
|
||||
doc["clock"] = {}
|
||||
doc["clock"]["interval"] = "0000-00-00T00:00:00Z/9999-12-31T24:00:00Z"
|
||||
doc["clock"]["currentTime"] = datetime.utcnow().isoformat() + "Z"
|
||||
doc["clock"]["step"] = "SYSTEM_CLOCK"
|
||||
czml.append(doc)
|
||||
|
||||
|
||||
|
||||
for x in Stations:
|
||||
if x["id"] == station_id:
|
||||
color = [0,230,64,255]
|
||||
color = [0, 230, 64, 255]
|
||||
if x["status"] == "Testing":
|
||||
color = [248,148,6,255]
|
||||
color = [248, 148, 6, 255]
|
||||
if x["status"] == "Offline":
|
||||
color = [255,0,0,50]
|
||||
|
||||
color = [255, 0, 0, 50]
|
||||
station = {}
|
||||
station["id"] = str(x["id"])
|
||||
station["name"] = x["name"]
|
||||
|
@ -270,18 +245,17 @@ def api_station(station_id):
|
|||
station["point"]["color"] = {}
|
||||
station["point"]["color"]["rgba"] = color
|
||||
station["point"]["outlineColor"] = {}
|
||||
station["point"]["outlineColor"]["rgba"] = [255,255,255,color[3]]
|
||||
station["point"]["outlineColor"]["rgba"] = [255, 255, 255, color[3]]
|
||||
station["point"]["outlineWidth"] = 2.0
|
||||
station["position"] = {}
|
||||
station["point"]["pixelSize"]=7.0
|
||||
station["position"]["cartographicDegrees"] = [x["lng"],x['lat'],x["altitude"]]
|
||||
station["description"] = "<b>ID: "+str(x["id"])+"</b><br><b>Total Observations: "
|
||||
station["description"]+=str(x["observations"])+"</b><br><b>Status: "+x["status"]+"</b><br><b>QTH: "
|
||||
station["description"]+=x["qthlocator"]+"</b><br></b>Description: </b>"+x["description"]
|
||||
station["point"]["pixelSize"] = 7.0
|
||||
station["position"]["cartographicDegrees"] = [x["lng"], x['lat'], x["altitude"]]
|
||||
station["description"] = "<b>ID: " + str(x["id"]) + "</b><br><b>Total Observations: "
|
||||
station["description"] += str(x["observations"]) + "</b><br><b>Status: " + x["status"] + "</b><br><b>QTH: "
|
||||
station["description"] += x["qthlocator"] + "</b><br></b>Description: </b>" + x["description"]
|
||||
czml.append(station)
|
||||
break
|
||||
|
||||
|
||||
for y in StationsPasses[station_id]:
|
||||
sat = {}
|
||||
sat["id"] = str(y["id"])
|
||||
|
@ -289,47 +263,38 @@ def api_station(station_id):
|
|||
sat["show"] = True
|
||||
sat["point"] = {}
|
||||
sat["point"]["color"] = {}
|
||||
sat["point"]["color"]["rgba"] = [255,0,0,255]
|
||||
sat["point"]["pixelSize"]=8.0
|
||||
#sat["billboard"] = {"image":"static/sat.png","scale":0.50}
|
||||
sat["point"]["color"]["rgba"] = [255, 0, 0, 255]
|
||||
sat["point"]["pixelSize"] = 8.0
|
||||
sat["position"] = {}
|
||||
sat["position"]["cartographicDegrees"]=[]
|
||||
sat["position"]["cartographicDegrees"] = []
|
||||
sat["description"] = SatDescrip[y["norad"]]
|
||||
temp = y["start"]
|
||||
satObj = EarthSatellite(TLEs[y["norad"]][1],TLEs[y["norad"]][2],TLEs[y["norad"]][0])
|
||||
satObj = EarthSatellite(TLEs[y["norad"]][1], TLEs[y["norad"]][2], TLEs[y["norad"]][0])
|
||||
time = 0
|
||||
while temp <= y["end"]+timedelta(minutes=1):
|
||||
|
||||
subpoint = satObj.at(ts.utc(temp)).subpoint()
|
||||
lat = subpoint.latitude.degrees
|
||||
lng = subpoint.longitude.degrees
|
||||
elevation = subpoint.elevation.m
|
||||
sat["position"]["cartographicDegrees"].extend([time,lng,lat,elevation])
|
||||
time+=60
|
||||
temp = temp+timedelta(minutes=1)
|
||||
sat["position"]["cartographicDegrees"].extend([time, lng, lat, elevation])
|
||||
time += 60
|
||||
temp = temp + timedelta(minutes=1)
|
||||
sat["position"]["interpolationAlgorithm"] = "LAGRANGE"
|
||||
sat["position"]["interpolationDegree"] = 5
|
||||
sat["position"]["epoch"] = (y["start"].isoformat()+"Z").replace("+00:00","")
|
||||
sat["path"] = {"show":{"interval":(y["start"].isoformat()+"Z").replace("+00:00","")+"/"+((y["end"]+timedelta(minutes=1)).isoformat()+"Z").replace("+00:00",""),"boolean":True},"width":2,"material":{"solidColor":{"color":{"rgba":[0,255,0,255]}}},"leadTime":100000,"trailTime":100000 }
|
||||
|
||||
sat["position"]["epoch"] = (y["start"].isoformat() + "Z").replace("+00:00", "")
|
||||
sat["path"] = {"show": {"interval": (y["start"].isoformat()+"Z").replace("+00:00", "") + "/" + ((y["end"] + timedelta(minutes=1)).isoformat() + "Z").replace("+00:00", ""), "boolean": True}, "width": 2, "material": {"solidColor": {"color": {"rgba": [0, 255, 0, 255]}}}, "leadTime": 100000, "trailTime": 100000}
|
||||
czml.append(sat)
|
||||
|
||||
for y in StationsPasses[station_id]:
|
||||
sat = {}
|
||||
sat["id"] = str(y["id"])+"Link"
|
||||
sat["polyline"] = {"show":{"interval":(y["start"].isoformat()+"Z").replace("+00:00","")+"/"+((y["end"]+timedelta(minutes=1)).isoformat()+"Z").replace("+00:00",""),"boolean":True},"width":2,"material":{"solidColor":{"color":{"rgba":y["transmitter"][1]}}},"followSurface":False,"positions":{"references":[str(y["id"])+"#position",str(station_id)+"#position"]}}
|
||||
czml.append(sat)
|
||||
|
||||
sat["polyline"] = {"show": {"interval": (y["start"].isoformat()+"Z").replace("+00:00", "") + "/" + ((y["end"] + timedelta(minutes=1)).isoformat()+"Z").replace("+00:00", ""), "boolean": True}, "width": 2, "material": {"solidColor": {"color": {"rgba": y["transmitter"][1]}}}, "followSurface": False, "positions": {"references": [str(y["id"]) + "#position", str(station_id) + "#position"]}}
|
||||
czml.append(sat)
|
||||
return json.dumps(czml)
|
||||
|
||||
|
||||
|
||||
#updatePasses()
|
||||
|
||||
updateStations()
|
||||
updateTransmitters()
|
||||
getFuture()
|
||||
updateCZML()
|
||||
#updateTLE()
|
||||
#updatePasses()
|
||||
scheduler.start()
|
||||
app.run(use_reloader=False,host = "0.0.0.0",port=5001)
|
||||
app.run(use_reloader=False, host="0.0.0.0", port=5001)
|
||||
|
|
Loading…
Reference in New Issue