diff --git a/app/routes_jsapi.py b/app/routes_jsapi.py index 2a0198b..77e7f3f 100644 --- a/app/routes_jsapi.py +++ b/app/routes_jsapi.py @@ -32,14 +32,10 @@ def satellite_data(collection_id): for sat in satCollection: satellite = sat.Satellite satObject = {} + satObject['dbid'] = satellite.satellite_id satObject['title'] = satellite.satellite_tle0 satObject['tle1'] = satellite.satellite_tle1 satObject['tle2'] = satellite.satellite_tle2 - - next_pass = get_next_pass(satellite.satellite_tle0, satellite.satellite_tle1, satellite.satellite_tle2, float(config.config_data['qth_latitude']), float(config.config_data['qth_longitude']), 0) - satObject['next_pass'] = next_pass - - data['satellites'].append(satObject) data['success'] = True diff --git a/app/static/js/polar_svg.js b/app/static/js/polar_svg.js index 183d673..1eb5d6d 100644 --- a/app/static/js/polar_svg.js +++ b/app/static/js/polar_svg.js @@ -1,5 +1,5 @@ -function calcPolarPlotSVG(timeframe, groundstation, tleLine1, tleLine2) { +function calcPolarPlotSVG(timeframe, groundstation, tleLine1, tleLine2, geo, rotatorValues) { 'use strict'; const pi = Math.PI; @@ -13,7 +13,7 @@ function calcPolarPlotSVG(timeframe, groundstation, tleLine1, tleLine2) { height: 0 }; - var polarGetXY = function(az, el) { + var polarGetXY = function (az, el) { var ret = new Object(); ret.x = (90 - el) * Math.sin(az * deg2rad); ret.y = (el - 90) * Math.cos(az * deg2rad); @@ -35,79 +35,113 @@ function calcPolarPlotSVG(timeframe, groundstation, tleLine1, tleLine2) { var positionAndVelocity = satellite.propagate(satrec, t.toDate()); var gmst = satellite.gstime(t.toDate()); - var positionEci = positionAndVelocity.position; - var positionEcf = satellite.eciToEcf(positionEci, gmst); + var positionEci = positionAndVelocity.position; + var positionEcf = satellite.eciToEcf(positionEci, gmst); - var lookAngles = satellite.ecfToLookAngles(observerGd, positionEcf); + var lookAngles = satellite.ecfToLookAngles(observerGd, positionEcf); - return {'azimuth': lookAngles.azimuth * rad2deg, - 'elevation': lookAngles.elevation * rad2deg}; + return { + 'azimuth': lookAngles.azimuth * rad2deg, + 'elevation': lookAngles.elevation * rad2deg + }; } + if (geo == false) { + // Draw the orbit pass on the polar az/el plot + var g = ''; - // Draw the orbit pass on the polar az/el plot - var g = ''; - - for (var t = timeframe.start; t < timeframe.end; t = t.add(20, 's')) { - var sky_position = polarGetAzEl(t); - var coord = polarGetXY(sky_position.azimuth, sky_position.elevation); - - if (g == '') { - g += 'M'; - } else { - g += ' L'; + for (var t = timeframe.start; t < timeframe.end; t = t.add(20, 's')) { + var sky_position = polarGetAzEl(t); + var coord = polarGetXY(sky_position.azimuth, sky_position.elevation); + + if (g == '') { + g += 'M'; + } else { + g += ' L'; + } + g += coord.x + ' ' + coord.y; } - g += coord.x + ' ' + coord.y; - } + + polarOrbit.setAttribute('d', g); + + // Draw observation start + var point_start = document.createElementNS(svg_namespace, 'circle'); + point_start.setAttributeNS(null, 'fill', 'blue'); + point_start.setAttributeNS(null, 'stroke', 'black'); + point_start.setAttributeNS(null, 'stroke-width', '1'); + + var sky_position_rise = polarGetAzEl(timeframe.start); + var coord_rise = polarGetXY(sky_position_rise.azimuth, sky_position_rise.elevation); + + point_start.setAttribute('cx', coord_rise.x); + point_start.setAttribute('cy', coord_rise.y); + point_start.setAttribute('r', 2); - polarOrbit.setAttribute('d', g); + // Draw oberservation end + var point_end = document.createElementNS(svg_namespace, 'circle'); + point_end.setAttributeNS(null, 'fill', 'blue'); + point_end.setAttributeNS(null, 'stroke', 'black'); + point_end.setAttributeNS(null, 'stroke-width', '1'); + + var sky_position_set = polarGetAzEl(timeframe.end); + var coord_set = polarGetXY(sky_position_set.azimuth, sky_position_set.elevation); + + point_end.setAttribute('cx', coord_set.x); + point_end.setAttribute('cy', coord_set.y); + point_end.setAttribute('r', 2); + + } - // Draw observation start - var point_start = document.createElementNS(svg_namespace, 'circle'); - point_start.setAttributeNS(null, 'fill', 'blue'); - point_start.setAttributeNS(null, 'stroke', 'black'); - point_start.setAttributeNS(null, 'stroke-width', '1'); + // draw rotator + if (rotatorValues.az >= 0 && rotatorValues.el >= 0) + { + + var point_rotator = document.createElementNS(svg_namespace, 'circle'); + var coord_rotator = polarGetXY(rotatorValues.az, rotatorValues.el); + point_rotator.setAttribute('cx', coord_rotator.x); + point_rotator.setAttribute('cy', coord_rotator.y); + point_rotator.setAttribute('r', 9); + //point_end.setAttributeNS(null, 'fill', 'blue'); + point_rotator.setAttributeNS(null, 'stroke', 'purple'); + point_rotator.setAttributeNS(null, 'stroke-width', '1'); + point_rotator.setAttributeNS(null, 'fill-opacity', '0.1'); + + /* + var point_crosshair = document.createElementNS(svg_namespace, 'path'); + point_crosshair.setAttributeNS(null, 'stroke', 1) + point_crosshair.setAttributeNS(null, 'stroke-width', 1) + var pathdata = "M" + coord_rotator.x + " " + coord_rotator.y + " L" + (coord_rotator.x + 10) + " " + coord_rotator.y + console.log(pathdata) + point_crosshair.setAttribute('d', "M" + coord_rotator.x + " " + coord_rotator.y + " L" + (coord_rotator.x + 10) + " " + coord_rotator.y) + */ + + } - var sky_position_rise = polarGetAzEl(timeframe.start); - var coord_rise = polarGetXY(sky_position_rise.azimuth, sky_position_rise.elevation); // sat visible now ? var sky_position_current = polarGetAzEl(new dayjs(new Date())); - if (sky_position_current.elevation > 0 ) - { + if (sky_position_current.elevation > 0) { var point_current = document.createElementNS(svg_namespace, 'circle'); point_current.setAttributeNS(null, 'fill', 'green'); point_current.setAttributeNS(null, 'stroke', 'black'); point_current.setAttributeNS(null, 'stroke-width', '1'); - + var coord_set = polarGetXY(sky_position_current.azimuth, sky_position_current.elevation); - + point_current.setAttribute('cx', coord_set.x); point_current.setAttribute('cy', coord_set.y); point_current.setAttribute('r', 7); } - point_start.setAttribute('cx', coord_rise.x); - point_start.setAttribute('cy', coord_rise.y); - point_start.setAttribute('r', 2); - - // Draw oberservation end - var point_end = document.createElementNS(svg_namespace, 'circle'); - point_end.setAttributeNS(null, 'fill', 'blue'); - point_end.setAttributeNS(null, 'stroke', 'black'); - point_end.setAttributeNS(null, 'stroke-width', '1'); - - var sky_position_set = polarGetAzEl(timeframe.end); - var coord_set = polarGetXY(sky_position_set.azimuth, sky_position_set.elevation); - - point_end.setAttribute('cx', coord_set.x); - point_end.setAttribute('cy', coord_set.y); - point_end.setAttribute('r', 2); + var drawObjects = [polarOrbit, point_start, point_end]; + if (point_current != null) + drawObjects.push(point_current) + if (point_rotator != null) + { + drawObjects.push(point_rotator) + } - if ( point_current == null) - return [polarOrbit, point_start, point_end]; - else - return [polarOrbit, point_start, point_end, point_current]; + return drawObjects } diff --git a/app/static/js/rotator.js b/app/static/js/rotator.js index 9790c06..8aa310d 100644 --- a/app/static/js/rotator.js +++ b/app/static/js/rotator.js @@ -1,15 +1,50 @@ -function rotatorConnectionOpen(event) { - console.log("Rotator Connected"); +var rotatorConnected = false; +var azActual = -1 +var elActual = -1 + +function connectRotator() +{ + if ( rotatorConnected == true ) + { + return; } - function rotatorConnectionClosed(event) { - console.log("Rotator Disconnected"); + try { + + rotator_header.innerHTML = "Rotator Control Connecting"; + + connectWS("ws://192.168.0.250:1880/ws/rotator", rotatorConnectionOpen, rotatorConnectionClosed, rotatorConnectionMessageReceived); } + catch (err) { + console.log("Couldn't connect to rotator websocket") + } + +} + +function rotatorConnectionOpen(event) { + console.log("Rotator Connected"); + + rotator_header.innerHTML = "Rotator Control Connected"; + + rotatorConnected = true; + $("#rotatorEnabled").attr("disabled", false); +} + +function rotatorConnectionClosed(event) { + rotator_header.innerHTML = "Rotator Control Disconnected"; + + $("#rotatorEnabled").attr("disabled", true); + + console.log("Rotator Disconnected"); + rotatorConnected = false; +} - function rotatorConnectionMessageReceived(event) { - console.log(JSON.parse(event.data)) +function rotatorConnectionMessageReceived(event) { + console.log(JSON.parse(event.data)) - rotatorData = JSON.parse(event.data) - rot_actual_el.innerHTML = rotatorData.el; - rot_actual_az.innerHTML = rotatorData.az; - } \ No newline at end of file + rotatorData = 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 3579f12..6520f62 100644 --- a/app/static/js/satellite_tracker.js +++ b/app/static/js/satellite_tracker.js @@ -27,7 +27,6 @@ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { var table = document.getElementById("satellitelist"); - // search for satellite object in satellite list via title function getSatelliteByTitle(arr, value) { for (var i = 0, iLen = arr.length; i < iLen; i++) { @@ -41,12 +40,86 @@ function getSatelliteByTitle(arr, value) { function calcSatellitePositions(satrec, dateobject) { var gmst = satellite.gstime(dateobject); var positionAndVelocity = satellite.propagate(satrec, dateobject); + var positionEci = positionAndVelocity.position; var velocityEci = positionAndVelocity.velocity; var positionGd = satellite.eciToGeodetic(positionEci, gmst); var positionEcf = satellite.eciToEcf(positionEci, gmst); var lookAngles = satellite.ecfToLookAngles(observerGd, positionEcf); - return [positionGd, lookAngles] + var positionEcf = satellite.eciToEcf(positionEci, gmst); + //var velocityEcf = satellite.eciToEcf(velocityEci, gmst); + var observerEcf = satellite.geodeticToEcf(observerGd); + var observerEci = satellite.ecfToEci(observerEcf, gmst); + + var dopplerFactorEci = satellite.dopplerFactor(observerEci, positionEci, velocityEci); + + return [positionGd, lookAngles, dopplerFactorEci] +} + +function calcNextPass(satrec) { + + if (isGeostationary(satrec)) { + return { 'aos': null, 'los': null, 'maxel_dt': null, 'max_el': 0, 'start_az': 0, 'path': [] } + } + + var start = new dayjs(new Date()) + var end = start.add(2, 'd') + + console.log(start) + console.log(end) + var prevLat = 0; + var prevLon = 0; + + var aos_dt = null + var los_dt = null + var maxel_dt = null + var max_el = -1 + var start_az = -1 + var prev_el = -1 + + var path = [] + + for (var t = start; t < end; t = t.add(20, 's')) { + var position = calcSatellitePositions(satrec, t.toDate()) + + //console.log(position) + var elevation = satellite.radiansToDegrees(position[1].elevation) + var azimuth = satellite.radiansToDegrees(position[1].azimuth) + + //console.log(elevation) + + if (elevation > 0) { + // pass started + if (prev_el < 0) { + console.log("sat rise") + max_el = elevation + start_az = azimuth + aos_dt = t + } + + // determine highest point + if (elevation > max_el) { + max_el = elevation + maxel_dt = t + } + + newLat = satellite.radiansToDegrees(position[0].latitude); + newLon = satellite.radiansToDegrees(position[0].longitude) + + path.push([newLat, newLon]) + } + else { + // have we reached end of the pass + if (prev_el > 0) { + los_dt = t; + break; + } + } + + prev_el = elevation; + } + + return { 'aos': aos_dt, 'los': los_dt, 'maxel_dt': maxel_dt, 'max_el': max_el, 'start_az': start_az, 'path': path } } // update satellite data from server (called when next pass is over) @@ -58,97 +131,201 @@ function updateData(jsondata) { jsondata.satellites.forEach(element => { for (var i = 0, iLen = satellites.length; i < iLen; i++) { if (satellites[i].title == element.title) { - var nextpass = [] - for (var x = 0; x < element.next_pass.passdata.length; x++) { - nextpass.push([element.next_pass.passdata[x].latitude, element.next_pass.passdata[x].longitude]) - } - satellites[i].next_pass_data = nextpass - satellites[i].all_data = element + var satrec = satellite.twoline2satrec(element.tle1, element.tle2); + satellites[i].next_pass_data = calcNextPass(satrec) break; } } }) }; +/* +Arccosine implementation. + +Returns a value between zero and two pi. +Borrowed from gsat 0.9 by Xavier Crehueras, EB3CZS. +Optimized by Alexandru Csete. +*/ +function arccos(x, y) { + if (x && y) { + if (y > 0.0) + return Math.acos(x / y); + else if (y < 0.0) + return pi + Math.acos(x / y); + } + + return 0.0; +} + +/* +Range circle calculations. + +Borrowed from gsat 0.9.0 by Xavier Crehueras, EB3CZS +who borrowed from John Magliacane, KD2BD. +Optimized by Alexandru Csete and William J Beksi. +*/ +function generateFootprint(satrec) { + pos = calcSatellitePositions(satrec, new Date()) + + var xkmper = 6.378135e3; + var pi = 3.1415926535898; /* Pi */ + var pio2 = 1.5707963267949; /* Pi/2 */ + + // not sure if this is 100% correct, but it looks right + var footprint = 12756.33 * Math.acos(xkmper / (xkmper + pos[0].height)) + + var beta = (0.5 * footprint) / xkmper; + var ssplat = pos[0].latitude + var ssplon = pos[0].longitude + + var points = []; + + var lat = 0; + var lon = 0; + + for (azi = 0; azi < 360; azi += 1) { + azimuth = satellite.degreesToRadians(azi); + lat = Math.asin(Math.sin(ssplat) * Math.cos(beta) + Math.cos(azimuth) * Math.sin(beta) + * Math.cos(ssplat)); + num = Math.cos(beta) - (Math.sin(ssplat) * Math.sin(lat)); + dem = Math.cos(ssplat) * Math.cos(lat); + + if (azi == 0 && (beta > pio2 - ssplat)) + lon = ssplon + pi; + + else if (azi == 180 && (beta > pio2 + ssplat)) + lon = ssplon + pi; + + else if (Math.abs(num / dem) > 1.0) + lon = ssplon; + + else { + if ((180 - azi) >= 0) + lon = ssplon - arccos(num, dem); + else + lon = ssplon + arccos(num, dem); + } + + points.push([satellite.radiansToDegrees(lat), satellite.radiansToDegrees(lon)]); + } + + + return points; +} + +function dopplerDiff(dopplerFactor, frequency) { + dop100mhz = Math.round(100 * dopplerFactor * 1000000) + dop = dop100mhz - 100000000 + return dop +} 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] + + dopp = dopplerDiff(doppler, 100) // satellite properties prop_title.innerHTML = satelliteData.title prop_az.innerHTML = satellite.radiansToDegrees(lookAngles.azimuth).toFixed(2) prop_el.innerHTML = satellite.radiansToDegrees(lookAngles.elevation).toFixed(2) - prop_range.innerHTML = lookAngles.rangeSat.toFixed(0) - - var satrise = new dayjs(satelliteData.all_data.next_pass.satrise) - - var difference = satrise.toDate().getTime() - (new Date().getTime()) - var hours = Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); - var minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60)); - - if (hours >= 0 && minutes >= 0) { - prop_countdown.innerHTML = hours.toString().padStart(2, '0') + ":" + minutes.toString().padStart(2, '0'); + if (satelliteData.prevRange == null) { + prop_range.innerHTML = lookAngles.rangeSat.toFixed(0) + " (?)" } else { - prop_countdown.innerHTML = 'Now'; + 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" + } } + selectedSatellite.prevRange = lookAngles.rangeSat - // draw next pass - layerGroup.clearLayers(); - var polyline = L.polyline(satelliteData.next_pass_data).arrowheads({ size: '20px', frequency: 'endonly' }); - polyline.addTo(layerGroup); + // draw footprint + footprintpoints = generateFootprint(satelliteData.satrec); + var footprint = L.polygon(footprintpoints); + footprint.addTo(layerGroup); - // draw orbit - orbit = [] - var start = new dayjs(new Date()) - var end = new dayjs(new Date(satelliteData.all_data.next_pass.satrise)) + if (isGeostationary(satelliteData.satrec) == false) { + var satrise = satelliteData.next_pass_data.aos; - var prevLat = 0; - var prevLon = 0; - - for (var t = start; t < end; t = t.add(20, 's')) { - var position = calcSatellitePositions(satelliteData.satrec, t.toDate()) + var difference = satrise.toDate().getTime() - (new Date().getTime()) - newLat = satellite.radiansToDegrees(position[0].latitude); - newLon = satellite.radiansToDegrees(position[0].longitude) + var hours = Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + var minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60)); - if (Math.abs(newLat - prevLat) > 10) { - var polyline = L.polyline(orbit, { color: 'black' }); - polyline.addTo(layerGroup); - orbit = [] + if (hours >= 0 && minutes >= 0) { + prop_countdown.innerHTML = hours.toString().padStart(2, '0') + ":" + minutes.toString().padStart(2, '0'); } - - if (Math.abs(newLon - prevLon) > 10) { - var polyline = L.polyline(orbit, { color: 'black' }); - polyline.addTo(layerGroup); - orbit = [] + else { + prop_countdown.innerHTML = 'Now'; } - orbit.push([newLat, newLon]) + // draw next pass + var polyline = L.polyline(satelliteData.next_pass_data.path).arrowheads({ size: '20px', frequency: 'endonly' }); + polyline.addTo(layerGroup); + + // draw orbit + orbit = [] + var start = new dayjs(new Date()) + var end = satelliteData.next_pass_data.aos + + var prevLat = 0; + var prevLon = 0; + + for (var t = start; t < end; t = t.add(20, 's')) { + var position = calcSatellitePositions(satelliteData.satrec, t.toDate()) + + newLat = satellite.radiansToDegrees(position[0].latitude); + newLon = satellite.radiansToDegrees(position[0].longitude) + + if (Math.abs(newLat - prevLat) > 10) { + var polyline = L.polyline(orbit, { color: 'black' }); + polyline.addTo(layerGroup); + orbit = [] + } + + if (Math.abs(newLon - prevLon) > 10) { + var polyline = L.polyline(orbit, { color: 'black' }); + polyline.addTo(layerGroup); + orbit = [] + } + + orbit.push([newLat, newLon]) - prevLat = satellite.radiansToDegrees(position[0].latitude) - prevLon = satellite.radiansToDegrees(position[0].longitude) + prevLat = satellite.radiansToDegrees(position[0].latitude) + prevLon = satellite.radiansToDegrees(position[0].longitude) + } + var polyline = L.polyline(orbit, { color: 'black' }); + polyline.addTo(layerGroup); + } + else { + prop_countdown.innerHTML = "N/A" } - var polyline = L.polyline(orbit, { color: 'black' }); - polyline.addTo(layerGroup); // draw polar graph var tleLine1 = satelliteData.tle1 var tleLine2 = satelliteData.tle2 var timeframe = { - start: new dayjs(new Date(satelliteData.all_data.next_pass.satrise)), - end: new dayjs(new Date(satelliteData.all_data.next_pass.satset)) + start: new dayjs(new Date(satelliteData.next_pass_data.aos)), + end: new dayjs(new Date(satelliteData.next_pass_data.los)) }; @@ -159,10 +336,44 @@ function updateSelectedSatellite() { }; + // send rotator position + if ($("#rotatorEnabled").is(':checked')) { + + var az = satellite.radiansToDegrees(lookAngles.azimuth).toFixed(2) + var el = satellite.radiansToDegrees(lookAngles.elevation).toFixed(2) + + // only send if elevation > 0 + // TODO: improve this to handle with 0 - 180 elevation rotator (ie. flip) + if (el > 0) { + rot_requested_az.innerHTML = az; + rot_requested_el.innerHTML = el; + + if (rotatorConnected) + { + var rotatorData = { 'az' : satellite.radiansToDegrees(lookAngles.azimuth), 'el' : satellite.radiansToDegrees(lookAngles.elevation)} + sendWS(rotatorData); + } + } + 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} + sendWS(rotatorData); + } + + } + } + + + // update polar graph var polarPlotSVG = calcPolarPlotSVG(timeframe, groundstation, tleLine1, - tleLine2); + tleLine2, isGeostationary(satelliteData.satrec), { 'az' : azActual, 'el' : elActual }); var based = ' \ \ @@ -186,19 +397,6 @@ function updateSelectedSatellite() { $('svg#polar').html(based); $('svg#polar').append(polarPlotSVG); - // send rotator position - if ($("#rotatorEnabled").is(':checked')) { - var az = satellite.radiansToDegrees(lookAngles.azimuth).toFixed(2) - var el = satellite.radiansToDegrees(lookAngles.elevation).toFixed(2) - - // only send if elevation > 0 - // TODO: improve this to handle with 0 - 180 elevation rotator (ie. flip) - if (el > 0) { - rot_requested_az.innerHTML = az; - rot_requested_el.innerHTML = el; - sendWS(lookAngles) - } - } } function selectSatellite(marker) { @@ -219,6 +417,14 @@ function selectSatellite(marker) { } } +function isGeostationary(satrec) { + + if (satrec.no < 0.005) + return true; + else + return false; +} + function initMap(jsondata) { console.log(jsondata); layerGroup.clearLayers(); @@ -265,12 +471,16 @@ function initMap(jsondata) { var satrec = satellite.twoline2satrec(element.tle1, element.tle2); + console.log(element.title) + console.log("Geostationary Check"); + console.log(satrec.no) + console.log(isGeostationary(satrec)); + var satdata = calcSatellitePositions(satrec, new Date()) var positionGd = satdata[0] var lookAngles = satdata[1] - var lat = satellite.radiansToDegrees(positionGd.latitude); var lon = satellite.radiansToDegrees(positionGd.longitude); @@ -282,23 +492,7 @@ function initMap(jsondata) { satObject.marker.setLatLng([lat, lon]).update() satObject.satrec = satrec - - var nextpass = [] - - // just skip it if error - if (element.next_pass == null) { - return; - } - - for (var x = 0; x < element.next_pass.passdata.length; x++) { - nextpass.push([element.next_pass.passdata[x].latitude, element.next_pass.passdata[x].longitude]) - } - - satObject.next_pass_data = nextpass - - - //satObject.orbit_data = orbit - satObject.all_data = element + satObject.next_pass_data = calcNextPass(satrec) var newRow = table.insertRow(); var satname = newRow.insertCell(); @@ -316,25 +510,37 @@ function initMap(jsondata) { satel.innerHTML = satellite.radiansToDegrees(lookAngles.elevation).toFixed(2) satrange.innerHTML = lookAngles.rangeSat.toFixed(0) - var satrise = new dayjs(element.next_pass.satrise) - var satset = new dayjs(element.next_pass.satset) - var satmax = new dayjs(element.next_pass.satmax) + if (isGeostationary(satrec) == false) { + var satrise = satdata.aos + var satset = satdata.los + var satmax = satdata.maxel_dt + + if (satrise != null) nextpassaos.innerHTML = satrise.utc().format('YYYY/MM/DD HH:mm') + if (satmax != null) nextpassmax.innerHTML = satmax.utc().format('YYYY/MM/DD HH:mm') + if (satset != null) nextpasslos.innerHTML = satset.utc().format('YYYY/MM/DD HH:mm') - nextpassaos.innerHTML = satrise.utc().format('YYYY/MM/DD HH:mm') - nextpassmax.innerHTML = satmax.utc().format('YYYY/MM/DD HH:mm') - nextpasslos.innerHTML = satset.utc().format('YYYY/MM/DD HH:mm') - maxel.innerHTML = element.next_pass.maxel.toFixed(2) + maxel.innerHTML = satdata.max_el - var difference = satrise.toDate().getTime() - (new Date().getTime()) + if (satrise != null) { + var difference = satrise.toDate().getTime() - (new Date().getTime()) - var hours = Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); - var minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60)); + var hours = Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + var minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60)); - if (hours >= 0 && minutes >= 0) { - countdown.innerHTML = hours.toString().padStart(2, '0') + ":" + minutes.toString().padStart(2, '0'); + if (hours >= 0 && minutes >= 0) { + countdown.innerHTML = hours.toString().padStart(2, '0') + ":" + minutes.toString().padStart(2, '0'); + } + else { + countdown.innerHTML = 'Now'; + } + } } else { - countdown.innerHTML = 'Now'; + nextpassaos.innerHTML = "N/A" + nextpassmax.innerHTML = "N/A" + nextpasslos.innerHTML = "N/A" + countdown.innerHTML = "N/A" + maxel.innerHTML = satellite.radiansToDegrees(lookAngles.elevation).toFixed(2) } satObject.row = newRow @@ -350,8 +556,6 @@ function initMap(jsondata) { updateLoop(); } - - function updateLoop() { sortTable(5, table); @@ -391,27 +595,41 @@ function updateLoop() { table.rows[x].cells[2].innerHTML = satellite.radiansToDegrees(lookAngles.elevation).toFixed(2) table.rows[x].cells[3].innerHTML = lookAngles.rangeSat.toFixed(2) - var satrise = new dayjs(element.all_data.next_pass.satrise) - var satset = new dayjs(element.all_data.next_pass.satset) - var satmax = new dayjs(element.all_data.next_pass.satmax) - - if (satset < new dayjs()) { - console.log("need update") - needUpdate = 1; + if (isGeostationary(element.satrec) == false) { + var satrise = element.next_pass_data.aos + var satset = element.next_pass_data.los + var satmax = element.next_pass_data.maxel_dt + + if (satset != null) { + if (satset < new dayjs()) { + console.log("need update") + needUpdate = 1; + } + } + + if (satrise != null && satset != null && satmax != null) { + var difference = satrise.toDate().getTime() - (new Date().getTime()) + var hours = Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + var minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60)); + + + if (hours >= 0 && minutes >= 0) { + table.rows[x].cells[4].innerHTML = hours.toString().padStart(2, '0') + ":" + minutes.toString().padStart(2, '0'); + } + 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') + } + + table.rows[x].cells[8].innerHTML = element.next_pass_data.max_el.toFixed(2) + } + else { + table.rows[x].cells[8].innerHTML = satellite.radiansToDegrees(lookAngles.elevation).toFixed(2) } - - var difference = satrise.toDate().getTime() - (new Date().getTime()) - - var hours = Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); - var minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60)); - - //countdown.innerHTML = hours + ":" + minutes; - - table.rows[x].cells[4].innerHTML = hours.toString().padStart(2, '0') + ":" + minutes.toString().padStart(2, '0'); - 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') - table.rows[x].cells[8].innerHTML = element.all_data.next_pass.maxel.toFixed(2) } } @@ -459,11 +677,6 @@ function updateSatelliteList() { $(document).ready(function () { getSatelliteList(); - try { - connectWS("ws://localhost:1880/ws/rotator", rotatorConnectionOpen, rotatorConnectionClosed, rotatorConnectionMessageReceived); - } - catch (err) { - console.log("Couldn't connect to rotator websocket") - } + connectRotator(); }); diff --git a/app/templates/index.html b/app/templates/index.html index 36d2bbe..2253923 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -78,6 +78,12 @@
+ + Doppler@100Mhz + +
+ +
-
- Rotator Control +
diff --git a/images/node_red_basic.png b/images/node_red_basic.png new file mode 100644 index 0000000..581b255 Binary files /dev/null and b/images/node_red_basic.png differ diff --git a/nodered_flow_examples/basic_template.json b/nodered_flow_examples/basic_template.json new file mode 100644 index 0000000..9da7664 --- /dev/null +++ b/nodered_flow_examples/basic_template.json @@ -0,0 +1,162 @@ +[ + { + "id": "0d2779ba14e375b5", + "type": "tab", + "label": "Satellite Server Control", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "6b8438d5e9a11a22", + "type": "websocket in", + "z": "0d2779ba14e375b5", + "name": "", + "server": "70c045e4549401f7", + "client": "", + "x": 320, + "y": 260, + "wires": [ + [ + "44b44287fc260a5b" + ] + ] + }, + { + "id": "0d0420f25d82e593", + "type": "websocket out", + "z": "0d2779ba14e375b5", + "name": "", + "server": "70c045e4549401f7", + "client": "", + "x": 860, + "y": 440, + "wires": [] + }, + { + "id": "aa57fdb47adb550d", + "type": "function", + "z": "0d2779ba14e375b5", + "name": "Update From Rotator", + "func": "// update this function with code to read from your rotator\nvar az_value = 179;\nvar el_value = 50\n\nvar newAzimuth = { payload: { 'az' : az_value, 'el' : el_value } }\n\nreturn newAzimuth;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 440, + "wires": [ + [ + "0d0420f25d82e593" + ] + ] + }, + { + "id": "8c724718ab717d61", + "type": "inject", + "z": "0d2779ba14e375b5", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "2", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 370, + "y": 440, + "wires": [ + [ + "aa57fdb47adb550d" + ] + ] + }, + { + "id": "666ef6429cf7ae1f", + "type": "function", + "z": "0d2779ba14e375b5", + "name": "Seperate Request", + "func": "// This function outputs the requested azimuth and elevation\n// from the satellite server. You need to add nodes after this\n// which will control your rotator\n\nvar az = msg.payload.az\nvar el = msg.payload.el\n\nvar newAzimuth = { payload: az }\nvar newElevation = { payload: el }\n\nreturn [newAzimuth, newElevation]", + "outputs": 2, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 670, + "y": 260, + "wires": [ + [ + "ce162e92462be6d4" + ], + [ + "33cbdf3e4e339bc4" + ] + ] + }, + { + "id": "44b44287fc260a5b", + "type": "json", + "z": "0d2779ba14e375b5", + "name": "", + "property": "payload", + "action": "", + "pretty": false, + "x": 490, + "y": 260, + "wires": [ + [ + "666ef6429cf7ae1f" + ] + ] + }, + { + "id": "ce162e92462be6d4", + "type": "debug", + "z": "0d2779ba14e375b5", + "name": "Set Azimuth", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 870, + "y": 240, + "wires": [] + }, + { + "id": "33cbdf3e4e339bc4", + "type": "debug", + "z": "0d2779ba14e375b5", + "name": "Set Elevation", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 870, + "y": 280, + "wires": [] + }, + { + "id": "70c045e4549401f7", + "type": "websocket-listener", + "path": "/ws/rotator", + "wholemsg": "false" + } +] \ No newline at end of file