1
0
Fork 0
satnogsmap/satnogs.py

226 lines
9.2 KiB
Python

from datetime import datetime , timedelta
import requests
from tqdm import tqdm
from flask import Flask , render_template,redirect,url_for
import json
from collections import defaultdict
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 satellite_tle import fetch_tles
from skyfield.api import EarthSatellite,utc,load
scheduler = BackgroundScheduler()
app = Flask(__name__)
ts = load.timescale()
broken = defaultdict(set)
Sats = defaultdict(list)
Passes = defaultdict(list)
Stations = []
TLEs = defaultdict(list)
Transmitters = defaultdict(dict)
CZML = []
def getFuture():
print "Getting future Passes"
global Sats
global TLEs
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')
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 = start.replace(tzinfo=utc)
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"]]
except Exception as 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)
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])]
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)
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]]
@scheduler.scheduled_job('interval',hours=1)
def updatePasses():
getFuture()
@scheduler.scheduled_job('interval',hours=1)
def updateStations():
global Stations
print "Updating Stations"
Stations = GetGroundStations()
@scheduler.scheduled_job('interval',minutes=30)
def updateCZML():
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["clock"]["step"] = "SYSTEM_CLOCK_MULTIPLER"
CZML.append(doc)
StationList = {}
for x in tqdm(Stations):
color = [0,230,64,255]
if x["status"] == "Testing":
color = [248,148,6,255]
if x["status"] == "Offline":
color = [255,0,0,50]
station = {}
station["id"] = str(x["id"])
station["name"] = x["name"]
station["point"] = {}
station["show"] = True
station["point"]["color"] = {}
station["point"]["color"]["rgba"] = color
station["point"]["outlineColor"] = {}
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: "+str(x["observations"])+"</b><br><b>Status: "+x["status"]+"</b><br><b>QTH: "+x["qthlocator"]+"</b><br></b>Description: </b>"+x["description"]
CZML.append(station)
#CZML.append({"point": {"color": {"rgba": [255, 0, 0, 255]}, "pixelSize": 7.0}, "position": {"interpolationDegree": 5, "epoch": "2019-02-20T18:15:31Z", "cartographicRadians": [0, 0.3926577985153905, 1.1691578160879883, 656892.3748016874, 60, 0.3350659338545192, 1.1089605458602834, 655874.386965892, 120, 0.2890197452488876, 1.047837527650023, 654785.5379851013, 180, 0.2509867794693532, 0.9860631482739753, 653641.7898772621, 240, 0.21870672074331488, 0.9238091562480084, 652460.3348020877, 300, 0.19067493892518161, 0.8611882322528641, 651259.3247753858, 360, 0.16585423673939337, 0.7982775055158141, 650057.5822615812, 420, 0.14350728383857447, 0.7351319146596802, 648874.2959984386, 480, 0.12309537649675795, 0.6717921438438812, 647728.7068061114, 540, 0.10421508370803956, 0.60828951924056, 646639.7884730175], "referenceFrame": "INERTIAL", "interpolationAlgorithm": "LAGRANGE"}, "show": True, "id": "485092", "name": "KKS-1 (KISEKI)"})
#return
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["position"] = {}
sat["position"]["cartographicDegrees"]=[]
temp = y["start"]
satObj = EarthSatellite(TLEs[x][1],TLEs[x][2],TLEs[x][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"]["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["label"] = {"show":{"interval":(y["start"].isoformat()+"Z").replace("+00:00","")+"/"+((y["end"]+timedelta(minutes=1)).isoformat()+"Z").replace("+00:00",""),"boolean":True},"horizontalOrigin":"LEFT","font":"12px sans-serif","text":TLEs[x][0]}
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":3,"material":{"solidColor":{"color":{"rgba":[255,0,0,255]}}},"followSurface":False,"positions":{"references":[str(y["id"])+"#position",str(y["station"])+"#position"]}}
CZML.append(sat)
@app.route("/")
def index():
return render_template("index.html")
@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")
def api_broken():
output = defaultdict(list)
for x in broken.keys():
output[x]=list(broken[x])
return json.dumps(output)
#updatePasses()
updateStations()
updateTransmitters()
getFuture()
updateCZML()
#updateTLE()
#updatePasses()
scheduler.start()
app.run(use_reloader=False,host = "0.0.0.0",port=5001)