From 55cd17de674ddcbc029b45a91aaa902e32de50c0 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Thu, 20 Jun 2013 23:05:41 -0700 Subject: [PATCH] Added support for integrated Google Maps interface via QWebView/JavaScript/JSONP. Broken due to something hairy wrt QWebView and /tmp. --- apps/modes_gui | 22 ++++++++-- python/CMakeLists.txt | 1 + python/__init__.py | 3 +- python/html_template.py | 92 +++++++++++++++++++++++++++++++++++++++++ python/kml.py | 89 +++++++++++++++++++++++++++++++++++++++ python/sql.py | 2 +- res/modes_rx.ui | 42 +++++++++++++------ 7 files changed, 234 insertions(+), 17 deletions(-) create mode 100644 python/html_template.py diff --git a/apps/modes_gui b/apps/modes_gui index 0d2ed4e..27c1e4b 100755 --- a/apps/modes_gui +++ b/apps/modes_gui @@ -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) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index c175c4f..e748bca 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -34,6 +34,7 @@ GR_PYTHON_INSTALL( altitude.py az_map.py cpr.py + html_template.py mlat.py exceptions.py flightgear.py diff --git a/python/__init__.py b/python/__init__.py index 093cdf7..29e0475 100644 --- a/python/__init__.py +++ b/python/__init__.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 diff --git a/python/html_template.py b/python/html_template.py new file mode 100644 index 0000000..1b2c154 --- /dev/null +++ b/python/html_template.py @@ -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 """ + + + ADS-B Aircraft Map + + + + + +
+
+ +""" % (my_position[0], my_position[1], json_file) diff --git a/python/kml.py b/python/kml.py index c7adb46..99e564e 100644 --- a/python/kml.py +++ b/python/kml.py @@ -170,3 +170,92 @@ class output_kml(threading.Thread): retstr+= '\n\t\n\n' 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\n\t\tRange rings\n\t\t0""" +# for rng in [100, 200, 300]: +# retstr += """\n\t\t\n\t\t\t%inm\n\t\t\t#rangering\n\t\t\t\n\t\t\t\t%s\n\t\t\t\n\t\t""" % (rng, self.draw_circle(self.my_coords, rng),) +# retstr += """\t\n""" + +# retstr += """\t\n\t\tAircraft locations\n\t\t0""" + + #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 diff --git a/python/sql.py b/python/sql.py index 7e4b300..30f20c2 100644 --- a/python/sql.py +++ b/python/sql.py @@ -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 diff --git a/res/modes_rx.ui b/res/modes_rx.ui index 733241c..b7c58b9 100644 --- a/res/modes_rx.ui +++ b/res/modes_rx.ui @@ -85,7 +85,7 @@ - 0 + 3 @@ -856,7 +856,7 @@ Climb - + 200 @@ -865,10 +865,10 @@ 91 - + true - + 4 @@ -901,7 +901,7 @@ true - + -20 @@ -910,10 +910,10 @@ 91 - + true - + 4 @@ -928,6 +928,18 @@ + + + Map + + + + + gridLayoutWidget + + + + @@ -1016,11 +1028,6 @@ - - QwtCompass - QwtDial -
qwt_compass.h
-
QwtDial QWidget @@ -1032,6 +1039,17 @@
air_modes/az_map
1
+ + QwtCompass + QwtDial +
qwt_compass.h
+
+ + QWebView + QWidget +
QtWebKit/qwebview.h
+ 1 +