def __init__(self, parent = None): super(ProdGui, self).__init__(parent) # counters self.face_count = 0 self.device_count = 1 self.current_device_no = 1 # Create the queues for data transfer from serial self.q_Data = None self.q_Error = None # Create (serial) event monitor flag self.event_monitor = False self.com_monitor = None # Create a data class self.livefeed = LiveDataFeed() self.value_samples = [] # Create a Timer Class self.timer = QTimer() #Init the UI self.create_main_frame() self.create_menu() #text file we will be saving in # ACC | GSM | GSM_SNR | RTC | SD | NRF_SPI | STN | V_BAT | GPS | GPS_ANT | NRF-ACC | NRF_SD | NRF_OTA self.failed_checks = {"acc":0,"gsm":0,"gsm_snr":0,"rtc":0,"sd":0,"nrf_spi":0,"stn":0,"v_bat":0, "gps":0,"gps_ant":0,"nrf_acc":0,"nrf_sd":0,"nrf_ota":0} self.setWindowTitle("Carnot Production") #advanced stuff self.advanced_set = False self.timer_counter = 0 self.small_string_flag = 0
def __init__(self, *args, **kwargs): MyMplCanvas.__init__(self, *args, **kwargs) timer = QtCore.QTimer(self) timer.timeout.connect(self.on_timer) timer.start(100) self.livefeed = LiveDataFeed() self.xydata = []
class CellCount_Qt_Mpl(QtGui.QWidget, ui_CellCount_Qt_Mpl.Ui_CellCount_Qt_Mpl): def __init__(self, parent=None): #def __init__(self, text, parent=None): super(CellCount_Qt_Mpl, self).__init__(parent) self.setupUi(self) # create live data feed object self.livefeed = LiveDataFeed() # add title & legends for plots self.setLegends() def on_start(self): # create timer object self.timer = QTimer() # connect signals with slots self.connect(self.timer, SIGNAL('timeout()'), self.on_timer) # update timer every ... seconds self.timer.start(frequency * 1000) def on_timer(self): """ Executed periodically when the monitor update timer is fired. """ # read the actual data data = np.loadtxt(options.filename, delimiter='\t') self.livefeed.add_data(data) """ The livefeed is used to find out whether new data was received since the last update. If not, nothing is updated. """ if self.livefeed.has_new_data: data = self.livefeed.read_data() # update bar plot self.barplot.axes.bar(data[:,0],data[:,1],width=0.5, bottom=0, color='r') self.barplot.axes.grid(True) self.barplot.axes.set_ylim(data[:,1].min()*0.9, data[:,1].max()*1.1) # update sum plot self.sumplot.axes.bar(data[:,0],data[:,2],width=0.5, bottom=0, color='g') self.sumplot.axes.grid(True) #update plots self.setLegends() self.barplot.draw() self.sumplot.draw() def setLegends(self): # add title & legends for the 1st plot self.barplot.axes.set_title('Cell Count Current') self.barplot.axes.set_xlabel('Frame') self.barplot.axes.set_ylabel('Cell Number') # add title & legends for the 2nd plot self.sumplot.axes.set_title('Cell Count Cumulative') self.sumplot.axes.set_xlabel('Frame') self.sumplot.axes.set_ylabel('Sum of Cells')
def __init__(self, parent=None): #def __init__(self, text, parent=None): super(CellCount_Qt_Mpl, self).__init__(parent) self.setupUi(self) # create live data feed object self.livefeed = LiveDataFeed() # add title & legends for plots self.setLegends()
def __init__(self, parent=None): super(DataMonitor, self).__init__(parent) self.monitor_active = False self.livefeed = LiveDataFeed() self.timer = QTimer() self.create_menu() self.create_main_frame() self.create_status_bar()
class MyDynamicMplCanvas(MyMplCanvas): """A canvas that updates itself every second with a new plot.""" def __init__(self, *args, **kwargs): MyMplCanvas.__init__(self, *args, **kwargs) timer = QtCore.QTimer(self) timer.timeout.connect(self.on_timer) timer.start(100) self.livefeed = LiveDataFeed() self.xydata = [] def on_start(self): channel_A = 0x30 channel_B = 0x34 StartGPIO() print("GPIO setup complete") StartSPI() print("SPI setup complete") self.data_q = Queue.Queue() self.adc = ADCMonitor(self.data_q, 0) self.dac = DAC() self.dac.write(0.75000, channel_B) self.adc.start() def on_stop(self): self.adc.join() def on_timer(self): self.read_adc_data() self.update_figure() def read_adc_data(self): qdata = list(get_all_from_queue(self.data_q)) if len(qdata) > 0: data = dict(ts=qdata[-1][0], voltage=qdata[-1][1]) self.livefeed.add_data(data) def compute_initial_figureself(): self.axes.plot([0], [0], 'r') def update_figure(self): data = self.livefeed.read_data() self.xydata.append((data['ts'], data['voltage'])) xdata = [s[0] for s in self.xydata] ydata = [s[1] for s in self.xydata] # Build a list of 4 random integers between 0 and 10 (both inclusive) #l = [random.randint(0, 10) for i in range(4)] self.axes.set_ylim(min(ydata), max(ydata)) self.axes.plot(xdata, ydata, 'r') self.draw()
def __init__(self, parent=None): super(PlottingDataMonitor, self).__init__(parent) self.monitor_active = False self.com_monitor = None self.com_data_q = None self.com_error_q = None self.livefeed = LiveDataFeed() self.temperature_samples = [] self.timer = QTimer() self.create_menu() self.create_main_frame() self.create_status_bar()
class PlottingDataMonitor(QMainWindow): def __init__(self, parent=None): super(PlottingDataMonitor, self).__init__(parent) self.monitor_active = False self.logger_active = False self.com_monitor = None self.com_data_q = None self.com_error_q = None self.livefeed = LiveDataFeed() self.temperature_samples = [] self.timer = QTimer() self.create_menu() self.create_main_frame() self.create_status_bar() def make_data_box(self, name): label = QLabel(name) qle = QLineEdit() qle.setEnabled(False) qle.setFrame(False) return (label, qle) def create_plot(self): plot = Qwt.QwtPlot(self) plot.setCanvasBackground(Qt.black) #plot.setAxisScale(Qwt.QwtPlot.xBottom, 0, 10000, 1000) plot.setAxisTitle(Qwt.QwtPlot.xBottom, 'Time') plot.setAxisScaleDraw(Qwt.QwtPlot.xBottom, DateTimeScaleDraw()) plot.setAxisLabelRotation(Qwt.QwtPlot.xBottom, -45.0 ) plot.setAxisLabelAlignment(Qwt.QwtPlot.xBottom, QtCore.Qt.AlignLeft | QtCore.Qt.AlignBottom ) plot.setAxisTitle(Qwt.QwtPlot.yLeft, 'CDC Counts') plot.setAxisAutoScale(Qwt.QwtPlot.yLeft) #plot.setAxisScale(Qwt.QwtPlot.yLeft, 0, 8000000, 1000000) #plot.replot() curve = Qwt.QwtPlotCurve('') curve.setRenderHint(Qwt.QwtPlotItem.RenderAntialiased) pen = QPen(QColor('limegreen')) pen.setWidth(2) curve.setPen(pen) curve.attach(plot) return plot, curve def create_status_bar(self): self.status_text = QLabel('Monitor idle') self.statusBar().addWidget(self.status_text, 1) def create_main_frame(self): # Edit Box # self.editbox = QTextEdit() self.editbox.setReadOnly(True) editbox_layout = QVBoxLayout() editbox_layout.addWidget(self.editbox) editbox_layout.addStretch(1) editbox_groupbox = QGroupBox('CDC Counts') editbox_groupbox.setLayout(editbox_layout) # Port name # portname_l, self.portname = self.make_data_box('COM Port:') portname_layout = QHBoxLayout() portname_layout.addWidget(portname_l) portname_layout.addWidget(self.portname, 0) portname_layout.addStretch(1) portname_groupbox = QGroupBox('COM Port') portname_groupbox.setLayout(portname_layout) # Period Box # periodBox_l, self.periodBox = self.make_data_box('Period:') meanBox_l, self.meanBox = self.make_data_box('Mean:') deviationBox_l, self.deviationBox = self.make_data_box('Deviation:') countBox_l, self.countBox = self.make_data_box('Counts:') self.resetButton = QPushButton(QIcon('lucia.png'), 'Reset') self.resetButton.setGeometry(10, 10, 100, 30) self.resetButton.clicked.connect(self.periodReset) self.stopButton = QPushButton(QIcon('lucia.png'), 'Stop') self.stopButton.setGeometry(10,10,100,30) self.stopButton.clicked.connect(self.periodStop) periodBox_layout = QHBoxLayout() periodBox_layout.addWidget(periodBox_l) periodBox_layout.addWidget(self.periodBox, 0) #periodBox_layout.addWidget(meanBox_l) #periodBox_layout.addWidget(self.meanBox, 0) periodBox_layout.addWidget(deviationBox_l) periodBox_layout.addWidget(self.deviationBox, 0) periodBox_layout.addWidget(countBox_l) periodBox_layout.addWidget(self.countBox, 0) periodBox_layout.addWidget(self.resetButton) periodBox_layout.addWidget(self.stopButton) self.stop = 1 periodBox_layout.addStretch(1) periodBox_groupbox = QGroupBox('Period Calculation') self.periodBox.setText('0') #self.meanBox.setText('M0') self.deviationBox.setText('0') self.countBox.setText('0') periodBox_groupbox.setLayout(periodBox_layout) # Add The Plot # self.plot, self.curve = self.create_plot() plot_layout = QVBoxLayout() plot_layout.addWidget(self.plot) plot_groupbox = QGroupBox('Capacitive to Digital Sensor Graph') plot_groupbox.setLayout(plot_layout) # Add The Zoomer # self.zoomer = Qwt.QwtPlotZoomer( Qwt.QwtPlot.xBottom, Qwt.QwtPlot.yLeft, Qwt.QwtPicker.DragSelection, Qwt.QwtPicker.AlwaysOff, self.plot.canvas()) self.zoomer.setRubberBandPen(QPen(Qt.red)) #self.zoomer.setZoomBase(True) # Main frame and layout # self.main_frame = QWidget() main_layout = QVBoxLayout() main_layout.addWidget(portname_groupbox) main_layout.addWidget(plot_groupbox) main_layout.addWidget(periodBox_groupbox) main_layout.addWidget(editbox_groupbox) main_layout.addStretch(1) self.main_frame.setLayout(main_layout) self.setCentralWidget(self.main_frame) self.set_actions_enable_state() def periodReset(self): print('Reset') self.periodAvg = [] self.periodCount = 0 self.stop = 0 self.startTime=time.clock() self.r = Tk() self.r.withdraw() self.r.clipboard_clear() def periodStop(self): print('Stop') self.stop = 1 try: for elem in self.periodAvg[2:len(self.periodAvg)]: self.r.clipboard_append(str(elem)) self.r.clipboard_append('\n') self.r.destroy() except: print('There is nothing in the clipboard') #win32clipboard.OpenClipboard() #win32clipboard.EmptyClipboard() #win32clipboard.SetClipboardText(str(self.periodAvg[1:len(self.periodAvg)])) #win32clipboard.CloseClipboard() def create_menu(self): # The File Menu # self.file_menu = self.menuBar().addMenu("&File") selectport_action = self.create_action("Select COM &Port...", shortcut="Ctrl+P", slot=self.on_select_port, tip="Select a COM port") self.startMon_action = self.create_action("&Start monitor", shortcut="Ctrl+M", slot=self.on_startMon, tip="Start the data monitor") self.stopMon_action = self.create_action("&Stop monitor", shortcut="Ctrl+T", slot=self.on_stopMon, tip="Stop the data monitor") self.startLog_action = self.create_action("&Start logger", shortcut="Ctrl+L", slot=self.on_startLog, tip="Start the data logger") self.stopLog_action = self.create_action("&Stop logger", shortcut="Ctrl+T", slot=self.on_stopLog, tip="Stop the data logger") self.openFile = QAction(QIcon('open.png'), 'Open Graph', self) self.openFile.setShortcut('Ctrl+O') self.openFile.setStatusTip('Open Graph File') self.openFile.triggered.connect(self.on_Open) exit_action = self.create_action("E&xit", slot=self.close, shortcut="Ctrl+X", tip="Exit the application") self.startMon_action.setEnabled(False) self.stopMon_action.setEnabled(False) self.startLog_action.setEnabled(False) self.stopLog_action.setEnabled(False) self.add_actions(self.file_menu, ( selectport_action, self.openFile, self.startMon_action, self.stopMon_action, self.startLog_action, self.stopLog_action, None, exit_action)) self.help_menu = self.menuBar().addMenu("&Help") about_action = self.create_action("&About", shortcut='F1', slot=self.on_about, tip='About the monitor') self.add_actions(self.help_menu, (about_action,)) def selected(self, _): self.showInfo() def meanstdv(self, x): """ Calculate mean and standard deviation of data x[]: mean = {\sum_i x_i \over n} std = sqrt(\sum_i (x_i - mean)^2 \over n-1) """ from math import sqrt n, mean, std = len(x), 0, 0 for a in x: mean = mean + a mean = mean / float(n) for a in x: std = std + (a - mean)**2 std = sqrt(std / float(n-1)) return mean, std def on_Open(self): cdc_data = [] index = [] fname = QFileDialog.getOpenFileName(self, 'Open file', 'QDir::currentPath()') if fname.isEmpty() == False: f = open(fname, 'r') cdc_data = f.readlines() f.close() cdc_data.pop(0) #Pop the first and the last to get rid of bad data cdc_data.pop(-1) cdc_data_float = map(float, cdc_data) index = [i for i in range(len(cdc_data))] # Draw the Graph # self.curve.setData(index, cdc_data_float) #self.curve.setData(index[0:3600], cdc_data_float[0:3600]) #Set up the axis scales self.plot.setAxisAutoScale(Qwt.QwtPlot.xBottom) self.plot.setAxisAutoScale(Qwt.QwtPlot.yLeft) self.zoomer.setZoomBase(True) #self.plot.replot() def set_actions_enable_state(self): if self.portname.text() == '': startMon_enable = stopMon_enable = False startLog_enable = stopLog_enable = False else: startMon_enable = not self.monitor_active stopMon_enable = self.monitor_active startLog_enable = not self.logger_active stopLog_enable = self.logger_active self.startLog_action.setEnabled(startLog_enable) self.startMon_action.setEnabled(startMon_enable) self.stopLog_action.setEnabled(stopLog_enable) self.stopMon_action.setEnabled(stopMon_enable) def on_about(self): msg = __doc__ QMessageBox.about(self, "About cdcLogger", msg.strip()) def on_select_port(self): ports = list(enumerate_serial_ports()) if len(ports) == 0: QMessageBox.critical(self, 'No ports', 'No serial ports found') return item, ok = QInputDialog.getItem(self, 'Select a port', 'Serial port:', ports, 0, False) if ok and not item.isEmpty(): self.portname.setText(item) self.set_actions_enable_state() def on_stopMon(self): if self.com_monitor is not None: self.com_monitor.join(10) self.com_monitor = None self.monitor_active = False self.timer.stop() self.set_actions_enable_state() self.status_text.setText('Monitor idle') def on_startMon(self): if self.com_monitor is not None or self.portname.text() == '': return # First define a couple of variables that will be used to calculate the period #self.startTime = 1.1 self.mark = 'False' self.periodAvg = [] self.periodCount = 0 self.data_q = Queue.Queue() self.error_q = Queue.Queue() self.com_monitor = ComMonitorThread( self.data_q, self.error_q, full_port_name(str(self.portname.text())), 57600) self.com_monitor.start() com_error = get_item_from_queue(self.error_q) if com_error is not None: QMessageBox.critical(self, 'ComMonitorThread error', com_error) self.com_monitor = None self.monitor_active = True self.set_actions_enable_state() self.timer = QTimer() self.connect(self.timer, SIGNAL('timeout()'), self.on_timer) self.timer.start(.005) self.status_text.setText('Monitor running') def on_startLog(self): self.log() self.logger_active = True self.set_actions_enable_state() def on_stopLog(self): self.logger_active = False self.set_actions_enable_state() def on_timer(self): """ Executed periodically when the monitor update timer is fired. """ self.read_serial_data() self.update_monitor() def log(self): self.log_state = True self.reading_num = 0 self.today = str(datetime.date.today()) self.logname = '%s.csv' % self.today self.file = open(self.logname, "wb") self.file_cvs = csv.writer(self.file) def save_data(self,reading): self.file_cvs.writerow ([reading]) def save_data_stamps(self,reading_num,reading,timestamp,utimestamp): self.file_cvs.writerow ([reading_num,reading,timestamp,utimestamp]) def update_monitor(self): """ Updates the state of the monitor window with new data. The livefeed is used to find out whether new data was received since the last update. If not, nothing is updated. """ if self.livefeed.has_new_data: data = self.livefeed.read_data() # time.time() is a timestamp for the graph X axis ticks # This may be a good place to add period calculation # self.temperature_samples.append((time.time(), data['temperature'])) if len(self.temperature_samples) > 765: self.temperature_samples.pop(0) xdata = [s[0] for s in self.temperature_samples] ydata = [s[1] for s in self.temperature_samples] if (len(self.temperature_samples) > 2 and self.stop == 0): if data['temperature'] > self.temperature_samples[-2][1]: self.mark = 1 elif (data['temperature'] < self.temperature_samples[-2][1]) and (self.mark == 1): endTime = time.clock() period = (endTime - self.startTime) self.periodAvg.append(period) if (len(self.periodAvg) <= 3): self.periodBox.setText('0') self.deviationBox.setText('0') self.countBox.setText('Waiting') if (len(self.periodAvg) > 3): self.Average, self.Deviation = self.meanstdv(self.periodAvg[2:len(self.periodAvg)]) self.periodBox.setText(str(self.Average)) self.deviationBox.setText(str(self.Deviation)) self.countBox.setText(str(len(self.periodAvg)-2)) self.startTime = endTime self.periodCount += 1 self.mark = 0 #avg = sum(ydata) / float(len(ydata)) self.plot.setAxisAutoScale(Qwt.QwtPlot.yLeft) self.plot.setAxisScale(Qwt.QwtPlot.xBottom, xdata[0], max(20, xdata[-1])) self.curve.setData(xdata, ydata) self.plot.replot() #self.plot.setAxisAutoScale(Qwt.QwtPlot.xBottom) #self.zoomer.setZoomBase(True) #self.thermo.setValue(avg) def read_serial_data(self): """ Called periodically by the update timer to read data from the serial port. """ qdata = list(get_all_from_queue(self.data_q)) if len(qdata) > 0: # At this point qdata object is a list type count = 0 # Updates the text box with the incoming values # Clears the text box every 4096 values so that # Memory does not fill up with scrolling text for elem in list(qdata): self.editbox.append(qdata[count][0]) if self.editbox.document().blockCount() == 4096: self.editbox.clear() data = dict(timestamp=qdata[count][1],temperature=int(qdata[count][0])) self.livefeed.add_data(data) if self.logger_active: self.reading_num = self.reading_num + 1 #Uncomment for stamps # #utimestamp = time.time() #A unix style timestamp for the log #self.save_data_stamps(self.reading_num,int(qdata[count][0]),qdata[count][1],utimestamp) if self.today != str(datetime.date.today()): self.file.close() self.log(); self.reading_num = self.reading_num + 1 self.save_data(int(qdata[count][0])) count=count+1 #data = dict(timestamp=qdata[-1][1], # temperature=int(qdata[-1][0])) #self.livefeed.add_data(data) def add_actions(self, target, actions): '''The following two methods are utilities for simpler creation and assignment of actions ''' for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def create_action( self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: self.connect(action, SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action def closeEvent(self, event): self.editbox.append("closing PyQtTest")
def __init__(self, parent=None): super(PlottingDataMonitor, self).__init__(parent) self.monitor_active = False self.com_monitor = None self.livefeed = LiveDataFeed() self.temperature_samples = [] self.timer = QTimer() # menu # self.file_menu = self.menuBar().addMenu("&File") selectport_action = QAction('Select TTY &Port...', self) selectport_action.triggered.connect(self.on_select_port) self.file_menu.addAction(selectport_action) self.start_action = QAction('&Start monitor') self.start_action.triggered.connect(self.on_start) self.start_action.setEnabled(False) self.file_menu.addAction(self.start_action) self.stop_action = QAction('&Stop monitor') self.stop_action.triggered.connect(self.on_stop) # main widget # # port portname_label = QLabel('tty port:') self.portname = QLineEdit() self.portname.setEnabled(False) self.portname.setFrame(False) portname_layout = QHBoxLayout() portname_layout.addWidget(portname_label) portname_layout.addWidget(self.portname, 0) portname_layout.addStretch(1) portname_groupbox = QGroupBox('Port') portname_groupbox.setLayout(portname_layout) # plot widget self.plot = qwt.QwtPlot(self) self.plot.setCanvasBackground(Qt.black) self.plot.setAxisTitle(qwt.QwtPlot.xBottom, 'Time') self.plot.setAxisScale(qwt.QwtPlot.xBottom, 0, 10, 1) self.plot.setAxisTitle(qwt.QwtPlot.yLeft, 'Temperature') self.plot.setAxisScale(qwt.QwtPlot.yLeft, 0, 250, 40) self.plot.replot() # curve widget self.curve = qwt.QwtPlotCurve('') self.curve.setRenderHint(qwt.QwtPlotItem.RenderAntialiased) pen = QPen(QColor('limegreen')) pen.setWidth(2) self.curve.setPen(pen) self.curve.attach(self.plot) # dial # self.dial = QDial() self.dial.setNotchesVisible(True) self.dial.setRange(0, 20) self.dial.setValue(10) self.dial.valueChanged.connect(self.on_dial_change) self.dial_label = QLabel('Update speed = %s (Hz)' % self.dial.value()) self.dial_label.setAlignment(Qt.AlignTop | Qt.AlignHCenter) dial_layout = QVBoxLayout() dial_layout.addWidget(self.dial) dial_layout.addWidget(self.dial_label) # plot layout plot_layout = QVBoxLayout() plot_layout.addWidget(self.plot) plot_layout.addLayout(dial_layout) plot_groupbox = QGroupBox('Temperature') plot_groupbox.setLayout(plot_layout) # main self.main_frame = QWidget() main_layout = QVBoxLayout() main_layout.addWidget(portname_groupbox) main_layout.addWidget(plot_groupbox) main_layout.addStretch(1) self.main_frame.setLayout(main_layout) self.setCentralWidget(self.main_frame) # status # self.status_text = QLabel('Monitor idle') self.statusBar().addWidget(self.status_text, 1)
class PlottingDataMonitor(QMainWindow): def __init__(self, parent=None): super(PlottingDataMonitor, self).__init__(parent) self.monitor_active = False self.com_monitor = None self.livefeed = LiveDataFeed() self.temperature_samples = [] self.timer = QTimer() # menu # self.file_menu = self.menuBar().addMenu("&File") selectport_action = QAction('Select TTY &Port...', self) selectport_action.triggered.connect(self.on_select_port) self.file_menu.addAction(selectport_action) self.start_action = QAction('&Start monitor') self.start_action.triggered.connect(self.on_start) self.start_action.setEnabled(False) self.file_menu.addAction(self.start_action) self.stop_action = QAction('&Stop monitor') self.stop_action.triggered.connect(self.on_stop) # main widget # # port portname_label = QLabel('tty port:') self.portname = QLineEdit() self.portname.setEnabled(False) self.portname.setFrame(False) portname_layout = QHBoxLayout() portname_layout.addWidget(portname_label) portname_layout.addWidget(self.portname, 0) portname_layout.addStretch(1) portname_groupbox = QGroupBox('Port') portname_groupbox.setLayout(portname_layout) # plot widget self.plot = qwt.QwtPlot(self) self.plot.setCanvasBackground(Qt.black) self.plot.setAxisTitle(qwt.QwtPlot.xBottom, 'Time') self.plot.setAxisScale(qwt.QwtPlot.xBottom, 0, 10, 1) self.plot.setAxisTitle(qwt.QwtPlot.yLeft, 'Temperature') self.plot.setAxisScale(qwt.QwtPlot.yLeft, 0, 250, 40) self.plot.replot() # curve widget self.curve = qwt.QwtPlotCurve('') self.curve.setRenderHint(qwt.QwtPlotItem.RenderAntialiased) pen = QPen(QColor('limegreen')) pen.setWidth(2) self.curve.setPen(pen) self.curve.attach(self.plot) # dial # self.dial = QDial() self.dial.setNotchesVisible(True) self.dial.setRange(0, 20) self.dial.setValue(10) self.dial.valueChanged.connect(self.on_dial_change) self.dial_label = QLabel('Update speed = %s (Hz)' % self.dial.value()) self.dial_label.setAlignment(Qt.AlignTop | Qt.AlignHCenter) dial_layout = QVBoxLayout() dial_layout.addWidget(self.dial) dial_layout.addWidget(self.dial_label) # plot layout plot_layout = QVBoxLayout() plot_layout.addWidget(self.plot) plot_layout.addLayout(dial_layout) plot_groupbox = QGroupBox('Temperature') plot_groupbox.setLayout(plot_layout) # main self.main_frame = QWidget() main_layout = QVBoxLayout() main_layout.addWidget(portname_groupbox) main_layout.addWidget(plot_groupbox) main_layout.addStretch(1) self.main_frame.setLayout(main_layout) self.setCentralWidget(self.main_frame) # status # self.status_text = QLabel('Monitor idle') self.statusBar().addWidget(self.status_text, 1) def set_actions_enable_state(self): if self.portname.text() == '': start_enable = stop_enable = False else: start_enable = not self.monitor_active stop_enable = self.monitor_active self.start_action.setEnabled(start_enable) self.stop_action.setEnabled(stop_enable) def read_serial_data(self): '''Called periodically be the update timer to read data from the serial port. ''' qdata = list(get_all_from_queue(self.data_q)) if len(qdata) > 0: # print(len(qdata)) data = dict(timestamp=qdata[-1][1], temperature=ord(qdata[-1][0])) # print(data) self.livefeed.add_data(data) else: print('no data') def update_monitor(self): '''Updates the state of the monitor window with new data. The livefeed is used to dind out whether new data was received since last update. If not, nothing is updated. ''' if self.livefeed.has_new_data: data = self.livefeed.read_data() # print(data) self.temperature_samples.append( (data['timestamp'], data['temperature'])) if len(self.temperature_samples) > 100: self.temperature_samples.pop(0) xdata = [s[0] for s in self.temperature_samples] ydata = [s[1] for s in self.temperature_samples] avg = sum(ydata) / float(len(ydata)) self.plot.setAxisScale(qwt.QwtPlot.xBottom, xdata[0], max(20, xdata[-1])) self.curve.setData(xdata, ydata) self.plot.replot() # slots def on_select_port(self): text, ok = QInputDialog.getText(self, 'Port Name', 'Enter tty:') if ok: self.portname.setText(str(text)) self.set_actions_enable_state() def on_start(self): '''Start the monitor: com_monitor thread and the update timer''' if self.com_monitor is not None or self.portname.text() == '': return self.data_q = Queue() self.error_q = Queue() self.com_monitor = ComMonitorThread(self.data_q, self.error_q, self.portname.text(), 38400) self.com_monitor.start() com_error = None try: com_error = self.error_q.get(True, 0.01) except Empty: pass if com_error is not None: QMessageBox.critical(self, 'ComMonitorThread error', com_error) self.com_monitor = None self.monitor_active = True self.set_actions_enable_state() self.timer = QTimer() self.timer.timeout.connect(self.on_timer) update_freq = self.dial.value() if update_freq > 0: self.timer.start(1000 / update_freq) self.status_text.setText('Monitor running') def on_stop(self): '''Stop the monitor''' if self.com_monitor is not None: self.com_monitor.join(0.01) self.com_monitor = None self.monitor_actibe = False self.timer.stop() self.set_actions_enable_state() self.status_text.setText('Monitor idle') def on_timer(self): '''Executed periodically when the monitor update timer is fired.''' self.read_serial_data() self.update_monitor() def on_dial_change(self): '''When the dial is rotated, it sets the update interval of the timer''' update_freq = self.dial.value() self.dial_label.setText('Update speed = %s (Hz)' % self.dial.value()) if self.timer.isActive(): update_freq = max(0.01, update_freq) self.timer.setInterval(1000 / update_freq)
class ProdGui(QMainWindow): def __init__(self, parent = None): super(ProdGui, self).__init__(parent) # counters self.face_count = 0 self.device_count = 1 self.current_device_no = 1 # Create the queues for data transfer from serial self.q_Data = None self.q_Error = None # Create (serial) event monitor flag self.event_monitor = False self.com_monitor = None # Create a data class self.livefeed = LiveDataFeed() self.value_samples = [] # Create a Timer Class self.timer = QTimer() #Init the UI self.create_main_frame() self.create_menu() #text file we will be saving in # ACC | GSM | GSM_SNR | RTC | SD | NRF_SPI | STN | V_BAT | GPS | GPS_ANT | NRF-ACC | NRF_SD | NRF_OTA self.failed_checks = {"acc":0,"gsm":0,"gsm_snr":0,"rtc":0,"sd":0,"nrf_spi":0,"stn":0,"v_bat":0, "gps":0,"gps_ant":0,"nrf_acc":0,"nrf_sd":0,"nrf_ota":0} self.setWindowTitle("Carnot Production") #advanced stuff self.advanced_set = False self.timer_counter = 0 self.small_string_flag = 0 def create_main_frame(self): self.createFaces() self.create_next_button() self.create_status_bar() self.leftGroupBox.setEnabled(False) self.middleGroupBox.setEnabled(False) self.rightGroupBox.setEnabled(False) self.basicGroupBox.setEnabled(False) self.leftGroupBox.hide() self.middleGroupBox.hide() self.rightGroupBox.hide() self.basic.pixelLabel.setPixmap(QPixmap("images/logo.png")) self.left.pixelLabel.setPixmap(QPixmap("images/logo.png")) self.basic.saveToText.clicked.connect(self.on_save_txt) self.basic.submitButton.clicked.connect(self.on_submit) self.basic.device_text.append(str(self.current_device_no)) self.basic.nextButton.clicked.connect(self.on_flash_button) # self.left.device_id.append(str(self.current_device_no)) self.main_frame = QWidget() face_widget = QWidget() face_layout = QHBoxLayout() face_layout.addWidget(self.leftGroupBox); face_layout.addWidget(self.middleGroupBox); face_layout.addWidget(self.rightGroupBox); face_layout.addWidget(self.basicGroupBox) face_widget.setLayout(face_layout) main_layout = QVBoxLayout() main_layout.addWidget(face_widget) main_layout.addWidget(self.next_button) self.main_frame.setLayout(main_layout) self.setCentralWidget(self.main_frame) def on_flash_button(self): print("\n\nFlashing NRF\n") os.system("flashNRF.cmd") os.system('testing_main1.cmd') time.sleep(5) def create_menu(self): self.menu = self.menuBar().addMenu("&File") self.start_qc = self.create_action("Start &QC", shortcut = "Ctrl+Q", slot = self.on_start, tip = "Start the QC process") self.advanced = self.create_action("&Advanced", shortcut = "Ctrl+C", slot = self.on_advanced, tip = "Super Saiyan") self.menu.addAction(self.start_qc) self.menu.addAction(self.advanced) def createFaces(self): self.leftGroupBox = QGroupBox("Step 1") self.left = LeftWidget() layout1 = QVBoxLayout() layout1.addWidget(self.left) self.leftGroupBox.setLayout(layout1) self.leftGroupBox.setMaximumSize(400, 450) self.middleGroupBox = QGroupBox("Step 2") self.middle = MiddleWidget() layout2 = QVBoxLayout() layout2.addWidget(self.middle) self.middleGroupBox.setLayout(layout2) self.middleGroupBox.setMaximumSize(450, 450) self.rightGroupBox = QGroupBox("Step 3") self.right = RightWidget() layout3 = QVBoxLayout() layout3.addWidget(self.right) self.rightGroupBox.setLayout(layout3) self.rightGroupBox.setMaximumSize(400, 450) # adding the next device button the right widget self.right.nextButton.clicked.connect(self.new_device) self.basicGroupBox = QGroupBox("Carnot") self.basic = BasicWidget() layout4 = QVBoxLayout() layout4.addWidget(self.basic) self.basicGroupBox.setLayout(layout4) self.basicGroupBox.setMinimumSize(400, 550) self.basicGroupBox.setMaximumSize(400, 1000) #self.basic.nextButton.clicked.connect(self.new_device()) def create_next_button(self): self.next_button = QPushButton("Next") #self.next_button.clicked.connect(self.__next_face) self.next_button.clicked.connect(self.new_device) self.next_button.setEnabled(False) def create_status_bar(self): self.status_text = QLabel("Idle (No QC?)") #self.statusBar().addWidget(self.status_text) def create_action( self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: action.triggered.connect(slot) if checkable: action.setCheckable(True) return action def new_device(self): #inclease device number self.basic.device_text.clear() self.basic.device_text.append(str(int(self.current_device_no) + 1)) self.current_device_no = int(self.current_device_no) + 1 #disable the buttons self.basic.saveToText.setEnabled(False) self.basic.submitButton.setEnabled(False) self.basic.nextButton.setEnabled(False) self.basic.pixelLabel.setPixmap(QPixmap("images/logo.png")) #refresh_face #self.update_faces() ''' self.leftGroupBox.setEnabled(False) self.middleGroupBox.setEnabled(False) self.rightGroupBox.setEnabled(False) self.leftGroupBox.setEnabled(True) self.next_button.setEnabled(True) print("device count:", self.device_count, '\n') self.left.update(self.on_serial_ports(),"Checked", qr_code(self.device_count)) ''' def __next_face(self): if self.face_count == 0: self.middleGroupBox.setEnabled(True) self.face_count += 1 self.update_faces() elif self.face_count == 1: self.rightGroupBox.setEnabled(True) self.face_count = 0 self.next_button.setEnabled(False) self.device_count += 1 def on_serial_ports(self): ''' get a list of ports available. ''' port_list = serial_ports() if len(port_list) == 0: QMessageBox.critical(self, "Check Connection", "Device Not Connected") return port = port_list return port def on_timer(self): """Executed periodically when qc update timer is launched""" self.read_serial_data() def on_advanced(self): self.leftGroupBox.show() self.middleGroupBox.show() self.advanced_set = True if self.basicGroupBox.isEnabled(): self.leftGroupBox.setEnabled(True) self.middleGroupBox.setEnabled(True) else: self.leftGroupBox.setEnabled(False) self.middleGroupBox.setEnabled(False) def on_start(self): ''' Start session -> on_serial_ports, then com_monitor thread ''' # this will call the flashing cmd scripts print("\n\nFlashing NRF\n") os.system("flashNRF.cmd") os.system("testing_main1.cmd") # so on start we will flash the device #then we sleep for 5 seconds so that the system is ready time.sleep(5) self.basicGroupBox.setEnabled(True) self.next_button.setEnabled(True) # self.basic.pixelLabel.setPixmap(QPixmap("images/cross-1.png")) self.basic.pixelLabel.setEnabled(True) if self.advanced_set: self.leftGroupBox.setEnabled(True) self.middleGroupBox.setEnabled(True) if self.com_monitor is not None and self.left.com_set() == "": return self.q_Data = queue.Queue() self.q_Error = queue.Queue() self.com_monitor = ComMonitorThread( self.q_Data, self.q_Error, self.on_serial_ports(), 9600) self.com_monitor.start() com_error = get_item_from_queue(self.q_Error) if com_error is not None: QMessageBox.critical(self, 'ComMonitorThread error', com_error) self.com_monitor = None self.event_monitor = True self.timer = QTimer() # self.connect(self.timer, SIGNAL('timeout()'), self.on_timer) self.timer.timeout.connect(self.on_timer) self.timer.start(500.0) #self.status_text.setText("Bad Batch") def read_serial_data(self): """Called periodically to see if serial buffer data available""" ''' each qdata has a list which with-in has a list with single character plus time stamp. ''' #[STAT]: ACC | GSM | GSM_SNR | RTC | SD | NRF_SPI | STN | GPS | GPS_ANT | NRF-ACC #[INFO]: STM_FW | STM_ID | STN_FW | GSM_Ver | CCID | NRF_ID_low | NRF_ID_high b = [] self.timer_counter += 1 #every 1 sec if self.timer_counter > 2: self.timer_counter = 0 qdata = list(get_all_from_queue(self.q_Data)) print(qdata) if len(qdata) > 0 and b'S' in qdata[0][0]: qdata = qdata[1:] #skip the first S if len(qdata) > 70: self.left.update(self.on_serial_ports(),"Checked", qr_code(self.device_count)) for i_a in qdata: if b'\r' in i_a: break b.append(i_a[0]) #TODO: there is a glich in the code, if we do advanced while running the QC, # we only get a portion of the UART string if len(b) > 120: if b[1] == b'A': #in b we dont need the last 3 values \r \n and b'S' #and in the bedinning we dont need b'TAT' data = [] # print(b) for i in range(0,len(b)): data.append(b[i].decode("utf-8")) #find position of "I" for STAT string ending #find position of "S" or "\r" for INFT string ending # print(data) if "I" in data: data_stat = data[4:(data.index("I")-1)] data_info = data[data.index("I")+5:] print(data_stat) print(data_info) data_stat = "".join(data_stat) data_info = "".join(data_info) data_stat = data_stat.split(",") data_info = data_info.split(",") # now we have our data in the above variables '''ACC | GSM | GSM_SNR | RTC | SD | NRF_SPI | STN | V_BAT | GPS | GPS_ANT | NRF-ACC | NRF_SD | NRF_OTA STM_FW | STM_ID | STN_FW | GSM_Ver | CCID | NRF_ID_low | NRF_ID_high ''' print(data_stat) print(data_info) self.livefeed.add_status(data_stat) self.livefeed.add_info(data_info) self.update_faces() else: self.small_string_flag += 1 if self.small_string_flag > 10: QMessageBox.information(self, "Check Connections", "Receiving less data, maybe NRF SPI has failed") self.small_string_flag = 5 else: pass self.current_device_no = self.basic.device_text.toPlainText() if self.current_device_no != "": self.basic.qr.clear() self.basic.qr.append(qr_code(self.current_device_no)) #the following is for data from Teensy '''data = qdata[0] data = data[0].decode("utf-8") data_stat = "".join(data[5:34]) data_info = ''.join(data[41:]) data_stat = data_stat.split(",") data_info = data_info.split(",") print(data_stat) print(data_info) self.livefeed.add_status(data_stat) self.livefeed.add_info(data_info) self.update_faces()''' def update_faces(self): '''ACC | GSM | GSM_SNR | RTC | SD | NRF_SPI | STN | V_BAT | GPS | GPS_ANT | NRF-ACC | NRF_SD | NRF_OTA STM_FW | STM_ID | STN_FW | GSM_Ver | CCID | NRF_ID_low | NRF_ID_high | NRF_Version ''' if self.livefeed.has_new_status: data_status = self.livefeed.read_status() #update battery voltage self.basic.text1.clear() self.basic.text1.append(data_status[7]) #read info data_info = self.livefeed.read_info() if self.check_stm_status(data_status,data_info): print("All stats good") else: print("Error\n") if self.livefeed.has_new_info: data_info = self.livefeed.read_info() else: pass '''if self.livefeed.has_new_status: data_status = self.livefeed.read_status() if self.check_stm_status(data_status): self.middle.update_middle_status(data_status[-1]) else: print("Error\n") # self.middle.update_middle(data[0], data[1], data[2], data[3:]) if self.livefeed.has_new_info: data_info = self.livefeed.read_info() #format stm_id, nrf_id, stm_ver, nrf_ver if self.check_stm_status(data_status): self.middle.update_middle(data_info[1], data_info[-1], data_info[0], data_info[2]) else: print("Error\n") else: pass''' def check_stm_status(self,data,info): '''ACC | GSM | GSM_SNR | RTC | SD | NRF_SPI | STN | V_BAT | GPS | GPS_ANT | NRF-ACC | NRF_SD | NRF_OTA STM_FW | STM_ID | STN_FW | GSM_Ver | CCID | NRF_ID_low | NRF_ID_high | NRF_version ''' #this is used for teensy debugging #[STAT]: //ACC | GSM | GSM_SNR | RTC | SD | NRF_SPI | STN | V_BAT | GPS | GPS_ANT | NRF-ACC | NRF_SD | NRF_OTA #self.middle.update_status_flags(data[6], data[1], data[0], data[3], data[5],data[2], # data[4], data[7], data[8], data[9]) if self.advanced_set: print(info[8]) if 'S' not in info[8]: self.middle.update_middle(*info) self.middle.update_status_flags(data[6], data[1], data[0], data[3], data[5], data[2], data[4], data[8], data[9], data[10], data[11], data[12]) else: print("Bad info string received\n") #print(data) if '0' in data: print(data) number_fails = data.count('0') fail = "" failed_devices = [] if data[0] == '0': failed_devices.append("ACC") if data[1] == '0': failed_devices.append("GSM") if data[2] == '0': failed_devices.append("GSM-SNR") if data[3] == '0': failed_devices.append("RTC") if data[4] == '0': failed_devices.append("SD") if data[5] == '0': failed_devices.append("NRF-SPI") if data[6] == '0': failed_devices.append("STN") if data[7] == '0': failed_devices.append("GPS") if data[8] == '0': failed_devices.append("GPS-ANT") if data[9] == '0': failed_devices.append("NRF-ACC") print(failed_devices) fail = " ".join(failed_devices) print(fail) QMessageBox.critical(self, "Device Modules Failed", "%s module(s) failed"% fail) self.basic.pixelLabel.setPixmap(QPixmap("images/cross-1.png")) #TODO: Disable this popup from comming again and again return 0 elif int(data[2]) < 12: QMessageBox.critical(self, "GSM Antenna", "Please reconnect it") else: #TODO: Enable all the buttons self.basic.pixelLabel.setPixmap(QPixmap("images/tick-black.png")) self.basic.submitButton.setEnabled(True) self.basic.saveToText.setEnabled(True) self.basic.nextButton.setEnabled(True) return 1 def on_submit(self): self.basic.pixelLabel.setPixmap(QPixmap("images/wait_1.jpg")) time.sleep(1) data_status = self.livefeed.read_status() data_info = self.livefeed.read_info() user_input_voltage = self.basic.text2.toPlainText() if user_input_voltage != "": user_input_voltage = float(user_input_voltage) else: QMessageBox.information(self, "Please enter value", "Measure the voltage value.") return if data_info[4] == "": print("no ccid") data_info[4] = "123456789" if data_info[3] == "": print("No gsm version") data_info[3] = 255 if data_info[2] == "": print("no STN version") data_info[2] = "255" ''' stms_i = stnFlag nrfs_st= string of nrf_sd+unplug+gps+acc nrfs_i = gps gsmv = gsm version gpsv = we dont currently have gps version ''' stm_status_bk = str(data_status[0]+data_status[1]+data_status[3]+data_status[4]+data_status[5]+data_status[6]+ data_status[7]+data_status[8]+data_status[9]) data_to_backend = {"lb":int(self.current_device_no), "pc":str(qr_code(int(self.current_device_no))), "flg":1, "stm":str(data_info[1]), "stmv": int(data_info[0]), "nrf":str(data_info[5] + data_info[6]), "nrfv":int(data_info[-1]), "simcc":str(data_info[4]), "stms_st":stm_status_bk, "stms_i":int(data_status[6]), "nrfs_st": "1111","nrfs_i": int(data_status[8]), "gsmv": data_info[3] ,"pwr": data_status[7],"hbn":int(data_info[-1]), "stnv":str(data_info[2]),"gpsv":"123456789A", "vltDevice":int(user_input_voltage)} print(data_to_backend) r = requests.post('http://carnot-staging.herokuapp.com/devices/log/', data = json.dumps(data_to_backend), headers = {"ApiKey":"JXn8e6C29jhZ065i8wyQktY33YD3s9zy"}) #print(r.content) y = r.content.decode("utf-8") # now we have a string if "true" in y: QMessageBox.information(self, "Server", "Data saved to backed") self.new_device() else: QMessageBox.critical(self, "Server", "Check internet connection") def on_save_txt(self): data_status = self.livefeed.read_status() data_info = self.livefeed.read_info() self.local_file = open("carnot_device.csv","a+") self.local_file.write("%d, " % int(self.current_device_no)) self.local_file.write("%s, " % (qr_code(int(self.current_device_no)))) for i in data_info: self.local_file.write("%s, " % i) for i in data_status: print(i) self.local_file.write("%s, " % (data_status)) self.local_file.write("\r\n") self.local_file.close()
class PlottingDataMonitor(QMainWindow): def __init__(self, parent=None): super(PlottingDataMonitor, self).__init__(parent) self.monitor_active = False self.com_monitor = None self.com_data_q = None self.com_error_q = None self.livefeed = LiveDataFeed() self.temperature_samples = [] self.timer = QTimer() self.create_menu() self.create_main_frame() self.create_status_bar() # self.showFullScreen() def make_data_box(self, name): label = QLabel(name) qle = QLineEdit() qle.setEnabled(False) qle.setFrame(False) return (label, qle) def create_plot(self): plot = Qwt.QwtPlot(self) plot.setCanvasBackground(Qt.black) plot.setAxisTitle(Qwt.QwtPlot.xBottom, "Time") plot.setAxisScale(Qwt.QwtPlot.xBottom, 0, 10, 1) plot.setAxisTitle(Qwt.QwtPlot.yLeft, "val") plot.setAxisScale(Qwt.QwtPlot.yLeft, 0, 30000, 40) plot.setAxisAutoScale(Qwt.QwtPlot.yLeft) plot.replot() curve = Qwt.QwtPlotCurve("") # curve.setRenderHint(Qwt.QwtPlotItem.RenderAntialiased) pen = QPen(QColor("limegreen")) pen.setWidth(2) curve.setPen(pen) curve.attach(plot) return plot, curve def create_status_bar(self): self.status_text = QLabel("Monitor idle") self.statusBar().addWidget(self.status_text, 1) def create_main_frame(self): # Port name # portname_l, self.portname = self.make_data_box("Serial port:") portname_layout = QHBoxLayout() portname_layout.addWidget(portname_l) portname_layout.addWidget(self.portname, 0) portname_layout.addStretch(1) portname_groupbox = QGroupBox("Serial Port") portname_groupbox.setLayout(portname_layout) # Plot and thermo # self.plot, self.curve = self.create_plot() # self.thermo = self.create_thermo() plot_layout = QVBoxLayout() plot_layout.addWidget(self.plot) plot_groupbox = QGroupBox("Value") plot_groupbox.setLayout(plot_layout) # Main frame and layout # self.main_frame = QWidget() main_layout = QVBoxLayout() main_layout.addWidget(portname_groupbox) main_layout.addWidget(plot_groupbox) main_layout.addStretch(1) self.main_frame.setLayout(main_layout) self.setCentralWidget(self.main_frame) self.set_actions_enable_state() def create_menu(self): self.file_menu = self.menuBar().addMenu("&File") selectport_action = self.create_action( "Select serial &Port...", shortcut="Ctrl+P", slot=self.on_select_port, tip="Select a serial port" ) self.start_action = self.create_action( "&Start monitor", shortcut="Ctrl+M", slot=self.on_start, tip="Start the data monitor" ) self.stop_action = self.create_action( "&Stop monitor", shortcut="Ctrl+T", slot=self.on_stop, tip="Stop the data monitor" ) exit_action = self.create_action("E&xit", slot=self.close, shortcut="Ctrl+X", tip="Exit the application") self.start_action.setEnabled(False) self.stop_action.setEnabled(False) self.add_actions(self.file_menu, (selectport_action, self.start_action, self.stop_action, None, exit_action)) self.help_menu = self.menuBar().addMenu("&Help") about_action = self.create_action("&About", shortcut="F1", slot=self.on_about, tip="About the monitor") self.add_actions(self.help_menu, (about_action,)) def set_actions_enable_state(self): if self.portname.text() == "": start_enable = stop_enable = False else: start_enable = not self.monitor_active stop_enable = self.monitor_active self.start_action.setEnabled(start_enable) self.stop_action.setEnabled(stop_enable) def on_about(self): msg = __doc__ QMessageBox.about(self, "About the demo", msg.strip()) def on_select_port(self): ports = list(enumerate_serial_ports()) if len(ports) == 0: QMessageBox.critical(self, "No ports", "No serial ports found") return item, ok = QInputDialog.getItem(self, "Select a port", "Serial port:", ports, 0, False) if ok and not item.isEmpty(): self.portname.setText(item) self.set_actions_enable_state() def on_stop(self): """ Stop the monitor """ if self.com_monitor is not None: self.com_monitor.join(0.01) self.com_monitor = None self.monitor_active = False self.timer.stop() self.set_actions_enable_state() self.status_text.setText("Monitor idle") def on_start(self): """ Start the monitor: com_monitor thread and the update timer """ if self.com_monitor is not None or self.portname.text() == "": return self.data_q = Queue.Queue() self.error_q = Queue.Queue() self.com_monitor = ComMonitorThread(self.data_q, self.error_q, full_port_name(str(self.portname.text())), 9600) self.com_monitor.start() com_error = get_item_from_queue(self.error_q) if com_error is not None: QMessageBox.critical(self, "ComMonitorThread error", com_error) self.com_monitor = None self.monitor_active = True self.set_actions_enable_state() self.timer = QTimer() self.connect(self.timer, SIGNAL("timeout()"), self.on_timer) update_freq = 20 self.timer.start(1000.0 / update_freq) self.status_text.setText("Monitor running") def on_timer(self): """ Executed periodically when the monitor update timer is fired. """ self.read_serial_data() self.update_monitor() def update_monitor(self): """ Updates the state of the monitor window with new data. The livefeed is used to find out whether new data was received since the last update. If not, nothing is updated. """ if self.livefeed.has_new_data: data = self.livefeed.read_data() self.temperature_samples.append((data["timestamp"], data["temperature"])) if len(self.temperature_samples) > 100: self.temperature_samples.pop(0) xdata = [s[0] for s in self.temperature_samples] ydata = [s[1] for s in self.temperature_samples] # self.plot.setAxisScale(Qwt.QwtPlot.xBottom, xdata[0], max(10, xdata[-1])) self.plot.setAxisScale(Qwt.QwtPlot.xBottom, xdata[0], xdata[0] + 5) self.curve.setData(xdata, ydata) self.plot.replot() def read_serial_data(self): """ Called periodically by the update timer to read data from the serial port. """ qdata = list(get_all_from_queue(self.data_q)) if len(qdata) > 0: # print qdata data = dict(timestamp=qdata[-1][1], temperature=int(qdata[-1][0])) self.livefeed.add_data(data) # The following two methods are utilities for simpler creation # and assignment of actions # def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def create_action(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: self.connect(action, SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action
class PlottingDataMonitor(QMainWindow): def __init__(self, parent=None): super(PlottingDataMonitor, self).__init__(parent) self.monitor_active = False self.com_monitor = None self.com_data_q = None self.com_error_q = None self.livefeed = LiveDataFeed() self.temperature_samples = [] self.timer = QTimer() self.create_menu() self.create_main_frame() self.create_status_bar() def make_data_box(self, name): label = QLabel(name) qle = QLineEdit() qle.setEnabled(False) qle.setFrame(False) return (label, qle) def create_plot(self): plot = Qwt.QwtPlot(self) plot.setCanvasBackground(Qt.black) plot.setAxisTitle(Qwt.QwtPlot.xBottom, 'Time') plot.setAxisScale(Qwt.QwtPlot.xBottom, 0, 10, 1) plot.setAxisTitle(Qwt.QwtPlot.yLeft, 'Temperature') plot.setAxisScale(Qwt.QwtPlot.yLeft, 0, 250, 40) plot.replot() curve = Qwt.QwtPlotCurve('') curve.setRenderHint(Qwt.QwtPlotItem.RenderAntialiased) pen = QPen(QColor('limegreen')) pen.setWidth(2) curve.setPen(pen) curve.attach(plot) return plot, curve def create_thermo(self): thermo = Qwt.QwtThermo(self) thermo.setPipeWidth(6) thermo.setRange(0, 120) thermo.setAlarmLevel(80) thermo.setAlarmEnabled(True) thermo.setFillColor(Qt.green) thermo.setAlarmColor(Qt.red) thermo.setOrientation(Qt.Horizontal, Qwt.QwtThermo.BottomScale) return thermo def create_knob(self): knob = Qwt.QwtKnob(self) knob.setRange(0, 20, 0, 1) knob.setScaleMaxMajor(10) knob.setKnobWidth(50) knob.setValue(10) return knob def create_status_bar(self): self.status_text = QLabel('Monitor idle') self.statusBar().addWidget(self.status_text, 1) def create_main_frame(self): # Port name # portname_l, self.portname = self.make_data_box('COM Port:') portname_layout = QHBoxLayout() portname_layout.addWidget(portname_l) portname_layout.addWidget(self.portname, 0) portname_layout.addStretch(1) portname_groupbox = QGroupBox('COM Port') portname_groupbox.setLayout(portname_layout) # Plot and thermo # self.plot, self.curve = self.create_plot() self.thermo = self.create_thermo() thermo_l = QLabel('Average') thermo_layout = QHBoxLayout() thermo_layout.addWidget(thermo_l) thermo_layout.addWidget(self.thermo) thermo_layout.setSpacing(5) self.updatespeed_knob = self.create_knob() self.connect(self.updatespeed_knob, SIGNAL('valueChanged(double)'), self.on_knob_change) self.knob_l = QLabel('Update speed = %s (Hz)' % self.updatespeed_knob.value()) self.knob_l.setAlignment(Qt.AlignTop | Qt.AlignHCenter) knob_layout = QVBoxLayout() knob_layout.addWidget(self.updatespeed_knob) knob_layout.addWidget(self.knob_l) plot_layout = QVBoxLayout() plot_layout.addWidget(self.plot) plot_layout.addLayout(thermo_layout) plot_layout.addLayout(knob_layout) plot_groupbox = QGroupBox('Temperature') plot_groupbox.setLayout(plot_layout) # Main frame and layout # self.main_frame = QWidget() main_layout = QVBoxLayout() main_layout.addWidget(portname_groupbox) main_layout.addWidget(plot_groupbox) main_layout.addStretch(1) self.main_frame.setLayout(main_layout) self.setCentralWidget(self.main_frame) self.set_actions_enable_state() def create_menu(self): self.file_menu = self.menuBar().addMenu("&File") selectport_action = self.create_action("Select COM &Port...", shortcut="Ctrl+P", slot=self.on_select_port, tip="Select a COM port") self.start_action = self.create_action("&Start monitor", shortcut="Ctrl+M", slot=self.on_start, tip="Start the data monitor") self.stop_action = self.create_action("&Stop monitor", shortcut="Ctrl+T", slot=self.on_stop, tip="Stop the data monitor") exit_action = self.create_action("E&xit", slot=self.close, shortcut="Ctrl+X", tip="Exit the application") self.start_action.setEnabled(False) self.stop_action.setEnabled(False) self.add_actions(self.file_menu, ( selectport_action, self.start_action, self.stop_action, None, exit_action)) self.help_menu = self.menuBar().addMenu("&Help") about_action = self.create_action("&About", shortcut='F1', slot=self.on_about, tip='About the monitor') self.add_actions(self.help_menu, (about_action,)) def set_actions_enable_state(self): if self.portname.text() == '': start_enable = stop_enable = False else: start_enable = not self.monitor_active stop_enable = self.monitor_active self.start_action.setEnabled(start_enable) self.stop_action.setEnabled(stop_enable) def on_about(self): msg = __doc__ QMessageBox.about(self, "About the demo", msg.strip()) def on_select_port(self): ports = list(enumerate_serial_ports()) if len(ports) == 0: QMessageBox.critical(self, 'No ports', 'No serial ports found') return item, ok = QInputDialog.getItem(self, 'Select a port', 'Serial port:', ports, 0, False) if ok and not item.isEmpty(): self.portname.setText(item) self.set_actions_enable_state() def on_stop(self): """ Stop the monitor """ if self.com_monitor is not None: self.com_monitor.join(0.01) self.com_monitor = None self.monitor_active = False self.timer.stop() self.set_actions_enable_state() self.status_text.setText('Monitor idle') def on_start(self): """ Start the monitor: com_monitor thread and the update timer """ if self.com_monitor is not None or self.portname.text() == '': return self.data_q = queue.Queue() self.error_q = queue.Queue() self.com_monitor = ComMonitorThread( self.data_q, self.error_q, full_port_name(str(self.portname.text())), 38400) self.com_monitor.start() com_error = get_item_from_queue(self.error_q) if com_error is not None: QMessageBox.critical(self, 'ComMonitorThread error', com_error) self.com_monitor = None self.monitor_active = True self.set_actions_enable_state() self.timer = QTimer() self.connect(self.timer, SIGNAL('timeout()'), self.on_timer) update_freq = self.updatespeed_knob.value() if update_freq > 0: self.timer.start(1000.0 / update_freq) self.status_text.setText('Monitor running') def on_timer(self): """ Executed periodically when the monitor update timer is fired. """ self.read_serial_data() self.update_monitor() def on_knob_change(self): """ When the knob is rotated, it sets the update interval of the timer. """ update_freq = self.updatespeed_knob.value() self.knob_l.setText('Update speed = %s (Hz)' % self.updatespeed_knob.value()) if self.timer.isActive(): update_freq = max(0.01, update_freq) self.timer.setInterval(1000.0 / update_freq) def update_monitor(self): """ Updates the state of the monitor window with new data. The livefeed is used to find out whether new data was received since the last update. If not, nothing is updated. """ if self.livefeed.has_new_data: data = self.livefeed.read_data() self.temperature_samples.append( (data['timestamp'], data['temperature'])) if len(self.temperature_samples) > 100: self.temperature_samples.pop(0) xdata = [s[0] for s in self.temperature_samples] ydata = [s[1] for s in self.temperature_samples] avg = sum(ydata) / float(len(ydata)) self.plot.setAxisScale(Qwt.QwtPlot.xBottom, xdata[0], max(20, xdata[-1])) self.curve.setData(xdata, ydata) self.plot.replot() self.thermo.setValue(avg) def read_serial_data(self): """ Called periodically by the update timer to read data from the serial port. """ qdata = list(get_all_from_queue(self.data_q)) if len(qdata) > 0: data = dict(timestamp=qdata[-1][1], temperature=ord(qdata[-1][0])) self.livefeed.add_data(data) # The following two methods are utilities for simpler creation # and assignment of actions # def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def create_action( self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: self.connect(action, SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action
class DataMonitor(QMainWindow): def __init__(self, parent=None): super(DataMonitor, self).__init__(parent) self.monitor_active = False self.livefeed = LiveDataFeed() self.timer = QTimer() self.create_menu() self.create_main_frame() self.create_status_bar() def make_data_box(self, name): label = QLabel(name) qle = QLineEdit() qle.setEnabled(False) qle.setFrame(False) return (label, qle) def create_plot(self): plot = Qwt.QwtPlot(self) plot.setCanvasBackground(Qt.black) plot.setAxisTitle(Qwt.QwtPlot.xBottom, 'Frame') plot.setAxisScale(Qwt.QwtPlot.xBottom, 0, 10, 1) plot.setAxisTitle(Qwt.QwtPlot.yLeft, 'Number of Cells') plot.setAxisScale(Qwt.QwtPlot.yLeft, 0, 200, 40) plot.replot() curve = Qwt.QwtPlotCurve('') curve.setRenderHint(Qwt.QwtPlotItem.RenderAntialiased) pen = QPen(QColor('limegreen')) pen.setWidth(2) curve.setPen(pen) curve.attach(plot) curve.setSymbol( Qwt.QwtSymbol(Qwt.QwtSymbol.Ellipse, pen.color(), pen.color(), QSize(10, 10))) return plot, curve def create_knob(self): knob = Qwt.QwtKnob(self) knob.setRange(0, 20, 0, 1) knob.setScaleMaxMajor(10) knob.setKnobWidth(50) knob.setValue(2) return knob def create_status_bar(self): self.status_text = QLabel('Monitor idle') self.statusBar().addWidget(self.status_text, 1) def create_main_frame(self): self.plot, self.curve = self.create_plot() self.updatespeed_knob = self.create_knob() self.connect(self.updatespeed_knob, SIGNAL('valueChanged(double)'), self.on_knob_change) self.knob_l = QLabel('Update speed = %s (Hz)' % self.updatespeed_knob.value()) self.knob_l.setAlignment(Qt.AlignTop | Qt.AlignHCenter) knob_layout = QVBoxLayout() knob_layout.addWidget(self.updatespeed_knob) knob_layout.addWidget(self.knob_l) plot_layout = QVBoxLayout() plot_layout.addWidget(self.plot) plot_layout.addLayout(knob_layout) plot_groupbox = QGroupBox('Data Plot') plot_groupbox.setLayout(plot_layout) # Main frame and layout # self.main_frame = QWidget() main_layout = QVBoxLayout() main_layout.addWidget(plot_groupbox) main_layout.addStretch(1) self.main_frame.setLayout(main_layout) self.setCentralWidget(self.main_frame) self.set_actions_enable_state() def create_menu(self): self.file_menu = self.menuBar().addMenu("&File") self.start_action = self.create_action("&Start monitor", shortcut="Ctrl+M", slot=self.on_start, tip="Start the data monitor") self.stop_action = self.create_action("&Stop monitor", shortcut="Ctrl+T", slot=self.on_stop, tip="Stop the data monitor") exit_action = self.create_action("E&xit", slot=self.close, shortcut="Ctrl+X", tip="Exit the application") self.start_action.setEnabled(True) self.stop_action.setEnabled(False) self.add_actions( self.file_menu, (self.start_action, self.stop_action, None, exit_action)) self.add_actions(self.file_menu, (None, exit_action)) def set_actions_enable_state(self): start_enable = not self.monitor_active stop_enable = self.monitor_active self.start_action.setEnabled(start_enable) self.stop_action.setEnabled(stop_enable) def on_stop(self): # Stop the data monitor self.monitor_active = False self.timer.stop() self.set_actions_enable_state() self.status_text.setText('Monitor idle') def on_start(self): #Start the data monitor self.data_q = Queue.Queue() self.monitor_active = True self.set_actions_enable_state() self.timer = QTimer() self.connect(self.timer, SIGNAL('timeout()'), self.on_timer) update_freq = self.updatespeed_knob.value() if update_freq > 0: self.timer.start(1000.0 / update_freq) self.status_text.setText('Monitor running') def on_timer(self): """ Executed periodically when the monitor update timer is fired. """ self.ReadData() self.update_monitor() def on_knob_change(self): """ When the knob is rotated, it sets the update interval of the timer. """ update_freq = self.updatespeed_knob.value() self.knob_l.setText('Update speed = %s (Hz)' % self.updatespeed_knob.value()) if self.timer.isActive(): update_freq = max(0.01, update_freq) self.timer.setInterval(1000.0 / update_freq) def update_monitor(self): """ Updates the state of the monitor window with new data. The livefeed is used to find out whether new data was received since the last update. If not, nothing is updated. """ if self.livefeed.has_new_data: data = self.livefeed.read_data() try: xdata = data[:, 0] ydata = data[:, 1] # scale axis automatically self.plot.setAxisScale(Qwt.QwtPlot.xBottom, xdata.min() * 0.9, xdata.max() * 1.1) self.plot.setAxisScale(Qwt.QwtPlot.yLeft, ydata.min() * 0.9, ydata.max() * 1.1) self.curve.setData(xdata, ydata) self.plot.replot() except: #print 'No data yet ...' test = 1 # just to do something, because otherwise error (ugly, but works ...) def ReadData(self): #Called periodically by the update timer to read data data = np.loadtxt(options.filename, delimiter='\t') self.livefeed.add_data(data) # The following two methods are utilities for simpler creation # and assignment of actions # def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def create_action(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: self.connect(action, SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action