#!/usr/bin/env python import sys import traceback from PySide2.QtCore import ( Qt, QObject, Signal, Slot, QRunnable, QThreadPool ) from PySide2.QtWidgets import ( QApplication, QMainWindow ) from PySide2.QtCharts import ( QtCharts ) from UM24CUI import Ui_MainWindow from meter import um24c class WorkerSignals(QObject): """ Defines the signals available from a running worker thread. Supported signals are: finished No data error `tuple` (exctype, value, traceback.format_exc() ) result `object` data returned from processing, anything progress `int` indicating % progress """ finished = Signal() error = Signal(tuple) result = Signal(object) progress = Signal(int) class MeterSignals(WorkerSignals): progress = Signal(object) class UM24LabUIWorker(QRunnable): def __init__(self, fn, *args, **kwargs): super(UM24LabUIWorker, self).__init__() self.fn = fn self.args = args self.kwargs = kwargs self.signals = WorkerSignals() self.kwargs['progress_callback'] = self.signals.progress @Slot() def run(self): try: result = self.fn(*self.args, **self.kwargs) except Exception: traceback.print_exc() exctype, value = sys.exc_info()[:2] self.signals.error.emit((exctype, value, traceback.format_exc())) else: self.signals.result.emit(result) finally: self.signals.finished.emit() class UM24LabWorker(UM24LabUIWorker): def __init__(self, fn, *args, **kwargs): super(UM24LabUIWorker, self).__init__() self.fn = fn self.args = args self.kwargs = kwargs self.signals = MeterSignals() self.kwargs['progress_callback'] = self.signals.progress @Slot() def run(self): while um24c.is_connected(): try: result = self.fn(*self.args, **self.kwargs) self.signals.progress.emit(result) except Exception: traceback.print_exc() exctype, value = sys.exc_info()[:2] self.signals.error.emit((exctype, value, traceback.format_exc())) else: self.signals.result.emit(result) class UM24Lab(QMainWindow): def __init__(self): super(UM24Lab, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.threadpool = QThreadPool() self.meter_stats = None self.ui.labelTimeRecorded.setText('00:00:00') self.ui.sliderBrightness.setValue(0) self.ui.sliderScreenOff.setValue(0) self.ui.lcdVoltage.display(0.00) self.ui.lcdCurrent.display(0.00) self.ui.lcdImpedance.display(0.00) self.ui.lcdPower.display(0.00) self.ui.lcdTempC.display(0) self.ui.lcdTempF.display(0) self.ui.progressTempC.setValue(0) self.ui.progressTempF.setValue(0) self.ui.lcdDataMinus.display(0.00) self.ui.lcdDataPlus.display(0.00) self.ui.lcdCapacityRecorded.display(0) self.ui.lcdEnergyRecorded.display(0) self.ui.spinStopCurrent.setValue(0.00) self.ui.buttonGroup.buttons()[0].setChecked(True) # TODO: Add splash screen, discover in background self.action_discover_devices() self.ui.buttonNextScreen.clicked.connect(self.action_next_screen) self.ui.buttonSwitchGroup.clicked.connect(self.action_next_group) self.ui.buttonClearData.clicked.connect(self.action_clear_group) self.ui.buttonRotateScreen.clicked.connect(self.action_rotate_screen) # --- Plot setup --- self._setup_plots() self.timer_step = 0 # timer = QTimer(self) # timer.timeout.connect(self.update_graphs) # timer.start(50) def _setup_plots(self): self.ui.plotVoltage = QtCharts.QChart() self.ui.widgetVoltage.setChart(self.ui.plotVoltage) self.ui.plotCurrent = QtCharts.QChart() self.ui.widgetCurrent.setChart(self.ui.plotCurrent) # --- Voltage --- self.voltage = self.ui.plotVoltage self.voltage_series = QtCharts.QLineSeries(self) self.voltage_series.setName('Voltage over time') self.voltage_series.setUseOpenGL(True) self.voltage.addSeries(self.voltage_series) axis_x = QtCharts.QValueAxis() axis_x.setRange(0, 0) # axis_x.setTickCount(1) axis_x.setTickInterval(0.001) axis_x.setTitleText('Seconds') self.voltage.addAxis(axis_x, Qt.AlignBottom) self.voltage_series.attachAxis(axis_x) axis_y = QtCharts.QValueAxis() # axis_y.setTickCount(1) axis_y.setRange(0, 10) axis_y.setTitleText('Voltage (V)') self.voltage.addAxis(axis_y, Qt.AlignLeft) self.voltage_series.attachAxis(axis_y) # --- Current --- self.current = self.ui.plotCurrent self.current_series = QtCharts.QLineSeries(self) self.current_series.setName('Current over time') self.current_series.setUseOpenGL(True) self.current.addSeries(self.current_series) axis_x = QtCharts.QValueAxis() axis_x.setRange(0, 60000) # axis_x.setTickCount(1) # axis_x.setTickInterval(1) axis_x.setTitleText('Seconds') self.current.addAxis(axis_x, Qt.AlignBottom) self.current_series.attachAxis(axis_x) axis_y = QtCharts.QValueAxis() # axis_y.setTickCount(1) axis_y.setRange(0, 10) axis_y.setTitleText('Current (A)') self.current.addAxis(axis_y, Qt.AlignLeft) self.current_series.attachAxis(axis_y) def action_next_screen(self): um24c.send_command(um24c.Command.NEXT_SCREEN) def action_next_group(self): um24c.send_command(um24c.Command.NEXT_GROUP) def action_rotate_screen(self): um24c.send_command(um24c.Command.ROTATE_SCREEN) def action_clear_group(self): um24c.send_command(um24c.Command.CLEAR_GROUP) def do_discover_devices(self, progress_callback): return um24c.discover_devices() def discover_devices_finished(self): if self.ui.comboDevices.count() > 0: self.ui.comboDevices.setEnabled(True) self.ui.buttonConnection.setEnabled(True) def discover_devices_result(self, devices): for device in devices: self.ui.comboDevices.addItem(device[0]) self.ui.buttonConnection.clicked.connect(self.action_connect_device) def action_discover_devices(self): worker = UM24LabUIWorker(self.do_discover_devices) worker.signals.result.connect(self.discover_devices_result) worker.signals.finished.connect(self.discover_devices_finished) # worker.signals.progress.connect(...) self.threadpool.start(worker) def do_connect_device(self, progress_callback): if not um24c.is_connected(): um24c.connect(self.ui.comboDevices.currentText()) if um24c.is_connected(): self.ui.buttonConnection.setText('Disconnect') self.ui.comboDevices.setEnabled(False) return True else: um24c.disconnect() if not um24c.is_connected(): self.ui.buttonConnection.setText('Connect') self.ui.comboDevices.setEnabled(True) return False def connect_device_result(self, status): self.ui.comboDevices.setEnabled(not status) if status: self.ui.buttonConnection.setText('Disconnect') self.action_update_stats() else: self.ui.buttonConnection.setText('Connect') def action_connect_device(self): worker = UM24LabUIWorker(self.do_connect_device) worker.signals.result.connect(self.connect_device_result) self.threadpool.start(worker) def do_update_stats(self, progress_callback): return um24c.get_meter_stats() def update_stats_progress(self, current): self.meter_stats = current self.update_graphs() def update_stats_finished(self): ui = self.ui ui.lcdVoltage.display(self.meter_stats.Voltage / 100) ui.lcdCurrent.display(self.meter_stats.Current / 1000) ui.lcdImpedance.display(self.meter_stats.Load_equivalent_impedance / 10) ui.lcdPower.display(self.meter_stats.Power / 1000) ui.lcdTempC.display(self.meter_stats.Temperature_Celcius) ui.lcdTempF.display(self.meter_stats.Temperature_Fahrenheit) ui.progressTempC.setValue(self.meter_stats.Temperature_Celcius) ui.progressTempF.setValue(self.meter_stats.Temperature_Fahrenheit) ui.lcdDataMinus.display(self.meter_stats.DMinus / 100) ui.lcdDataPlus.display(self.meter_stats.DPlus / 100) ui.lcdCapacityRecorded.display(self.meter_stats.Recorded_Capacity) ui.lcdEnergyRecorded.display(self.meter_stats.Recorded_Energy) ui.spinStopCurrent.setValue(self.meter_stats.Current_Trigger / 100) ui.sliderBrightness.setValue(self.meter_stats.Display_brightness) ui.sliderScreenOff.setValue(self.meter_stats.Display_timeout) ui.buttonGroup.buttons()[self.meter_stats.Current_screen] \ .setChecked(True) def action_update_stats(self): worker = UM24LabWorker(self.do_update_stats) worker.signals.progress.connect(self.update_stats_progress) worker.signals.finished.connect(self.update_stats_finished) self.threadpool.start(worker) def update_graphs(self): if um24c.is_connected() and self.meter_stats: ui = self.ui ui.lcdVoltage.display(self.meter_stats.Voltage / 100) ui.lcdCurrent.display(self.meter_stats.Current / 1000) ui.lcdImpedance.display(self.meter_stats.Load_equivalent_impedance / 10) ui.lcdPower.display(self.meter_stats.Power / 1000) ui.lcdTempC.display(self.meter_stats.Temperature_Celcius) ui.lcdTempF.display(self.meter_stats.Temperature_Fahrenheit) ui.progressTempC.setValue(self.meter_stats.Temperature_Celcius) ui.progressTempF.setValue(self.meter_stats.Temperature_Fahrenheit) ui.lcdDataMinus.display(self.meter_stats.DMinus / 100) ui.lcdDataPlus.display(self.meter_stats.DPlus / 100) ui.lcdCapacityRecorded.display(self.meter_stats.Recorded_Capacity) ui.lcdEnergyRecorded.display(self.meter_stats.Recorded_Energy) ui.spinStopCurrent.setValue(self.meter_stats.Current_Trigger / 100) ui.sliderBrightness.setValue(self.meter_stats.Display_brightness) ui.sliderScreenOff.setValue(self.meter_stats.Display_timeout) ui.buttonGroup.buttons()[self.meter_stats.Current_screen] \ .setChecked(True) # self.voltage_series.append(self.timer_step, random.randint(0, 10)) # self.current_series.append(self.timer_step, random.randint(0, 10)) # self.timer_step += 1 # for axis in self.voltage_series.attachedAxes(): # if axis.orientation() == Qt.Orientation.Horizontal: # axis.setRange(0, self.timer_step) # for axis in self.current_series.attachedAxes(): # if axis.orientation() == Qt.Orientation.Horizontal: # axis.setRange(0, self.timer_step) if __name__ == '__main__': app = QApplication(sys.argv) labview = UM24Lab() labview.show() sys.exit(app.exec_())