3 from PyQt4.QtGui import *
4 from PyQt4.QtCore import SIGNAL, SLOT, Qt, QTimer, QThread
7 from threading import Thread
8 from datetime import datetime
16 from nmea import GPSData
19 [ "00:0D:B5:38:9E:16", "BT-335" ],
20 [ "00:0D:B5:38:AF:C7", "BT-821" ],
24 logprefix = "/home/user/gps/"
26 # lets you get/set powered state of your bluetooth adapter
27 # code from http://tomch.com/wp/?p=132
28 def enable_bluetooth(enabled = None):
29 bus = dbus.SystemBus();
30 root = bus.get_object('org.bluez', '/')
31 manager = dbus.Interface(root, 'org.bluez.Manager')
32 defaultAdapter = manager.DefaultAdapter()
33 obj = bus.get_object('org.bluez', defaultAdapter)
34 adapter = dbus.Interface(obj, 'org.bluez.Adapter')
35 props = adapter.GetProperties()
38 return adapter.GetProperties()['Powered']
40 adapter.SetProperty('Powered', True)
42 adapter.SetProperty('Powered', False)
45 class GPSThread(QThread):
46 def __init__(self, addr, name, parent = None):
47 QThread.__init__(self, parent)
55 self.total_connects = 0
66 logname = os.path.join(logprefix, "%s.%s.nmea" % (datetime.today().strftime("%Y.%m.%d"), self.name))
68 enable_bluetooth(True)
69 self.logfile = open(logname, 'a')
72 if self.logfile is not None:
86 while not self.exiting and socket is None:
87 self.emit(SIGNAL("status_updated(QString)"), "Connecting...")
88 socket = bluetooth.BluetoothSocket()
89 socket.connect((self.addr, 1))
91 self.total_connects += 1
93 self.emit(SIGNAL("status_updated(QString)"), "Connected")
96 while not self.exiting and socket is not None:
97 chunk = socket.recv(1024)
100 raise Exception("Zero read")
103 self.total_length += len(chunk)
104 self.logfile.write(chunk)
107 lines = buffer.split('\n')
111 gpsdata.parse_nmea_string(line)
113 self.total_lines += len(lines)
115 # update display info every 10k
116 if self.total_length - last_length > 512:
117 self.emit(SIGNAL("status_updated(QString)"), "Logged %d lines, %d bytes, %d connects" % (self.total_lines, self.total_length, self.total_connects))
118 last_length = self.total_length
120 self.emit(SIGNAL("data_updated(QString)"), gpsdata.dump())
123 error = "%s: %s" % ("Cannot connect" if socket is None else "Read error", str(e))
125 error = "%s: %s" % ("Cannot connect" if socket is None else "Read error", sys.exc_info())
127 if self.exiting or error is None: return
129 # process error: wait some time and retry
130 global reconnect_delay
131 count = reconnect_delay
132 while not self.exiting and count > 0:
133 self.emit(SIGNAL("status_updated(QString)"), "%s, retry in %d" % (error, count))
143 while not self.exiting:
146 self.emit(SIGNAL("status_updated(QString)"), "FATAL: %s" % str(e))
151 self.emit(SIGNAL("status_updated(QString)"), "FATAL: cleanup failed")
153 self.emit(SIGNAL("status_updated(QString)"), "stopped")
155 class ContainerWidget(QWidget):
156 def __init__(self, addr, name, parent=None):
157 QWidget.__init__(self, parent)
163 self.status = "stopped"
166 self.startbutton = QPushButton("Start")
167 self.startbutton.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
168 self.connect(self.startbutton, SIGNAL('clicked()'), self.start_thread)
170 self.stopbutton = QPushButton("Stop")
171 self.stopbutton.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
172 self.stopbutton.setEnabled(False)
173 self.connect(self.stopbutton, SIGNAL('clicked()'), self.stop_thread)
175 self.statuswidget = QLabel()
176 self.statuswidget.setWordWrap(True)
178 self.monitorwidget = QLabel()
180 header = QHBoxLayout()
181 header.addWidget(self.startbutton)
182 header.addWidget(self.stopbutton)
183 header.addWidget(self.statuswidget)
185 self.layout = QVBoxLayout()
186 self.layout.addLayout(header)
187 self.layout.addWidget(self.monitorwidget)
189 self.setLayout(self.layout)
197 def start_thread(self):
198 if self.thread is not None:
201 self.startbutton.setEnabled(False)
202 self.stopbutton.setEnabled(True)
204 self.thread = GPSThread(self.addr, self.name, self)
205 self.connect(self.thread, SIGNAL("status_updated(QString)"), self.update_status)
206 self.connect(self.thread, SIGNAL("data_updated(QString)"), self.update_monitor)
207 self.connect(self.thread, SIGNAL("finished()"), self.gc_thread)
210 def stop_thread(self):
211 if self.thread is None:
214 self.stopbutton.setEnabled(False)
218 self.thread = None # join
220 self.startbutton.setEnabled(True)
221 self.stopbutton.setEnabled(False)
224 def update_status(self, status = None):
225 if status is not None:
227 self.statuswidget.setText("%s: %s" % (self.name, self.status))
229 def update_monitor(self, data = None):
230 self.monitorwidget.setText(data)
232 class MainWindow(QWidget):
233 def __init__(self, parent=None):
234 QWidget.__init__(self, parent)
235 self.setWindowTitle("UberLogger")
237 layout = QVBoxLayout()
240 for addr, name in devices:
241 layout.addWidget(ContainerWidget(addr, name))
243 self.setLayout(layout)
246 app = QApplication(sys.argv)
248 window = MainWindow()
250 sys.exit(app.exec_())
252 if __name__ == "__main__":