Added support for integrated Google Maps interface via QWebView/JavaScript/JSONP. Broken due to something hairy wrt QWebView and /tmp.
This commit is contained in:
parent
fbe3c464fb
commit
55cd17de67
@ -19,9 +19,9 @@
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
import os, sys, time, threading, datetime, math, csv
|
||||
import os, sys, time, threading, datetime, math, csv, tempfile
|
||||
from optparse import OptionParser
|
||||
from PyQt4 import QtCore,QtGui
|
||||
from PyQt4 import QtCore,QtGui,QtWebKit
|
||||
from PyQt4.Qwt5 import Qwt
|
||||
from gnuradio import gr, gru, optfir, eng_notation, blks2
|
||||
from gnuradio.eng_option import eng_option
|
||||
@ -72,7 +72,8 @@ class mainwindow(QtGui.QMainWindow):
|
||||
|
||||
#disable by default
|
||||
self.ui.check_adsbonly.setCheckState(QtCore.Qt.Unchecked)
|
||||
|
||||
|
||||
#set up the radio stuff
|
||||
self.queue = gr.msg_queue(10)
|
||||
self.running = False
|
||||
self.kmlgen = None #necessary bc we stop its thread in shutdown
|
||||
@ -288,12 +289,27 @@ class mainwindow(QtGui.QMainWindow):
|
||||
self.az_map_output = air_modes.az_map_output(self._cpr_dec, self.az_model, self._publisher)
|
||||
#self._relay.subscribe("dl_data", self.az_map_output.output)
|
||||
|
||||
#set up map
|
||||
self._htmlfile = open("/home/nick/wat.html", 'wb+')#tempfile.NamedTemporaryFile()
|
||||
self._jsonfile = tempfile.NamedTemporaryFile()
|
||||
|
||||
self.livedata = air_modes.output_print(self._cpr_dec, self._publisher)
|
||||
#add output for live data box
|
||||
#self._relay.subscribe("dl_data", self.output_live_data)
|
||||
|
||||
#create SQL database for KML and dashboard displays
|
||||
self.dbwriter = air_modes.output_sql(self._cpr_dec, self.dbname, self.lock, self._publisher)
|
||||
self.jsonpgen = air_modes.output_jsonp(self._jsonfile.name, self.dbname, my_position, self.lock, timeout=1)
|
||||
htmlstring = air_modes.html_template(my_position, self._jsonfile.name)
|
||||
self._htmlfile.write(htmlstring)
|
||||
self._htmlfile.flush()
|
||||
class WebPage(QtWebKit.QWebPage):
|
||||
def javaScriptConsoleMessage(self, msg, line, source):
|
||||
print '%s line %d: %s' % (source, line, msg)
|
||||
page = WebPage()
|
||||
self.ui.mapView.setPage(page)
|
||||
self.ui.mapView.load( QtCore.QUrl( QtCore.QUrl.fromLocalFile("/home/nick/wat.html") ) )
|
||||
self.ui.mapView.show()
|
||||
|
||||
#output to update reports/sec widget
|
||||
self._relay.subscribe("dl_data", self.increment_reportspersec)
|
||||
|
@ -34,6 +34,7 @@ GR_PYTHON_INSTALL(
|
||||
altitude.py
|
||||
az_map.py
|
||||
cpr.py
|
||||
html_template.py
|
||||
mlat.py
|
||||
exceptions.py
|
||||
flightgear.py
|
||||
|
@ -57,7 +57,7 @@ from parse import *
|
||||
from msprint import output_print
|
||||
from sql import output_sql
|
||||
from sbs1 import output_sbs1
|
||||
from kml import output_kml
|
||||
from kml import output_kml, output_jsonp
|
||||
from raw_server import raw_server
|
||||
from radio import modes_radio
|
||||
from exceptions import *
|
||||
@ -65,6 +65,7 @@ from az_map import *
|
||||
from types import *
|
||||
from altitude import *
|
||||
from cpr import cpr_decoder
|
||||
from html_template import html_template
|
||||
#this is try/excepted in case the user doesn't have numpy installed
|
||||
try:
|
||||
from flightgear import output_flightgear
|
||||
|
92
python/html_template.py
Normal file
92
python/html_template.py
Normal file
@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python
|
||||
#HTML template for Mode S map display
|
||||
#Nick Foster, 2013
|
||||
|
||||
def html_template(my_position, json_file):
|
||||
if my_position is None:
|
||||
my_position = [37, -122]
|
||||
|
||||
return """
|
||||
<html>
|
||||
<head>
|
||||
<title>ADS-B Aircraft Map</title>
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
|
||||
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false">
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var map;
|
||||
var markers = [];
|
||||
var defaultLocation = new google.maps.LatLng(%f, %f);
|
||||
var defaultZoomLevel = 9;
|
||||
|
||||
function requestJSONP() {
|
||||
var script = document.createElement("script");
|
||||
script.src = "%s?" + Math.random();
|
||||
script.params = Math.random();
|
||||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
};
|
||||
|
||||
var planeMarker;
|
||||
var planes = [];
|
||||
|
||||
function clearMarkers() {
|
||||
for (var i = 0; i < planes.length; i++) {
|
||||
planes[i].setMap(null);
|
||||
}
|
||||
planes = [];
|
||||
};
|
||||
|
||||
function jsonp_callback(results) { // from JSONP
|
||||
clearMarkers();
|
||||
airplanes = {};
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
airplanes[results[i].icao] = {
|
||||
center: new google.maps.LatLng(results[i].lat, results[i].lon),
|
||||
heading: results[i].hdg,
|
||||
altitude: 0
|
||||
};
|
||||
}
|
||||
refreshIcons();
|
||||
}
|
||||
|
||||
function refreshIcons() {
|
||||
for (var airplane in airplanes) {
|
||||
var plane_icon = {
|
||||
url: "http://www.nerdnetworks.org/~bistromath/airplane_sprite.png",
|
||||
size: new google.maps.Size(128,128),
|
||||
origin: new google.maps.Point(parseInt(airplanes[airplane].heading/10)*128,0),
|
||||
anchor: new google.maps.Point(64,64),
|
||||
//scaledSize: new google.maps.Size(4608,126)
|
||||
};
|
||||
var planeOptions = {
|
||||
map: map,
|
||||
position: airplanes[airplane].center,
|
||||
icon: plane_icon
|
||||
};
|
||||
planeMarker = new google.maps.Marker(planeOptions);
|
||||
planes.push(planeMarker);
|
||||
};
|
||||
};
|
||||
|
||||
function initialize()
|
||||
{
|
||||
var myOptions =
|
||||
{
|
||||
zoom: defaultZoomLevel,
|
||||
center: defaultLocation,
|
||||
disableDefaultUI: true,
|
||||
mapTypeId: google.maps.MapTypeId.TERRAIN
|
||||
};
|
||||
|
||||
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
|
||||
|
||||
requestJSONP();
|
||||
setInterval("requestJSONP()", 1000);
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body onload="initialize()">
|
||||
<div id="map_canvas" style="width:100%%; height:100%%">
|
||||
</div>
|
||||
</body>
|
||||
</html>""" % (my_position[0], my_position[1], json_file)
|
@ -170,3 +170,92 @@ class output_kml(threading.Thread):
|
||||
|
||||
retstr+= '\n\t</Folder>\n</Document>\n</kml>'
|
||||
return retstr
|
||||
|
||||
#we just inherit from output_kml because we're doing the same thing, only in a different format.
|
||||
class output_jsonp(output_kml):
|
||||
def genkml(self):
|
||||
retstr="""jsonp_callback(["""
|
||||
|
||||
# if self.my_coords is not None:
|
||||
# retstr += """\n\t<Folder>\n\t\t<name>Range rings</name>\n\t\t<open>0</open>"""
|
||||
# for rng in [100, 200, 300]:
|
||||
# retstr += """\n\t\t<Placemark>\n\t\t\t<name>%inm</name>\n\t\t\t<styleUrl>#rangering</styleUrl>\n\t\t\t<LinearRing>\n\t\t\t\t<coordinates>%s</coordinates>\n\t\t\t</LinearRing>\n\t\t</Placemark>""" % (rng, self.draw_circle(self.my_coords, rng),)
|
||||
# retstr += """\t</Folder>\n"""
|
||||
|
||||
# retstr += """\t<Folder>\n\t\t<name>Aircraft locations</name>\n\t\t<open>0</open>"""
|
||||
|
||||
#read the database and add KML
|
||||
q = "select distinct icao from positions where seen > datetime('now', '-5 minute')"
|
||||
c = self._db.cursor()
|
||||
self.locked_execute(c, q)
|
||||
icaolist = c.fetchall()
|
||||
#now we have a list icaolist of all ICAOs seen in the last 5 minutes
|
||||
|
||||
for icao in icaolist:
|
||||
icao = icao[0]
|
||||
#print "ICAO: %x" % icao
|
||||
# q = "select * from positions where icao=%i and seen > datetime('now', '-2 hour') ORDER BY seen DESC limit 1" % icao
|
||||
# self.locked_execute(c, q)
|
||||
# pos = c.fetchall()
|
||||
#print "Track length: %i" % len(track)
|
||||
# if len(track) != 0:
|
||||
# lat = track[0][3]
|
||||
# if lat is None: lat = 0
|
||||
# lon = track[0][4]
|
||||
# if lon is None: lon = 0
|
||||
# alt = track[0][2]
|
||||
# if alt is None: alt = 0
|
||||
|
||||
# metric_alt = alt * 0.3048 #google earth takes meters, the commie bastards
|
||||
|
||||
# trackstr = ""
|
||||
|
||||
# for pos in track:
|
||||
# trackstr += " %f,%f,%f" % (pos[4], pos[3], pos[2]*0.3048)
|
||||
|
||||
# trackstr = string.lstrip(trackstr)
|
||||
# else:
|
||||
# alt = 0
|
||||
# metric_alt = 0
|
||||
# lat = 0
|
||||
# lon = 0
|
||||
# trackstr = str("")
|
||||
|
||||
#now get metadata
|
||||
# q = "select ident from ident where icao=%i" % icao
|
||||
# self.locked_execute(c, q)
|
||||
# r = c.fetchall()
|
||||
# if len(r) != 0:
|
||||
# ident = r[0][0]
|
||||
# else: ident=""
|
||||
#if ident is None: ident = ""
|
||||
#get most recent speed/heading/vertical
|
||||
q = "select seen, speed, heading, vertical from vectors where icao=%i order by seen desc limit 1" % icao
|
||||
self.locked_execute(c, q)
|
||||
r = c.fetchall()
|
||||
if len(r) != 0:
|
||||
seen = r[0][0]
|
||||
speed = r[0][1]
|
||||
heading = r[0][2]
|
||||
vertical = r[0][3]
|
||||
|
||||
else:
|
||||
seen = 0
|
||||
speed = 0
|
||||
heading = 0
|
||||
vertical = 0
|
||||
|
||||
q = "select lat, lon from positions where icao=%i order by seen desc limit 1" % icao
|
||||
self.locked_execute(c, q)
|
||||
r = c.fetchall()
|
||||
if len(r) != 0:
|
||||
lat = r[0][0]
|
||||
lon = r[0][1]
|
||||
else:
|
||||
lat = 0
|
||||
lon = 0
|
||||
#now generate some KML
|
||||
retstr+= """{"icao": "%.6x", "lat": %f, "lon": %f, "hdg": %i, "speed": %i, "vertical": %i},""" % (icao, lat, lon, heading, speed, vertical)
|
||||
|
||||
retstr+= """]);"""
|
||||
return retstr
|
||||
|
@ -80,7 +80,7 @@ class output_sql:
|
||||
c = self._db.cursor()
|
||||
c.execute(query)
|
||||
c.close()
|
||||
# self._db.commit()
|
||||
self._db.commit()
|
||||
|
||||
except ADSBError:
|
||||
pass
|
||||
|
@ -85,7 +85,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>3</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="setup">
|
||||
<property name="sizePolicy">
|
||||
@ -856,7 +856,7 @@
|
||||
<string>Climb</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QwtCompass" name="compass_heading">
|
||||
<widget class="QwtCompass" name="compass_heading" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
@ -865,10 +865,10 @@
|
||||
<height>91</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<property name="readOnly" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<property name="lineWidth" stdset="0">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</widget>
|
||||
@ -901,7 +901,7 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QwtCompass" name="compass_bearing">
|
||||
<widget class="QwtCompass" name="compass_bearing" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>-20</x>
|
||||
@ -910,10 +910,10 @@
|
||||
<height>91</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<property name="readOnly" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<property name="lineWidth" stdset="0">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</widget>
|
||||
@ -928,6 +928,18 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="map_tab">
|
||||
<attribute name="title">
|
||||
<string>Map</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_8">
|
||||
<item row="0" column="0">
|
||||
<widget class="QWebView" name="mapView" native="true">
|
||||
<zorder>gridLayoutWidget</zorder>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="livedatatab">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
@ -1016,11 +1028,6 @@
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QwtCompass</class>
|
||||
<extends>QwtDial</extends>
|
||||
<header>qwt_compass.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QwtDial</class>
|
||||
<extends>QWidget</extends>
|
||||
@ -1032,6 +1039,17 @@
|
||||
<header location="global">air_modes/az_map</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QwtCompass</class>
|
||||
<extends>QwtDial</extends>
|
||||
<header>qwt_compass.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QWebView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">QtWebKit/qwebview.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
Loading…
Reference in New Issue
Block a user