diff --git a/app/models.py b/app/models.py index 369fd15..c41e4b7 100644 --- a/app/models.py +++ b/app/models.py @@ -34,3 +34,25 @@ class Satellite(db.Model): def __repr__(self): return ''.format(self.satellite_name) +class SatelliteTransmitter(db.Model): + __tablename__ = 'satellite_transmitter' + + transmitter_id = db.Column(db.Integer, primary_key=True) + satellite_norad_id = db.Column(db.BigInteger, nullable=False) + transmitter_description = db.Column(db.Text) + transmitter_alive = db.Column(db.Boolean) + transmitter_type = db.Column(db.Text) + transmitter_uplink_low = db.Column(db.BigInteger) + transmitter_uplink_high = db.Column(db.BigInteger) + transmitter_uplink_mode = db.Column(db.Text) + transmitter_downlink_low = db.Column(db.BigInteger) + transmitter_downlink_high = db.Column(db.BigInteger) + transmitter_downlink_mode = db.Column(db.Text) + transmitter_invert = db.Column(db.Boolean) + transmitter_baud = db.Column(db.BigInteger) + transmitter_citation = db.Column(db.Text) + transmitter_coordination = db.Column(db.Text) + transmitter_coordination_url = db.Column(db.Text) + + + diff --git a/app/routes.py b/app/routes.py index 8fc7116..a35fba8 100644 --- a/app/routes.py +++ b/app/routes.py @@ -6,6 +6,9 @@ @app.route('/index') def index(): - return render_template('index.html', title='Home') + # get available collections + collections = SatelliteCollection.query.all() + + return render_template('index.html', title='Home', collections=collections) diff --git a/app/routes_jsapi.py b/app/routes_jsapi.py index 77e7f3f..58ce8fe 100644 --- a/app/routes_jsapi.py +++ b/app/routes_jsapi.py @@ -1,6 +1,6 @@ from flask import jsonify from app import app, db -from app.models import Satellite, SatelliteCollection, SatelliteCollectionAssignmment +from app.models import Satellite, SatelliteCollection, SatelliteCollectionAssignmment,SatelliteTransmitter from app.forms import CreateCollectionForm, AddSatelliteCollectionForm from sqlalchemy import and_ from app import config @@ -36,6 +36,28 @@ def satellite_data(collection_id): satObject['title'] = satellite.satellite_tle0 satObject['tle1'] = satellite.satellite_tle1 satObject['tle2'] = satellite.satellite_tle2 + satObject['transmitters'] = [] + + # do we have any transmitters for this satellite ? + transmitterData = SatelliteTransmitter.query.filter_by(satellite_norad_id=satellite.satellite_norad_id).all() + + for item in transmitterData: + satObject['transmitters'].append({ + 'description' : item.transmitter_description, + 'type' : item.transmitter_type, + 'uplink_low' : item.transmitter_uplink_low, + 'uplink_high' : item.transmitter_uplink_high, + 'uplink_mode' : item.transmitter_uplink_mode, + 'downlink_low' : item.transmitter_downlink_low, + 'downlink_high' : item.transmitter_downlink_high, + 'downlink_mode' : item.transmitter_downlink_mode, + 'invert' : item.transmitter_invert, + 'baud' : item.transmitter_baud, + 'citation' : item.transmitter_citation, + 'coordination' : item.transmitter_coordination, + 'coordination_url' : item.transmitter_coordination_url, + }) + data['satellites'].append(satObject) data['success'] = True @@ -52,6 +74,14 @@ def tle_api(norad_id): return jsonify([{}]) - +''' +@app.route('/browser/transmitter_api/') +def transmitter_api(norad_id): + req = requests.get("https://db.satnogs.org/api/transmitters/?alive=true&format=json&satellite__norad_cat_id=" + norad_id) + if req.status_code == 200: + data = req.json() + return jsonify(data) + return jsonify([{}]) +''' diff --git a/app/routes_satellites.py b/app/routes_satellites.py index 0648f73..87d7a00 100644 --- a/app/routes_satellites.py +++ b/app/routes_satellites.py @@ -7,8 +7,6 @@ from app import config from app.satellite_functions import calc_future_passes, get_satellite_record - - @app.route('/view_satellites') def view_satellites(): satellites = Satellite.query.all() diff --git a/app/static/css/custom.css b/app/static/css/custom.css index d985bf8..8e6249f 100644 --- a/app/static/css/custom.css +++ b/app/static/css/custom.css @@ -21,4 +21,5 @@ .small { font: 10px sans-serif; - } \ No newline at end of file + } + diff --git a/app/static/js/radio.js b/app/static/js/radio.js new file mode 100644 index 0000000..1ef4258 --- /dev/null +++ b/app/static/js/radio.js @@ -0,0 +1,50 @@ +var radioConnected = false; + +function connectRadio() +{ + if ( radioConnected == true ) + { + return; + } + + try { + + radio_header.innerHTML = "Radio Control Connecting"; + + connectWS("ws://localhost:1880/ws/radio", radioConnectionOpen, radioConnectionClosed, radioConnectionMessageReceived); + } + catch (err) { + console.log("Couldn't connect to radio websocket") + } + +} + +function radioConnectionOpen(event) { + console.log("Radio Connected"); + + radio_header.innerHTML = "Radio Control Connected"; + + radioConnected = true; + $("#radioEnabled").attr("disabled", false); +} + +function radioConnectionClosed(event) { + radio_header.innerHTML = "Radio Control Disconnected"; + + $("#radioEnabled").attr("disabled", true); + + console.log("Radio Disconnected"); + radioConnected = false; +} + +function radioConnectionMessageReceived(event) { + console.log(JSON.parse(event.data)) + + radioData = JSON.parse(event.data) + /* + azActual = rotatorData.az; + elActual = rotatorData.el; + rot_actual_el.innerHTML = rotatorData.el; + rot_actual_az.innerHTML = rotatorData.az; + */ +} \ No newline at end of file diff --git a/app/static/js/satellite_tracker.js b/app/static/js/satellite_tracker.js index 6520f62..6c71797 100644 --- a/app/static/js/satellite_tracker.js +++ b/app/static/js/satellite_tracker.js @@ -18,6 +18,7 @@ var once = 0; var bounds = L.latLngBounds(L.latLng(-90, -180), L.latLng(90, 180)); var mymap = L.map('map', { center: bounds.getCenter(), maxBounds: bounds, maxBoundsViscosity: 1.0, minZoom: 2, }).setView([0, 0], 2); var layerGroup = L.layerGroup().addTo(mymap); +var satGroup = L.layerGroup().addTo(mymap); var observer = L.marker([0, 0], { icon: qth, title: 'Observer' }).addTo(mymap); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { @@ -223,38 +224,46 @@ function updateSelectedSatellite() { if (selectedSatellite == null) return + + layerGroup.clearLayers(); satelliteData = selectedSatellite; var satdata = calcSatellitePositions(satelliteData.satrec, new Date()) - var positionGd = satdata[0] var lookAngles = satdata[1] - var doppler = satdata[2] + var dopplerFactor = satdata[2] - dopp = dopplerDiff(doppler, 100) // satellite properties prop_title.innerHTML = satelliteData.title + prop_tracker_title.innerHTML = prop_title.innerHTML + prop_az.innerHTML = satellite.radiansToDegrees(lookAngles.azimuth).toFixed(2) prop_el.innerHTML = satellite.radiansToDegrees(lookAngles.elevation).toFixed(2) + prop_tracker_az.innerHTML = prop_az.innerHTML + prop_tracker_el.innerHTML = prop_el.innerHTML + + if (satelliteData.prevRange == null) { prop_range.innerHTML = lookAngles.rangeSat.toFixed(0) + " (?)" } else { if (satelliteData.prevRange > lookAngles.rangeSat) { prop_range.innerHTML = lookAngles.rangeSat.toFixed(0) + " (-)" - prop_dopup.innerHTML = dop + "Hz" + // } else { prop_range.innerHTML = lookAngles.rangeSat.toFixed(0) + " (+)" - prop_dopup.innerHTML = (-1 * dop) + "Hz" + //prop_tracker_dopup.innerHTML = (-1 * dop) + "Hz" } } + prop_tracker_range.innerHTML = prop_range.innerHTML + selectedSatellite.prevRange = lookAngles.rangeSat // draw footprint @@ -277,6 +286,7 @@ function updateSelectedSatellite() { prop_countdown.innerHTML = 'Now'; } + // draw next pass var polyline = L.polyline(satelliteData.next_pass_data.path).arrowheads({ size: '20px', frequency: 'endonly' }); polyline.addTo(layerGroup); @@ -319,6 +329,8 @@ function updateSelectedSatellite() { prop_countdown.innerHTML = "N/A" } + prop_tracker_countdown.innerHTML = prop_countdown.innerHTML + // draw polar graph var tleLine1 = satelliteData.tle1 var tleLine2 = satelliteData.tle2 @@ -348,32 +360,110 @@ function updateSelectedSatellite() { rot_requested_az.innerHTML = az; rot_requested_el.innerHTML = el; - if (rotatorConnected) - { - var rotatorData = { 'az' : satellite.radiansToDegrees(lookAngles.azimuth), 'el' : satellite.radiansToDegrees(lookAngles.elevation)} + if (rotatorConnected) { + var rotatorData = { 'az': satellite.radiansToDegrees(lookAngles.azimuth), 'el': satellite.radiansToDegrees(lookAngles.elevation) } sendWS(rotatorData); } } - else - { + else { rot_requested_az.innerHTML = satelliteData.next_pass_data.start_az.toFixed(2) rot_requested_el.innerHTML = 0; - if (rotatorConnected) - { - var rotatorData = { 'az' : satelliteData.next_pass_data.start_az, 'el' : 0} + if (rotatorConnected) { + var rotatorData = { 'az': satelliteData.next_pass_data.start_az, 'el': 0 } sendWS(rotatorData); } } } - + // update radio data + var e = document.getElementById("sel_transmitter"); + + if (e != null) { + var value = e.options[e.selectedIndex].value; + var text = e.options[e.selectedIndex].text; + + transmitter = satelliteData.transmitters[value] + + dop = dopplerDiff(dopplerFactor, 100) + + + if (transmitter.downlink_low != null) { + downlink = transmitter.downlink_low.toString() + downlink = downlink.padStart(9, '0') + downlink = downlink.substring(0, 3) + "." + downlink.substring(3, 6) + "." + downlink.substring(6) + " Hz" + downlink_freq_sat.innerHTML = downlink + downlink_mode.innerHTML = transmitter.downlink_mode + + dop = dopplerDiff(dopplerFactor, 100) + //prop_tracker_dopup.innerHTML = dop + "Hz" + + doppler_amount = (dop / 100) * (transmitter.downlink_low / 1000000) + + if (satelliteData.prevRange > lookAngles.rangeSat) + {} + else + { + doppler_amount = doppler_amount * -1; + } + + downlink_doppler.innerHTML = Math.round(doppler_amount) + " Hz" + + downlink_doppler_amount = (transmitter.downlink_low + Math.round(doppler_amount)).toString() + downlink_doppler_amount = downlink_doppler_amount.padStart(9, '0') + downlink_doppler_amount = downlink_doppler_amount.substring(0, 3) + "." + downlink_doppler_amount.substring(3, 6) + "." + downlink_doppler_amount.substring(6) + " Hz" + downlink_freq_radio.innerHTML = downlink_doppler_amount + } + else + { + downlink_mode.innerHTML = "N/A" + downlink_freq_sat.innerHTML = "N/A" + downlink_freq_radio.innerHTML = "N/A" + downlink_doppler.innerHTML = "N/A" + } + + if (transmitter.uplink_low != null) { + uplink = transmitter.uplink_low.toString() + uplink = uplink.padStart(9, '0') + uplink = uplink.substring(0, 3) + "." + uplink.substring(3, 6) + "." + uplink.substring(6) + " Hz" + uplink_freq_sat.innerHTML = uplink + uplink_mode.innerHTML = transmitter.uplink_mode + + doppler_amount = (dop / 100) * (transmitter.uplink_low / 1000000) + + if (satelliteData.prevRange > lookAngles.rangeSat) + { + doppler_amount = doppler_amount * -1; + } + else + { + } + + uplink_doppler.innerHTML = Math.round(doppler_amount) + " Hz" + + uplink_doppler_amount = (transmitter.uplink_low + Math.round(doppler_amount)).toString() + uplink_doppler_amount = uplink_doppler_amount.padStart(9, '0') + uplink_doppler_amount = uplink_doppler_amount.substring(0, 3) + "." + uplink_doppler_amount.substring(3, 6) + "." + uplink_doppler_amount.substring(6) + " Hz" + uplink_freq_radio.innerHTML = uplink_doppler_amount + } + else + { + uplink_mode.innerHTML = "N/A" + uplink_freq_sat.innerHTML = "N/A" + uplink_freq_radio.innerHTML = "N/A" + uplink_doppler.innerHTML = "N/A" + + } + + } + + // update polar graph var polarPlotSVG = calcPolarPlotSVG(timeframe, groundstation, tleLine1, - tleLine2, isGeostationary(satelliteData.satrec), { 'az' : azActual, 'el' : elActual }); + tleLine2, isGeostationary(satelliteData.satrec), { 'az': azActual, 'el': elActual }); var based = ' \ \ @@ -396,6 +486,9 @@ function updateSelectedSatellite() { $('svg#polar').html(based); $('svg#polar').append(polarPlotSVG); + //$('svg#polar_tracker').html(based); + //$('svg#polar_tracker').append(polarPlotSVG); + polar_tracker.innerHTML = polar.innerHTML } @@ -407,12 +500,26 @@ function selectSatellite(marker) { marker.setIcon(inRangeIcon) } - if (satelliteData == null) { console.log("error: can't find satellite object") } else { selectedSatellite = satelliteData + + // update transmitters list + if (selectedSatellite.transmitters.length > 0) { + // build up a selection + transmitter_data = ""; + prop_tracker_transmitters.innerHTML = transmitter_data; + } + else { + prop_tracker_transmitters.innerHTML = "None Specified"; + } + updateSelectedSatellite(); } } @@ -427,7 +534,12 @@ function isGeostationary(satrec) { function initMap(jsondata) { console.log(jsondata); + + // clear data + satellites = [] layerGroup.clearLayers(); + satGroup.clearLayers(); + table.innerHTML = "" observer_lat = jsondata.observer.coordinates[0]; observer_lon = jsondata.observer.coordinates[1]; @@ -465,16 +577,16 @@ function initMap(jsondata) { }); - var addedMarker = marker.addTo(mymap) + var addedMarker = marker.addTo(satGroup) - satObject = { 'title': element.title, 'marker': addedMarker, 'tle1': element.tle1, 'tle2': element.tle2 } + satObject = { 'dbid': element.dbid, 'title': element.title, 'marker': addedMarker, 'tle1': element.tle1, 'tle2': element.tle2 } var satrec = satellite.twoline2satrec(element.tle1, element.tle2); - console.log(element.title) - console.log("Geostationary Check"); - console.log(satrec.no) - console.log(isGeostationary(satrec)); + //console.log(element.title) + //console.log("Geostationary Check"); + //console.log(satrec.no) + //console.log(isGeostationary(satrec)); var satdata = calcSatellitePositions(satrec, new Date()) @@ -488,12 +600,11 @@ function initMap(jsondata) { return; } - satObject.marker.setLatLng([lat, lon]).update() satObject.satrec = satrec satObject.next_pass_data = calcNextPass(satrec) - + satObject.transmitters = element.transmitters var newRow = table.insertRow(); var satname = newRow.insertCell(); var sataz = newRow.insertCell(); @@ -504,6 +615,7 @@ function initMap(jsondata) { var nextpassmax = newRow.insertCell(); var nextpasslos = newRow.insertCell(); var maxel = newRow.insertCell(); + var info = newRow.insertCell(); satname.innerHTML = element.title sataz.innerHTML = satellite.radiansToDegrees(lookAngles.azimuth).toFixed(2) @@ -543,9 +655,12 @@ function initMap(jsondata) { maxel.innerHTML = satellite.radiansToDegrees(lookAngles.elevation).toFixed(2) } + info.innerHTML = "" satObject.row = newRow satellites.push(satObject) + + if (first == 0) { selectSatellite(satObject.marker); first = 1; @@ -619,7 +734,7 @@ function updateLoop() { else { table.rows[x].cells[4].innerHTML = 'Now'; } - + table.rows[x].cells[5].innerHTML = satrise.utc().format('YYYY/MM/DD HH:mm') table.rows[x].cells[6].innerHTML = satmax.utc().format('YYYY/MM/DD HH:mm') table.rows[x].cells[7].innerHTML = satset.utc().format('YYYY/MM/DD HH:mm') @@ -647,8 +762,15 @@ function updateLoop() { } function getSatelliteList() { + var e = document.getElementById("collections"); + var value = e.options[e.selectedIndex].value; + var text = e.options[e.selectedIndex].text; + + console.log(value) + console.log(text) + $.ajax({ - url: "/browser/satellite_data/1", + url: "/browser/satellite_data/" + value, type: 'GET', dataType: 'json', success: function (res) { @@ -674,9 +796,15 @@ function updateSatelliteList() { } +var tabEl = document.querySelector('button[data-bs-toggle="tab"]') +tabEl.addEventListener('shown.bs.tab', function (event) { + mymap.invalidateSize(); +}) + $(document).ready(function () { getSatelliteList(); connectRotator(); + connectRadio(); }); diff --git a/app/templates/index.html b/app/templates/index.html index 2253923..94449fc 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -8,128 +8,289 @@ {% block content %} -
-
-
-
-
-
-
+ -
-
+
+
-
-
- Future Passes -
-
- - - - - - - - - - - - - - -
Satellite NameAzimuthElevationRangeCountdownAOSMaxLOSMax El
-
-
+