From f89c3fa2bfe7d369866a1939a7c201200016cb38 Mon Sep 17 00:00:00 2001 From: wgaylord Date: Tue, 18 Dec 2018 12:27:19 -0600 Subject: [PATCH] Inital recode --- requirments.txt | 3 + satnogs.py | 67 +++-------------- satnogs_api_client.py | 171 ++++++++++++++++++------------------------ 3 files changed, 83 insertions(+), 158 deletions(-) create mode 100644 requirments.txt diff --git a/requirments.txt b/requirments.txt new file mode 100644 index 0000000..08420a8 --- /dev/null +++ b/requirments.txt @@ -0,0 +1,3 @@ +requests==2.21.0 +flask==1.0.2 +apscheduler==3.5.3 \ No newline at end of file diff --git a/satnogs.py b/satnogs.py index e60494d..9c3768e 100644 --- a/satnogs.py +++ b/satnogs.py @@ -3,15 +3,12 @@ import requests from flask import Flask , render_template,redirect,url_for import json from apscheduler.schedulers.background import BackgroundScheduler -import ephem from satnogs_api_client import fetch_satellites, DB_BASE_URL,fetch_tle_of_observation from satellite_tle import fetch_tles scheduler = BackgroundScheduler() 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 = [] Stations = [] @@ -25,10 +22,7 @@ class Pass: satellite = None transmitter = None norad = 0 - - def __repr__(self): - return "\n: {}\n: {}\n: {}\n: {}\n {}\n: {}".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(): @@ -68,10 +62,9 @@ def getActive(): temp.ground_station = x["ground_station"] temp.norad = str(x["norad_cat_id"]) 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: temp.satellite = {"name":""} - #temp.transmitter = requests.get("https://db.satnogs.org/api/transmitters/"+x["transmitter"]).json() Passes.append(temp) @@ -121,7 +114,7 @@ def updateStations(): def updateTLE(): print "Updating TLE" 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') # Remove satellites with temporary 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("/") def map_view(): - stations = [] - 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(""+str(x.id)+"") - return json.dumps(obs) + return render_template("map.html") @app.route('/api/activestations') def api_active_stations(): - 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) - - + return json.dumps(Stations) @app.route('/api/occuringobservations') def api_occuring_observations(): @@ -181,32 +152,12 @@ def api_occuring_sats(): if x.satellite['norad_cat_id'] not in TLEs.keys(): q = fetch_tle_of_observation(x.id) 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]) - now = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') - 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) + obs[x.id] = {"ground_station":x.ground_station,"start":x.start.isoformat(),"end":x.end.isoformat()} + return json.dumps([obs,TLEs]) -@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/') -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() updateStations() diff --git a/satnogs_api_client.py b/satnogs_api_client.py index 82b5e9e..59518af 100644 --- a/satnogs_api_client.py +++ b/satnogs_api_client.py @@ -1,6 +1,8 @@ -import requests +from __future__ import print_function import re +import requests + NETWORK_DEV_BASE_URL = 'https://network-dev.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' +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): - # 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 - 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, norad_id, start.isoformat(), end.isoformat()) - # print(url) - r = requests.get(url=url) + observations = get_paginated_endpoint(url) - if r.status_code != requests.codes.ok: - print("No observations found for {}, start: {}, end: {}.".format(norad_id, start_time, end_time)) - raise - - 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)) + # Current prod is broken and can't filter on NORAD ID correctly, + # use client-side filtering instead + observations = list(observation for observation in observations + if observation['norad_cat_id'] == norad_id) return observations def fetch_observation_data(observation_ids, prod=True): # Get station location from the observation via the observation_id - + observations = [] for observation_id in observation_ids: - r = requests.get(url='{}/api/observations/{}/'.format(NETWORK_BASE_URL if prod else NETWORK_DEV_BASE_URL, - observation_id)) - if r.status_code != requests.codes.ok: - print("Observation {} not found in network.".format(observation_id)) - continue + base_url = (NETWORK_BASE_URL if prod else NETWORK_DEV_BASE_URL) + r = requests.get(url='{}/api/observations/{}/'.format(base_url, + observation_id)) + r.raise_for_status() observations.append(r.json()) return observations + def fetch_ground_station_data(ground_station_ids, prod=True): # Fetch ground station metadata from network ground_stations = [] 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, - ground_station_id)) - if r.status_code != requests.codes.ok: - print("Ground Station {} not found in db.".format(ground_station_id)) - raise - data = r.json() + # Skip frames from deleted groundstations, indidcated as ID 'None' + if str(ground_station_id) == 'None': + print("Skipping groundstation 'None'.") + continue + + 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()) return ground_stations + def fetch_satellite_data(norad_cat_id): # Fetch satellite metadata from network - r = requests.get(url='{}/api/satellites/{}/'.format(DB_BASE_URL, norad_cat_id)) - if r.status_code != requests.codes.ok: - print("ERROR: Satellite {} not found in network.".format(norad_cat_id)) + r = requests.get(url='{}/api/satellites/{}/'.format(DB_BASE_URL, + norad_cat_id)) + r.raise_for_status() return r.json() + 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) r = requests.get(url=url) 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] -def fetch_telemetry(norad_id, max_frames, url): +def fetch_telemetry(norad_id, url): # http://db-dev.satnogs.org/api/telemetry/?satellite=43595 query_str = '{}/api/telemetry/?satellite={}' + url = query_str.format(url, norad_id) - try: - data = fetch_multi_page_api_endpoint(url, max_entries=max_frames) - except HTTPError: - print("No telemetry found for {}.".format(norad_id)) - raise + telemetry = get_paginated_endpoint(url) - 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/' url = query_str.format(url) - try: - data = fetch_multi_page_api_endpoint(url, max_entries=max_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 + satellites = get_paginated_endpoint(url, max_entries=max_entries) + return satellites def post_telemetry(norad_id, - source, + source, # Receiver Callsign lon, lat, timestamp,