Revert SQL changes and use a separate, non-db datamodel for the dashboard display.
This commit is contained in:
parent
0a1d863f5f
commit
70b099a05e
@ -60,17 +60,18 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
self.dbinput = None
|
self.dbinput = None
|
||||||
|
|
||||||
#connect the database to the model and the model to the listview
|
#connect the database to the model and the model to the listview
|
||||||
self.dbname = 'air_modes.db'
|
# self.dbname = 'air_modes.db'
|
||||||
self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
|
# self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
|
||||||
self.db.setDatabaseName(self.dbname)
|
# self.db.setDatabaseName(self.dbname)
|
||||||
self.db.open()
|
# self.db.open()
|
||||||
self.datamodel = QtSql.QSqlQueryModel()
|
self.datamodel = dashboard_data_model(None)
|
||||||
self.datamodel.setQuery("select * from aircraft order by icao")
|
|
||||||
|
|
||||||
self.ui.list_aircraft.setModel(self.datamodel)
|
self.ui.list_aircraft.setModel(self.datamodel)
|
||||||
self.ui.list_aircraft.setModelColumn(0)
|
self.ui.list_aircraft.setModelColumn(0)
|
||||||
|
|
||||||
#set up dashboard views
|
#set up dashboard views
|
||||||
|
#TODO: figure out why you can't update the RSSI or compass widgets with this mapper
|
||||||
|
#pretty sure it's a Qt bug in the SQL code -- returns as string instead of double
|
||||||
self.icaodelegate = ICAOViewDelegate()
|
self.icaodelegate = ICAOViewDelegate()
|
||||||
self.ui.list_aircraft.setItemDelegate(self.icaodelegate)
|
self.ui.list_aircraft.setItemDelegate(self.icaodelegate)
|
||||||
self.dashboard_mapper = QtGui.QDataWidgetMapper()
|
self.dashboard_mapper = QtGui.QDataWidgetMapper()
|
||||||
@ -88,6 +89,7 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
compass_palette = QtGui.QPalette()
|
compass_palette = QtGui.QPalette()
|
||||||
compass_palette.setColor(QtGui.QPalette.Foreground, QtCore.Qt.white)
|
compass_palette.setColor(QtGui.QPalette.Foreground, QtCore.Qt.white)
|
||||||
self.ui.compass_heading.setPalette(compass_palette)
|
self.ui.compass_heading.setPalette(compass_palette)
|
||||||
|
#TODO: change the needle to an aircraft silhouette
|
||||||
self.ui.compass_heading.setNeedle(Qwt.QwtDialSimpleNeedle(Qwt.QwtDialSimpleNeedle.Ray, False, QtCore.Qt.black))
|
self.ui.compass_heading.setNeedle(Qwt.QwtDialSimpleNeedle(Qwt.QwtDialSimpleNeedle.Ray, False, QtCore.Qt.black))
|
||||||
self.ui.compass_heading.setValue(315.0)
|
self.ui.compass_heading.setValue(315.0)
|
||||||
|
|
||||||
@ -104,19 +106,6 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
rssi = index.model().data(index.model().index(index.row(), 2)).toFloat()[0]
|
rssi = index.model().data(index.model().index(index.row(), 2)).toFloat()[0]
|
||||||
self.ui.prog_rssi.setValue(rssi)
|
self.ui.prog_rssi.setValue(rssi)
|
||||||
|
|
||||||
#this is fired off by the main loop each time a packet comes in.
|
|
||||||
#eventually you might have this set to just QTimer, depending on how fast things go
|
|
||||||
#this is also updated on EVERY mode S packet, not just valid ADS-B
|
|
||||||
#the RIGHT way to do this is:
|
|
||||||
#all SQL is done inside the datamodel, which can be a QSqlTableModel type.
|
|
||||||
#No fields are editable by the user.
|
|
||||||
#when an update happens, the SQL model determines the row which has changed (by ICAO)
|
|
||||||
#the SQL model then invalidates that row, which will selectively update the list and hopefully the mapper.
|
|
||||||
def update_gui_widgets(self, msg):
|
|
||||||
#self.datamodel.reset() #this is hella bad
|
|
||||||
self.datamodel.setQuery("select * from aircraft order by icao")
|
|
||||||
self.dashboard_mapper.revert()
|
|
||||||
|
|
||||||
#goes and gets valid antenna, sample rate options from the device and grays out appropriate things
|
#goes and gets valid antenna, sample rate options from the device and grays out appropriate things
|
||||||
def populate_source_options(self):
|
def populate_source_options(self):
|
||||||
sourceid = self.ui.combo_source.currentText()
|
sourceid = self.ui.combo_source.currentText()
|
||||||
@ -207,7 +196,7 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
except:
|
except:
|
||||||
my_position = None
|
my_position = None
|
||||||
|
|
||||||
self.outputs = [self.update_gui_widgets]
|
self.outputs = []
|
||||||
self.updates = []
|
self.updates = []
|
||||||
|
|
||||||
#output options to populate outputs, updates
|
#output options to populate outputs, updates
|
||||||
@ -254,7 +243,7 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
#all this does is fade the ICAOs out as their last report gets older
|
#all this does is fade the ICAOs out as their last report gets older
|
||||||
class ICAOViewDelegate(QtGui.QStyledItemDelegate):
|
class ICAOViewDelegate(QtGui.QStyledItemDelegate):
|
||||||
def paint(self, painter, option, index):
|
def paint(self, painter, option, index):
|
||||||
paintstr = "%x" % index.model().data(index.model().index(index.row(), 0)).toInt()[0]
|
paintstr = "%06x" % index.model().data(index.model().index(index.row(), 0)).toInt()[0]
|
||||||
last_report = str(index.model().data(index.model().index(index.row(), 1)).toString())
|
last_report = str(index.model().data(index.model().index(index.row(), 1)).toString())
|
||||||
age = (datetime.datetime.utcnow() - datetime.datetime.strptime(last_report, "%Y-%m-%d %H:%M:%S")).total_seconds()
|
age = (datetime.datetime.utcnow() - datetime.datetime.strptime(last_report, "%Y-%m-%d %H:%M:%S")).total_seconds()
|
||||||
#minimum alpha is 0x40 (oldest), max is 0xFF (newest)
|
#minimum alpha is 0x40 (oldest), max is 0xFF (newest)
|
||||||
@ -264,6 +253,30 @@ class ICAOViewDelegate(QtGui.QStyledItemDelegate):
|
|||||||
painter.drawText(option.rect.left()+3, option.rect.top(), option.rect.width(), option.rect.height(), option.displayAlignment, paintstr)
|
painter.drawText(option.rect.left()+3, option.rect.top(), option.rect.width(), option.rect.height(), option.displayAlignment, paintstr)
|
||||||
#TODO: draw highlight for selection
|
#TODO: draw highlight for selection
|
||||||
|
|
||||||
|
class dashboard_data_model(QtCore.QAbstractTableModel):
|
||||||
|
def __init__(self, parent):
|
||||||
|
QtCore.QAbstractTableModel.__init__(self, parent)
|
||||||
|
self._data = []
|
||||||
|
self._colnames = ["icao", "seen", "rssi", "latitude", "longitude", "altitude", "speed", "heading", "vertical", "ident", "type"]
|
||||||
|
self._data.append([0x012345, "2012-07-12 09:17:51", -12.23, 31.12345, -112.12345, 86200.0, 776.0, 251.0, 11200.0, "BUTTSEX", "WAT"])
|
||||||
|
def rowCount(self, parent=QtCore.QVariant()):
|
||||||
|
return len(self._data)
|
||||||
|
def columnCount(self, parent=QtCore.QVariant()):
|
||||||
|
return len(self._colnames)
|
||||||
|
def data(self, index, role=QtCore.Qt.DisplayRole):
|
||||||
|
if not index.isValid():
|
||||||
|
return QtCore.QVariant()
|
||||||
|
if index.row() >= self.rowCount():
|
||||||
|
return QtCore.QVariant()
|
||||||
|
if index.column() >= self.columnCount():
|
||||||
|
return QtCore.QVariant()
|
||||||
|
if (role != QtCore.Qt.DisplayRole) and (role != QtCore.Qt.EditRole):
|
||||||
|
return QtCore.QVariant()
|
||||||
|
if self._data[index.row()][index.column()] is None:
|
||||||
|
return QtCore.QVariant()
|
||||||
|
else:
|
||||||
|
return QtCore.QVariant(self._data[index.row()][index.column()])
|
||||||
|
|
||||||
class output_handler(threading.Thread):
|
class output_handler(threading.Thread):
|
||||||
def __init__(self, outputs, updates, queue):
|
def __init__(self, outputs, updates, queue):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
# Boston, MA 02110-1301, USA.
|
# Boston, MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
|
|
||||||
import time, os, sys, math
|
import time, os, sys
|
||||||
from string import split, join
|
from string import split, join
|
||||||
import modes_parse
|
import modes_parse
|
||||||
import sqlite3
|
import sqlite3
|
||||||
@ -54,20 +54,6 @@ class modes_output_sql(modes_parse.modes_parse):
|
|||||||
"ident" TEXT NOT NULL
|
"ident" TEXT NOT NULL
|
||||||
);"""
|
);"""
|
||||||
c.execute(query)
|
c.execute(query)
|
||||||
query = """CREATE TABLE IF NOT EXISTS "aircraft" (
|
|
||||||
"icao" integer primary key not null,
|
|
||||||
"seen" text not null,
|
|
||||||
"rssi" real,
|
|
||||||
"latitude" real,
|
|
||||||
"longitude" real,
|
|
||||||
"altitude" real,
|
|
||||||
"speed" real,
|
|
||||||
"heading" real,
|
|
||||||
"vertical" real,
|
|
||||||
"ident" text,
|
|
||||||
"type" text
|
|
||||||
);"""
|
|
||||||
c.execute(query)
|
|
||||||
c.close()
|
c.close()
|
||||||
#we close the db conn now to reopen it in the output() thread context.
|
#we close the db conn now to reopen it in the output() thread context.
|
||||||
self.db.close()
|
self.db.close()
|
||||||
@ -85,8 +71,12 @@ class modes_output_sql(modes_parse.modes_parse):
|
|||||||
if self.db is None:
|
if self.db is None:
|
||||||
self.db = sqlite3.connect(self.filename)
|
self.db = sqlite3.connect(self.filename)
|
||||||
|
|
||||||
self.make_insert_query(message)
|
query = self.make_insert_query(message)
|
||||||
self.db.commit() #don't know if this is necessary
|
if query is not None:
|
||||||
|
c = self.db.cursor()
|
||||||
|
c.execute(query)
|
||||||
|
c.close()
|
||||||
|
self.db.commit() #don't know if this is necessary
|
||||||
except ADSBError:
|
except ADSBError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -97,60 +87,49 @@ class modes_output_sql(modes_parse.modes_parse):
|
|||||||
|
|
||||||
data = modes_parse.modes_reply(long(data, 16))
|
data = modes_parse.modes_reply(long(data, 16))
|
||||||
ecc = long(ecc, 16)
|
ecc = long(ecc, 16)
|
||||||
rssi = 10.0*math.log10(float(reference))
|
# reference = float(reference)
|
||||||
|
|
||||||
|
|
||||||
query = None
|
query = None
|
||||||
msgtype = data["df"]
|
msgtype = data["df"]
|
||||||
if msgtype == 17:
|
if msgtype == 17:
|
||||||
query = self.sql17(data, rssi)
|
query = self.sql17(data)
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
||||||
def sql17(self, data, rssi):
|
def sql17(self, data):
|
||||||
icao24 = data["aa"]
|
icao24 = data["aa"]
|
||||||
subtype = data["ftc"]
|
subtype = data["ftc"]
|
||||||
c = self.db.cursor()
|
|
||||||
|
retstr = None
|
||||||
|
|
||||||
if subtype == 4:
|
if subtype == 4:
|
||||||
(ident, typename) = self.parseBDS08(data)
|
(msg, typename) = self.parseBDS08(data)
|
||||||
c.execute("insert or ignore into aircraft (icao, seen, rssi, ident, type) values (%i, datetime('now'), %f, '%s', '%s')" % (icao24, rssi, ident, typename))
|
retstr = "INSERT OR REPLACE INTO ident (icao, ident) VALUES (" + "%i" % icao24 + ", '" + msg + "')"
|
||||||
c.execute("update aircraft set seen=datetime('now'), rssi=%f, ident='%s', type='%s' where icao=%i" % (rssi, ident, typename, icao24))
|
|
||||||
|
|
||||||
elif subtype >= 5 and subtype <= 8:
|
elif subtype >= 5 and subtype <= 8:
|
||||||
[ground_track, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data)
|
[ground_track, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data)
|
||||||
altitude = 0
|
altitude = 0
|
||||||
if decoded_lat is None: #no unambiguously valid position available
|
if decoded_lat is None: #no unambiguously valid position available
|
||||||
c.execute("insert or ignore into aircraft (icao, seen, rssi) values (%i, datetime('now'), %f)" % (icao24, rssi))
|
retstr = None
|
||||||
c.execute("update aircraft set seen=datetime('now'), rssi=%f where icao=%i" % (icao24, rssi))
|
|
||||||
else:
|
else:
|
||||||
c.execute("insert or ignore into aircraft (icao, seen, rssi, latitude, longitude, altitude) \
|
retstr = "INSERT INTO positions (icao, seen, alt, lat, lon) VALUES (" + "%i" % icao24 + ", datetime('now'), " + str(altitude) + ", " + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ")"
|
||||||
values (%i, datetime('now'), %f, %.6f, %.6f, %i)" % (icao24, rssi, decoded_lat, decoded_lon, altitude))
|
|
||||||
c.execute("update aircraft set seen=datetime('now'), rssi=%f, latitude=%.6f, longitude=%.6f, altitude=%i" % (rssi, decoded_lat, decoded_lon, altitude))
|
|
||||||
|
|
||||||
elif subtype >= 9 and subtype <= 18 and subtype != 15: #i'm eliminating type 15 records because they don't appear to be valid position reports.
|
elif subtype >= 9 and subtype <= 18 and subtype != 15: #i'm eliminating type 15 records because they don't appear to be valid position reports.
|
||||||
[altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS05(data)
|
[altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS05(data)
|
||||||
if decoded_lat is None: #no unambiguously valid position available
|
if decoded_lat is None: #no unambiguously valid position available
|
||||||
c.execute("insert or ignore into aircraft (icao, seen, rssi) values (%i, datetime('now'), %f);" % (icao24, rssi))
|
retstr = None
|
||||||
c.execute("update aircraft set seen=datetime('now'), rssi=%f where icao=%i" % (icao24, rssi))
|
|
||||||
else:
|
else:
|
||||||
c.execute("insert or ignore into aircraft (icao, seen, rssi, latitude, longitude, altitude) \
|
retstr = "INSERT INTO positions (icao, seen, alt, lat, lon) VALUES (" + "%i" % icao24 + ", datetime('now'), " + str(altitude) + ", " + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ")"
|
||||||
values (%i, datetime('now'), %f, %.6f, %.6f, %i)" % (icao24, rssi, decoded_lat, decoded_lon, altitude))
|
|
||||||
c.execute("update aircraft set seen=datetime('now'), rssi=%f, latitude=%.6f, longitude=%.6f, altitude=%i where icao=%i" % (rssi, decoded_lat, decoded_lon, altitude, icao24))
|
|
||||||
|
|
||||||
elif subtype == 19:
|
elif subtype == 19:
|
||||||
subsubtype = data["sub"]
|
subsubtype = data["sub"]
|
||||||
if subsubtype == 0:
|
if subsubtype == 0:
|
||||||
[velocity, heading, vert_spd] = self.parseBDS09_0(data)
|
[velocity, heading, vert_spd] = self.parseBDS09_0(data)
|
||||||
|
retstr = "INSERT INTO vectors (icao, seen, speed, heading, vertical) VALUES (" + "%i" % icao24 + ", datetime('now'), " + "%.0f" % velocity + ", " + "%.0f" % heading + ", " + "%.0f" % vert_spd + ")";
|
||||||
|
|
||||||
elif 1 <= subsubtype <= 2:
|
elif 1 <= subsubtype <= 2:
|
||||||
[velocity, heading, vert_spd] = self.parseBDS09_1(data)
|
[velocity, heading, vert_spd] = self.parseBDS09_1(data)
|
||||||
else:
|
retstr = "INSERT INTO vectors (icao, seen, speed, heading, vertical) VALUES (" + "%i" % icao24 + ", datetime('now'), " + "%.0f" % velocity + ", " + "%.0f" % heading + ", " + "%.0f" % vert_spd + ")";
|
||||||
return None
|
|
||||||
|
|
||||||
c.execute("insert or ignore into aircraft (icao, seen, rssi, speed, heading, vertical) \
|
|
||||||
values (%i, datetime('now'), %f, %.0f, %.0f, %.0f);" % (icao24, rssi, velocity, heading, vert_spd))
|
|
||||||
c.execute("update aircraft set seen=datetime('now'), rssi=%f, speed=%.0f, heading=%.0f, vertical=%.0f where icao=%i" % (rssi, velocity, heading, vert_spd, icao24))
|
|
||||||
|
|
||||||
|
return retstr
|
||||||
c.close()
|
|
||||||
|
@ -785,6 +785,9 @@
|
|||||||
<height>91</height>
|
<height>91</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
<property name="lineWidth">
|
<property name="lineWidth">
|
||||||
<number>4</number>
|
<number>4</number>
|
||||||
</property>
|
</property>
|
||||||
@ -859,9 +862,15 @@
|
|||||||
<height>271</height>
|
<height>271</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
<property name="layoutMode">
|
<property name="layoutMode">
|
||||||
<enum>QListView::SinglePass</enum>
|
<enum>QListView::SinglePass</enum>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="selectionRectVisible">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenuBar" name="menubar">
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
Loading…
Reference in New Issue
Block a user