Inital recode
parent
bf3b902e7a
commit
f89c3fa2bf
|
@ -0,0 +1,3 @@
|
||||||
|
requests==2.21.0
|
||||||
|
flask==1.0.2
|
||||||
|
apscheduler==3.5.3
|
67
satnogs.py
67
satnogs.py
|
@ -3,15 +3,12 @@ import requests
|
||||||
from flask import Flask , render_template,redirect,url_for
|
from flask import Flask , render_template,redirect,url_for
|
||||||
import json
|
import json
|
||||||
from apscheduler.schedulers.background import BackgroundScheduler
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
import ephem
|
|
||||||
from satnogs_api_client import fetch_satellites, DB_BASE_URL,fetch_tle_of_observation
|
from satnogs_api_client import fetch_satellites, DB_BASE_URL,fetch_tle_of_observation
|
||||||
from satellite_tle import fetch_tles
|
from satellite_tle import fetch_tles
|
||||||
|
|
||||||
scheduler = BackgroundScheduler()
|
scheduler = BackgroundScheduler()
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
modes = {1: 'FM', 2: 'AFSK1k2', 5: 'SSTV', 6: 'CW', 7: 'FMN', 9: 'USB', 15: 'GFSK4k8', 17: 'AHRPT', 18: 'AFSK9k6', 19: 'AM', 20: 'LSB', 21: 'FSK1k2', 22: 'FSK9k6', 26: 'GFSK1k2', 27: 'GFSK2k4', 28: 'GFSK9k6', 29: 'GFSK19k2', 30: 'MSK1k2', 31: 'MSK2k4', 32: 'MSK4k8', 33: 'MSK9k6', 34: 'MSK19k2', 35: 'MSK38k4', 36: 'GMSK1k2', 37: 'GMSK2k4', 38: 'GMSK4k8', 39: 'GMSK9k6', 40: 'PSK31', 41: 'PSK63', 42: 'QPSK31', 43: 'QPSK63', 44: 'APT', 45: 'HRPT', 46: 'FSK4k8', 47: 'BPSK1k2', 48: 'GMSK19k2', 49: 'AFSK', 50: 'BPSK', 51: 'FSK19k2', 52: 'BPSK115k2', 53: 'LRPT', 54: 'BPSK9k6', 55: 'FFSK1k2', 56: 'FSK2k4', 57: 'DSTAR', 58: 'DUV', 59: 'CERTO', 60: 'BPSK400', 61: 'OFDM', 62: 'QPSK38k4'}
|
|
||||||
|
|
||||||
|
|
||||||
Passes = []
|
Passes = []
|
||||||
Stations = []
|
Stations = []
|
||||||
|
@ -25,10 +22,7 @@ class Pass:
|
||||||
satellite = None
|
satellite = None
|
||||||
transmitter = None
|
transmitter = None
|
||||||
norad = 0
|
norad = 0
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "\n<ID>: {}\n<Start>: {}\n<End>: {}\n<Ground Station>: {}\n<Satellite> {}\n<Transmitter>: {}".format(self.id,self.start.strftime('%Y-%m-%dT%H:%M:%S%z'),self.end.strftime('%Y-%m-%dT%H:%M:%S%z'),self.ground_station,json.dumps(self.satellite,indent = 1),json.dumps(self.transmitter,indent=1))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def getActive():
|
def getActive():
|
||||||
|
@ -68,10 +62,9 @@ def getActive():
|
||||||
temp.ground_station = x["ground_station"]
|
temp.ground_station = x["ground_station"]
|
||||||
temp.norad = str(x["norad_cat_id"])
|
temp.norad = str(x["norad_cat_id"])
|
||||||
try:
|
try:
|
||||||
temp.satellite = requests.get("https://db.satnogs.org/api/satellites/"+str(x["norad_cat_id"])) .json()
|
temp.satellite = requests.get("https://db.satnogs.org/api/satellites/"+str(x["norad_cat_id"])).json()
|
||||||
except:
|
except:
|
||||||
temp.satellite = {"name":""}
|
temp.satellite = {"name":""}
|
||||||
#temp.transmitter = requests.get("https://db.satnogs.org/api/transmitters/"+x["transmitter"]).json()
|
|
||||||
Passes.append(temp)
|
Passes.append(temp)
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,7 +114,7 @@ def updateStations():
|
||||||
def updateTLE():
|
def updateTLE():
|
||||||
print "Updating TLE"
|
print "Updating TLE"
|
||||||
global TlEs
|
global TlEs
|
||||||
sats = fetch_satellites(url=DB_BASE_URL, max_satellites=None)
|
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')
|
satnogs_db_norad_ids = set(sat['norad_cat_id'] for sat in sats if sat['status'] != 're-entered')
|
||||||
# Remove satellites with temporary norad ids
|
# Remove satellites with temporary norad ids
|
||||||
temporary_norad_ids = set(filter(lambda norad_id: norad_id >= 99900, satnogs_db_norad_ids))
|
temporary_norad_ids = set(filter(lambda norad_id: norad_id >= 99900, satnogs_db_norad_ids))
|
||||||
|
@ -139,33 +132,11 @@ def updateTLE():
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def map_view():
|
def map_view():
|
||||||
stations = []
|
return render_template("map.html")
|
||||||
for x in Stations:
|
|
||||||
stations.append({'id':x['id'],'name':x['name'],'lat_lng':[x["lat"],x['lng']]})
|
|
||||||
return render_template("map.html",stations = stations)
|
|
||||||
|
|
||||||
@app.route('/occuringobservations')
|
|
||||||
def occuring_observations():
|
|
||||||
obs = []
|
|
||||||
for x in Passes:
|
|
||||||
obs.append("<a href='https://network.satnogs.org/observations/"+str(x.id)+"'>"+str(x.id)+"</a>")
|
|
||||||
return json.dumps(obs)
|
|
||||||
|
|
||||||
@app.route('/api/activestations')
|
@app.route('/api/activestations')
|
||||||
def api_active_stations():
|
def api_active_stations():
|
||||||
stations = []
|
return json.dumps(Stations)
|
||||||
for x in Passes:
|
|
||||||
stations.append(x.ground_station)
|
|
||||||
return json.dumps(stations)
|
|
||||||
|
|
||||||
@app.route('/api/onlinestations')
|
|
||||||
def api_online_stations():
|
|
||||||
stations = []
|
|
||||||
for x in Stations:
|
|
||||||
stations.append(x["id"])
|
|
||||||
return json.dumps(stations)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/occuringobservations')
|
@app.route('/api/occuringobservations')
|
||||||
def api_occuring_observations():
|
def api_occuring_observations():
|
||||||
|
@ -181,32 +152,12 @@ def api_occuring_sats():
|
||||||
if x.satellite['norad_cat_id'] not in TLEs.keys():
|
if x.satellite['norad_cat_id'] not in TLEs.keys():
|
||||||
q = fetch_tle_of_observation(x.id)
|
q = fetch_tle_of_observation(x.id)
|
||||||
TLEs[ x.norad ] = [str(x.satellite["name"]),str(q[0]),str(q[1])]
|
TLEs[ x.norad ] = [str(x.satellite["name"]),str(q[0]),str(q[1])]
|
||||||
satellite = ephem.readtle(TLEs[x.norad][0],TLEs[x.norad][1],TLEs[x.norad][2])
|
obs[x.id] = {"ground_station":x.ground_station,"start":x.start.isoformat(),"end":x.end.isoformat()}
|
||||||
now = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
|
return json.dumps([obs,TLEs])
|
||||||
satellite.compute(now)
|
|
||||||
lat = satellite.sublat*57.295779514
|
|
||||||
long = satellite.sublong*57.295779514
|
|
||||||
if x.satellite['norad_cat_id'] == 25544:
|
|
||||||
obs[x.norad] = {"name":satellite.name,"lat_lng":[lat,long],"eclipsed":satellite.eclipsed,"image":"/static/ISS"}
|
|
||||||
else:
|
|
||||||
obs[x.norad] = {"name":satellite.name,"lat_lng":[lat,long],"eclipsed":satellite.eclipsed,"image":None}
|
|
||||||
return json.dumps(obs)
|
|
||||||
|
|
||||||
@app.route('/api/satstationpairs')
|
|
||||||
def api_sat_station_pairs():
|
|
||||||
pairs = []
|
|
||||||
for x in Passes:
|
|
||||||
pairs.append([x.ground_station,x.norad])
|
|
||||||
return json.dumps(pairs)
|
|
||||||
|
|
||||||
@app.route('/api/getsatloc/<int:norad>')
|
|
||||||
def get_sat_loc(norad):
|
|
||||||
satellite = ephem.readtle(TLEs[norad][0],TLEs[norad][1],TLEs[norad][2])
|
|
||||||
now = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
|
|
||||||
satellite.compute(now)
|
|
||||||
lat = satellite.sublat*57.295779514
|
|
||||||
long = satellite.sublong*57.295779514
|
|
||||||
return json.dumps([lat,long,satellite.eclipsed])
|
|
||||||
|
|
||||||
updatePasses()
|
updatePasses()
|
||||||
updateStations()
|
updateStations()
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import requests
|
from __future__ import print_function
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
NETWORK_DEV_BASE_URL = 'https://network-dev.satnogs.org'
|
NETWORK_DEV_BASE_URL = 'https://network-dev.satnogs.org'
|
||||||
NETWORK_BASE_URL = 'https://network.satnogs.org'
|
NETWORK_BASE_URL = 'https://network.satnogs.org'
|
||||||
|
@ -8,92 +10,90 @@ DB_BASE_URL = 'https://db.satnogs.org'
|
||||||
DB_DEV_BASE_URL = 'https://db-dev.satnogs.org'
|
DB_DEV_BASE_URL = 'https://db-dev.satnogs.org'
|
||||||
|
|
||||||
|
|
||||||
|
def get_paginated_endpoint(url, max_entries=None):
|
||||||
|
r = requests.get(url=url)
|
||||||
|
r.raise_for_status()
|
||||||
|
|
||||||
|
data = r.json()
|
||||||
|
|
||||||
|
while 'next' in r.links and (not max_entries or len(data) < max_entries):
|
||||||
|
next_page_url = r.links['next']['url']
|
||||||
|
|
||||||
|
r = requests.get(url=next_page_url)
|
||||||
|
r.raise_for_status()
|
||||||
|
|
||||||
|
data.extend(r.json())
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
def fetch_observation_data_from_id(norad_id, start, end, prod=True):
|
def fetch_observation_data_from_id(norad_id, start, end, prod=True):
|
||||||
# Get all observations of the satellite with the given `norad_id` in the given timeframe
|
# Get all observations of the satellite
|
||||||
|
# with the given `norad_id` in the given timeframe
|
||||||
# https://network.satnogs.org/api/observations/?satellite__norad_cat_id=25544&start=2018-06-10T00:00&end=2018-06-15T00:00
|
# https://network.satnogs.org/api/observations/?satellite__norad_cat_id=25544&start=2018-06-10T00:00&end=2018-06-15T00:00
|
||||||
|
|
||||||
query_str = '{}/api/observations/?satellite__norad_cat_id={}&start={}&end={}'
|
query_str = '{}/api/observations/' \
|
||||||
|
'?satellite__norad_cat_id={}&start={}&end={}'
|
||||||
|
|
||||||
url = query_str.format(NETWORK_BASE_URL if prod else NETWORK_DEV_BASE_URL,
|
url = query_str.format(NETWORK_BASE_URL if prod else NETWORK_DEV_BASE_URL,
|
||||||
norad_id,
|
norad_id,
|
||||||
start.isoformat(),
|
start.isoformat(),
|
||||||
end.isoformat())
|
end.isoformat())
|
||||||
|
|
||||||
# print(url)
|
observations = get_paginated_endpoint(url)
|
||||||
r = requests.get(url=url)
|
|
||||||
|
|
||||||
if r.status_code != requests.codes.ok:
|
# Current prod is broken and can't filter on NORAD ID correctly,
|
||||||
print("No observations found for {}, start: {}, end: {}.".format(norad_id, start_time, end_time))
|
# use client-side filtering instead
|
||||||
raise
|
observations = list(observation for observation in observations
|
||||||
|
if observation['norad_cat_id'] == norad_id)
|
||||||
observations = r.json()
|
|
||||||
|
|
||||||
next_page_available = ('Link' in r.headers.keys())
|
|
||||||
|
|
||||||
if next_page_available:
|
|
||||||
parts = r.headers['Link'].split(',')
|
|
||||||
for part in parts:
|
|
||||||
if part[-5:-1] == 'next':
|
|
||||||
next_page_url = part[1:-13]
|
|
||||||
|
|
||||||
while next_page_available:
|
|
||||||
# print(next_page_url)
|
|
||||||
r = requests.get(url=next_page_url)
|
|
||||||
|
|
||||||
observations.extend(r.json())
|
|
||||||
|
|
||||||
next_page_available = False
|
|
||||||
|
|
||||||
if 'Link' in r.headers.keys():
|
|
||||||
parts = r.headers['Link'].split(',')
|
|
||||||
for part in parts:
|
|
||||||
if part[-5:-1] == 'next':
|
|
||||||
next_page_url = part[1:-13]
|
|
||||||
next_page_available = True
|
|
||||||
|
|
||||||
# Current prod is broken and can't filter on NORAD ID correctly, use client-side filtering instead
|
|
||||||
observations = list(filter(lambda o: o['norad_cat_id'] == norad_id, observations))
|
|
||||||
|
|
||||||
return observations
|
return observations
|
||||||
|
|
||||||
|
|
||||||
def fetch_observation_data(observation_ids, prod=True):
|
def fetch_observation_data(observation_ids, prod=True):
|
||||||
# Get station location from the observation via the observation_id
|
# Get station location from the observation via the observation_id
|
||||||
|
|
||||||
observations = []
|
observations = []
|
||||||
for observation_id in observation_ids:
|
for observation_id in observation_ids:
|
||||||
r = requests.get(url='{}/api/observations/{}/'.format(NETWORK_BASE_URL if prod else NETWORK_DEV_BASE_URL,
|
base_url = (NETWORK_BASE_URL if prod else NETWORK_DEV_BASE_URL)
|
||||||
observation_id))
|
r = requests.get(url='{}/api/observations/{}/'.format(base_url,
|
||||||
if r.status_code != requests.codes.ok:
|
observation_id))
|
||||||
print("Observation {} not found in network.".format(observation_id))
|
r.raise_for_status()
|
||||||
continue
|
|
||||||
observations.append(r.json())
|
observations.append(r.json())
|
||||||
|
|
||||||
return observations
|
return observations
|
||||||
|
|
||||||
|
|
||||||
def fetch_ground_station_data(ground_station_ids, prod=True):
|
def fetch_ground_station_data(ground_station_ids, prod=True):
|
||||||
# Fetch ground station metadata from network
|
# Fetch ground station metadata from network
|
||||||
ground_stations = []
|
ground_stations = []
|
||||||
for ground_station_id in ground_station_ids:
|
for ground_station_id in ground_station_ids:
|
||||||
r = requests.get(url='{}/api/stations/{}/'.format(NETWORK_BASE_URL if prod else NETWORK_DEV_BASE_URL,
|
# Skip frames from deleted groundstations, indidcated as ID 'None'
|
||||||
ground_station_id))
|
if str(ground_station_id) == 'None':
|
||||||
if r.status_code != requests.codes.ok:
|
print("Skipping groundstation 'None'.")
|
||||||
print("Ground Station {} not found in db.".format(ground_station_id))
|
continue
|
||||||
raise
|
|
||||||
data = r.json()
|
base_url = (NETWORK_BASE_URL if prod else NETWORK_DEV_BASE_URL)
|
||||||
|
r = requests.get(url='{}/api/stations/{}/'.format(base_url,
|
||||||
|
ground_station_id))
|
||||||
|
r.raise_for_status()
|
||||||
|
|
||||||
ground_stations.append(r.json())
|
ground_stations.append(r.json())
|
||||||
return ground_stations
|
return ground_stations
|
||||||
|
|
||||||
|
|
||||||
def fetch_satellite_data(norad_cat_id):
|
def fetch_satellite_data(norad_cat_id):
|
||||||
# Fetch satellite metadata from network
|
# Fetch satellite metadata from network
|
||||||
r = requests.get(url='{}/api/satellites/{}/'.format(DB_BASE_URL, norad_cat_id))
|
r = requests.get(url='{}/api/satellites/{}/'.format(DB_BASE_URL,
|
||||||
if r.status_code != requests.codes.ok:
|
norad_cat_id))
|
||||||
print("ERROR: Satellite {} not found in network.".format(norad_cat_id))
|
r.raise_for_status()
|
||||||
|
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
|
|
||||||
def fetch_tle_of_observation(observation_id, prod=True):
|
def fetch_tle_of_observation(observation_id, prod=True):
|
||||||
url = '{}/observations/{}/'.format(NETWORK_BASE_URL if prod else NETWORK_DEV_BASE_URL,
|
base_url = (NETWORK_BASE_URL if prod else NETWORK_DEV_BASE_URL)
|
||||||
|
url = '{}/observations/{}/'.format(base_url,
|
||||||
observation_id)
|
observation_id)
|
||||||
r = requests.get(url=url)
|
r = requests.get(url=url)
|
||||||
observation_page_html = r.text
|
observation_page_html = r.text
|
||||||
|
@ -107,68 +107,39 @@ def fetch_tle_of_observation(observation_id, prod=True):
|
||||||
return [obs_tle_2, obs_tle_3]
|
return [obs_tle_2, obs_tle_3]
|
||||||
|
|
||||||
|
|
||||||
def fetch_telemetry(norad_id, max_frames, url):
|
def fetch_telemetry(norad_id, url):
|
||||||
# http://db-dev.satnogs.org/api/telemetry/?satellite=43595
|
# http://db-dev.satnogs.org/api/telemetry/?satellite=43595
|
||||||
|
|
||||||
query_str = '{}/api/telemetry/?satellite={}'
|
query_str = '{}/api/telemetry/?satellite={}'
|
||||||
|
|
||||||
url = query_str.format(url, norad_id)
|
url = query_str.format(url, norad_id)
|
||||||
|
|
||||||
try:
|
telemetry = get_paginated_endpoint(url)
|
||||||
data = fetch_multi_page_api_endpoint(url, max_entries=max_frames)
|
|
||||||
except HTTPError:
|
|
||||||
print("No telemetry found for {}.".format(norad_id))
|
|
||||||
raise
|
|
||||||
|
|
||||||
return data
|
return telemetry
|
||||||
|
|
||||||
|
|
||||||
def fetch_satellites(max_satellites, url):
|
def fetch_transmitters(norad_id, url):
|
||||||
|
# http://db-dev.satnogs.org/api/transmitters/?satellite__norad_cat_id=25544
|
||||||
|
|
||||||
|
query_str = '{}/api/transmitters/?satellite__norad_cat_id={}'
|
||||||
|
|
||||||
|
url = query_str.format(url, norad_id)
|
||||||
|
|
||||||
|
transmitters = get_paginated_endpoint(url)
|
||||||
|
return transmitters
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_satellites(max_entries, url):
|
||||||
query_str = '{}/api/satellites/'
|
query_str = '{}/api/satellites/'
|
||||||
url = query_str.format(url)
|
url = query_str.format(url)
|
||||||
|
|
||||||
try:
|
satellites = get_paginated_endpoint(url, max_entries=max_entries)
|
||||||
data = fetch_multi_page_api_endpoint(url, max_entries=max_satellites)
|
return satellites
|
||||||
except HTTPError:
|
|
||||||
print("An HTTPError occured.")
|
|
||||||
raise
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
def fetch_multi_page_api_endpoint(url, max_entries):
|
|
||||||
# print(url)
|
|
||||||
r = requests.get(url=url)
|
|
||||||
r.raise_for_status()
|
|
||||||
|
|
||||||
data = r.json()
|
|
||||||
|
|
||||||
next_page_available = ('Link' in r.headers.keys())
|
|
||||||
|
|
||||||
if next_page_available and (not max_entries or len(data) < max_entries):
|
|
||||||
parts = r.headers['Link'].split(',')
|
|
||||||
for part in parts:
|
|
||||||
if part[-5:-1] == 'next':
|
|
||||||
next_page_url = part[1:-13]
|
|
||||||
|
|
||||||
while next_page_available and (not max_entries or len(data) < max_entries):
|
|
||||||
# print(next_page_url)
|
|
||||||
r = requests.get(url=next_page_url)
|
|
||||||
|
|
||||||
data.extend(r.json())
|
|
||||||
|
|
||||||
next_page_available = False
|
|
||||||
|
|
||||||
if 'Link' in r.headers.keys():
|
|
||||||
parts = r.headers['Link'].split(',')
|
|
||||||
for part in parts:
|
|
||||||
if part[-5:-1] == 'next':
|
|
||||||
next_page_url = part[1:-13]
|
|
||||||
next_page_available = True
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def post_telemetry(norad_id,
|
def post_telemetry(norad_id,
|
||||||
source,
|
source, # Receiver Callsign
|
||||||
lon,
|
lon,
|
||||||
lat,
|
lat,
|
||||||
timestamp,
|
timestamp,
|
||||||
|
|
Loading…
Reference in New Issue