def create_GUI(self): self.pbtn_step_activate = create_Toggle_button("Disabled") self.qled_step_size = QtWid.QLineEdit("1.0", alignment=QtCore.Qt.AlignRight) self.qled_step_size.setFixedWidth(70) grid_sub = QtWid.QGridLayout() grid_sub.addWidget(self.pbtn_step_activate, 0, 0, 1, 3) grid_sub.addWidget(QtWid.QLabel("Step size"), 1, 0) grid_sub.addWidget(self.qled_step_size, 1, 1) grid_sub.addWidget(QtWid.QLabel("mm"), 1, 2) font_1 = QtGui.QFont("", 20) font_2 = QtGui.QFont("", 30) p1 = {"font": font_1, "enabled": False} p2 = {"font": font_2, "enabled": False} self.pbtn_step_up = QtWid.QPushButton(chr(0x25B2), **p1) self.pbtn_step_up.setFixedSize(50, 50) self.pbtn_step_down = QtWid.QPushButton(chr(0x25BC), **p1) self.pbtn_step_down.setFixedSize(50, 50) self.pbtn_step_left = QtWid.QPushButton(chr(0x25C0), **p2) self.pbtn_step_left.setFixedSize(50, 50) self.pbtn_step_right = QtWid.QPushButton(chr(0x25B6), **p2) self.pbtn_step_right.setFixedSize(50, 50) self.pted_focus_trap = QtWid.QPlainTextEdit("", enabled=False) self.pted_focus_trap.setFixedSize(0, 0) # fmt: off grid = QtWid.QGridLayout() grid.addLayout(grid_sub, 0, 0, 1, 4) grid.addItem(QtWid.QSpacerItem(1, 12), 1, 0) grid.addWidget(self.pbtn_step_up, 2, 1, QtCore.Qt.AlignHCenter) grid.addWidget(self.pbtn_step_left, 3, 0, QtCore.Qt.AlignHCenter) grid.addWidget(self.pbtn_step_right, 3, 2, QtCore.Qt.AlignHCenter) grid.addWidget(self.pbtn_step_down, 4, 1, QtCore.Qt.AlignHCenter) grid.addWidget(self.pted_focus_trap, 5, 1, QtCore.Qt.AlignHCenter) # fmt: on self.grpb = QtWid.QGroupBox("Move single step") self.grpb.eventFilter = self.eventFilter self.grpb.installEventFilter(self.grpb) self.grpb.setStyleSheet(SS_GROUP) self.grpb.setLayout(grid)
def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setWindowTitle("Arduino & PyQt multithread demo") self.setStyleSheet(SS_TEXTBOX_READ_ONLY + SS_GROUP) if USE_LARGER_TEXT: self.setGeometry(50, 50, 1024, 768) else: self.setGeometry(350, 50, 960, 660) # ------------------------- # Top frame # ------------------------- # Left box self.qlbl_update_counter = QtWid.QLabel("0") self.qlbl_DAQ_rate = QtWid.QLabel("DAQ: nan Hz") self.qlbl_DAQ_rate.setStyleSheet("QLabel {min-width: 7em}") vbox_left = QtWid.QVBoxLayout() vbox_left.addWidget(self.qlbl_update_counter, stretch=0) vbox_left.addStretch(1) vbox_left.addWidget(self.qlbl_DAQ_rate, stretch=0) # Middle box self.qlbl_title = QtWid.QLabel( "Arduino & PyQt multithread demo", font=QtGui.QFont( "Palatino", 20 if USE_LARGER_TEXT else 14, weight=QtGui.QFont.Bold, ), ) self.qlbl_title.setAlignment(QtCore.Qt.AlignCenter) self.qlbl_cur_date_time = QtWid.QLabel("00-00-0000 00:00:00") self.qlbl_cur_date_time.setAlignment(QtCore.Qt.AlignCenter) self.qpbt_record = create_Toggle_button( "Click to start recording to file") self.qpbt_record.clicked.connect(lambda state: log.record(state)) vbox_middle = QtWid.QVBoxLayout() vbox_middle.addWidget(self.qlbl_title) vbox_middle.addWidget(self.qlbl_cur_date_time) vbox_middle.addWidget(self.qpbt_record) # Right box self.qpbt_exit = QtWid.QPushButton("Exit") self.qpbt_exit.clicked.connect(self.close) self.qpbt_exit.setMinimumHeight(30) self.qlbl_recording_time = QtWid.QLabel(alignment=QtCore.Qt.AlignRight) vbox_right = QtWid.QVBoxLayout() vbox_right.addWidget(self.qpbt_exit, stretch=0) vbox_right.addStretch(1) vbox_right.addWidget(self.qlbl_recording_time, stretch=0) # Round up top frame hbox_top = QtWid.QHBoxLayout() hbox_top.addLayout(vbox_left, stretch=0) hbox_top.addStretch(1) hbox_top.addLayout(vbox_middle, stretch=0) hbox_top.addStretch(1) hbox_top.addLayout(vbox_right, stretch=0) # ------------------------- # Bottom frame # ------------------------- # GraphicsLayoutWidget self.gw = pg.GraphicsLayoutWidget() self.plot = self.gw.addPlot() p = { "color": "#EEE", "font-size": "20pt" if USE_LARGER_TEXT else "10pt", } self.plot.setClipToView(True) self.plot.showGrid(x=1, y=1) self.plot.setLabel("bottom", text="history (sec)", **p) self.plot.setLabel("left", text="amplitude", **p) self.plot.setRange( xRange=[-1.04 * CHART_HISTORY_TIME, CHART_HISTORY_TIME * 0.04], yRange=[-1.1, 1.1], disableAutoRange=True, ) if USE_LARGER_TEXT: font = QtGui.QFont() font.setPixelSize(26) self.plot.getAxis("bottom").setTickFont(font) self.plot.getAxis("bottom").setStyle(tickTextOffset=20) self.plot.getAxis("bottom").setHeight(90) self.plot.getAxis("left").setTickFont(font) self.plot.getAxis("left").setStyle(tickTextOffset=20) self.plot.getAxis("left").setWidth(120) self.history_chart_curve = HistoryChartCurve( capacity=round(CHART_HISTORY_TIME * 1e3 / DAQ_INTERVAL_MS), linked_curve=self.plot.plot( pen=pg.mkPen(color=[255, 255, 0], width=3)), ) # 'Readings' p = {"readOnly": True, "maximumWidth": 7 * em} self.qlin_reading_t = QtWid.QLineEdit(**p) self.qlin_reading_1 = QtWid.QLineEdit(**p) self.qpbt_running = create_Toggle_button("Running", checked=True) self.qpbt_running.clicked.connect( lambda state: self.qpbt_running.setText("Running" if state else "Run")) # fmt: off grid = QtWid.QGridLayout() grid.addWidget(self.qpbt_running, 0, 0, 1, 2) grid.addWidget(QtWid.QLabel("time"), 1, 0) grid.addWidget(self.qlin_reading_t, 1, 1) grid.addWidget(QtWid.QLabel("#01"), 2, 0) grid.addWidget(self.qlin_reading_1, 2, 1) grid.setAlignment(QtCore.Qt.AlignTop) # fmt: on qgrp_readings = QtWid.QGroupBox("Readings") qgrp_readings.setLayout(grid) # 'Wave type' self.qpbt_wave_sine = QtWid.QPushButton("Sine") self.qpbt_wave_sine.clicked.connect(self.process_qpbt_wave_sine) self.qpbt_wave_square = QtWid.QPushButton("Square") self.qpbt_wave_square.clicked.connect(self.process_qpbt_wave_square) self.qpbt_wave_sawtooth = QtWid.QPushButton("Sawtooth") self.qpbt_wave_sawtooth.clicked.connect( self.process_qpbt_wave_sawtooth) # fmt: off grid = QtWid.QGridLayout() grid.addWidget(self.qpbt_wave_sine, 0, 0) grid.addWidget(self.qpbt_wave_square, 1, 0) grid.addWidget(self.qpbt_wave_sawtooth, 2, 0) grid.setAlignment(QtCore.Qt.AlignTop) # fmt: on qgrp_wave_type = QtWid.QGroupBox("Wave type") qgrp_wave_type.setLayout(grid) # 'Chart' self.plot_manager = PlotManager(parent=self) self.plot_manager.add_autorange_buttons(linked_plots=self.plot) self.plot_manager.add_preset_buttons( linked_plots=self.plot, linked_curves=self.history_chart_curve, presets=[ { "button_label": "0.100", "x_axis_label": "history (msec)", "x_axis_divisor": 1e-3, "x_axis_range": (-101, 0), }, { "button_label": "0:05", "x_axis_label": "history (sec)", "x_axis_divisor": 1, "x_axis_range": (-5.05, 0), }, { "button_label": "0:10", "x_axis_label": "history (sec)", "x_axis_divisor": 1, "x_axis_range": (-10.1, 0), }, ], ) self.plot_manager.add_clear_button( linked_curves=self.history_chart_curve) self.plot_manager.perform_preset(1) qgrp_chart = QtWid.QGroupBox("Chart") qgrp_chart.setLayout(self.plot_manager.grid) vbox = QtWid.QVBoxLayout() vbox.addWidget(qgrp_readings) vbox.addWidget(qgrp_wave_type) vbox.addWidget(qgrp_chart) vbox.addStretch() # Round up bottom frame hbox_bot = QtWid.QHBoxLayout() hbox_bot.addWidget(self.gw, 1) hbox_bot.addLayout(vbox, 0) # ------------------------- # Round up full window # ------------------------- vbox = QtWid.QVBoxLayout(self) vbox.addLayout(hbox_top, stretch=0) vbox.addSpacerItem(QtWid.QSpacerItem(0, 10)) vbox.addLayout(hbox_bot, stretch=1)
def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setWindowTitle("Keysight 3497xA control") self.setGeometry(600, 120, 1200, 600) self.setStyleSheet(SS_TEXTBOX_READ_ONLY + SS_GROUP) # ---------------------------------------------------------------------- # Top grid # ---------------------------------------------------------------------- self.qlbl_title = QtWid.QLabel( "Keysight 3497xA control", font=QtGui.QFont("Palatino", 14, weight=QtGui.QFont.Bold), ) self.qlbl_cur_date_time = QtWid.QLabel("00-00-0000 00:00:00") self.qpbt_record = create_Toggle_button( "Click to start recording to file", minimumHeight=40) self.qpbt_record.setMinimumWidth(400) # fmt: off self.qpbt_record.clicked.connect(lambda state: log.record(state)) # pylint: disable=unnecessary-lambda # fmt: on self.qpbt_exit = QtWid.QPushButton("Exit") self.qpbt_exit.clicked.connect(self.close) self.qpbt_exit.setMinimumHeight(30) grid_top = QtWid.QGridLayout() # fmt: off grid_top.addWidget(self.qlbl_title, 0, 0, QtCore.Qt.AlignCenter) grid_top.addWidget(self.qpbt_exit, 0, 2, QtCore.Qt.AlignRight) grid_top.addWidget(self.qlbl_cur_date_time, 1, 0, QtCore.Qt.AlignCenter) grid_top.addWidget(self.qpbt_record, 2, 0, QtCore.Qt.AlignCenter) # fmt: on grid_top.setColumnMinimumWidth(0, 420) grid_top.setColumnStretch(1, 1) # ---------------------------------------------------------------------- # Chart: Mux readings # ---------------------------------------------------------------------- # GraphicsLayoutWidget self.gw_mux = pg.GraphicsLayoutWidget() p = {"color": "#EEE", "font-size": "12pt"} self.pi_mux = self.gw_mux.addPlot() self.pi_mux.setClipToView(True) self.pi_mux.showGrid(x=1, y=1) self.pi_mux.setTitle("Mux readings", **p) self.pi_mux.setLabel("bottom", "history (min)", **p) self.pi_mux.setLabel("left", "misc. units", **p) self.pi_mux.setMenuEnabled(True) self.pi_mux.enableAutoRange(axis=pg.ViewBox.XAxis, enable=False) self.pi_mux.enableAutoRange(axis=pg.ViewBox.YAxis, enable=True) self.pi_mux.setAutoVisible(y=True) # Placeholder to be populated depending on the number of scan channels self.tscurves_mux = list() # List of `HistoryChartCurve` # ---------------------------------------------------------------------- # Legend # ---------------------------------------------------------------------- self.qgrp_legend = QtWid.QGroupBox("Legend") # ---------------------------------------------------------------------- # PlotManager # ---------------------------------------------------------------------- self.plot_manager = PlotManager(parent=self) self.plot_manager.add_autorange_buttons(linked_plots=self.pi_mux) self.plot_manager.add_preset_buttons( linked_plots=self.pi_mux, linked_curves=self.tscurves_mux, presets=[ { "button_label": "0:30", "x_axis_label": "history (sec)", "x_axis_divisor": 1, "x_axis_range": (-30, 0), }, { "button_label": "01:00", "x_axis_label": "history (sec)", "x_axis_divisor": 1, "x_axis_range": (-60, 0), }, { "button_label": "03:00", "x_axis_label": "history (min)", "x_axis_divisor": 60, "x_axis_range": (-3, 0), }, { "button_label": "05:00", "x_axis_label": "history (min)", "x_axis_divisor": 60, "x_axis_range": (-5, 0), }, { "button_label": "10:00", "x_axis_label": "history (min)", "x_axis_divisor": 60, "x_axis_range": (-10, 0), }, { "button_label": "30:00", "x_axis_label": "history (min)", "x_axis_divisor": 60, "x_axis_range": (-30, 0), }, ], ) self.plot_manager.add_clear_button(linked_curves=self.tscurves_mux) qgrp_history = QtWid.QGroupBox("History") qgrp_history.setLayout(self.plot_manager.grid) # ---------------------------------------------------------------------- # Right-panel grid # ---------------------------------------------------------------------- vbox1 = QtWid.QVBoxLayout() vbox1.addWidget(self.qgrp_legend, stretch=0, alignment=QtCore.Qt.AlignTop) vbox1.addWidget(qgrp_history, stretch=0, alignment=QtCore.Qt.AlignTop) vbox1.addStretch(1) # ---------------------------------------------------------------------- # Round up full window # ---------------------------------------------------------------------- hbox1 = QtWid.QHBoxLayout() hbox1.addWidget(mux_qdev.qgrp, stretch=0, alignment=QtCore.Qt.AlignTop) hbox1.addWidget(self.gw_mux, stretch=1) hbox1.addLayout(vbox1) vbox = QtWid.QVBoxLayout(self) vbox.addLayout(grid_top) vbox.addLayout(hbox1) vbox.addStretch(1)
def create_GUI(self): p = {"alignment": QtCore.Qt.AlignCenter, "font": FONT_MONOSPACE} p2 = {"alignment": QtCore.Qt.AlignCenter + QtCore.Qt.AlignVCenter} # self.qlbl_mux = QtWid.QLabel("Keysight 34972a", **p2) self.qlbl_mux_state = QtWid.QLabel("Offline", **p) self.qpbt_start_scan = create_Toggle_button("Start scan") self.qpte_SCPI_commands = QtWid.QPlainTextEdit( "", readOnly=True, lineWrapMode=False ) self.qpte_SCPI_commands.setStyleSheet(SS_TEXTBOX_READ_ONLY) self.qpte_SCPI_commands.setMaximumHeight(152) self.qpte_SCPI_commands.setMinimumWidth(200) self.qpte_SCPI_commands.setFont(FONT_MONOSPACE_SMALL) p = {"alignment": QtCore.Qt.AlignRight, "readOnly": True} self.qled_scanning_interval_ms = QtWid.QLineEdit("", **p) self.qled_obtained_interval_ms = QtWid.QLineEdit("", **p) self.qpte_errors = QtWid.QPlainTextEdit("", lineWrapMode=False) self.qpte_errors.setStyleSheet(SS_TEXTBOX_ERRORS) self.qpte_errors.setMaximumHeight(90) # fmt: off self.qpbt_ackn_errors = QtWid.QPushButton("Acknowledge errors") self.qpbt_reinit = QtWid.QPushButton("Reinitialize") self.qlbl_update_counter = QtWid.QLabel("0") self.qpbt_debug_test = QtWid.QPushButton("Debug test") # fmt: on self.qpbt_start_scan.clicked.connect(self.process_qpbt_start_scan) self.qpbt_ackn_errors.clicked.connect(self.process_qpbt_ackn_errors) self.qpbt_reinit.clicked.connect(self.process_qpbt_reinit) self.qpbt_debug_test.clicked.connect(self.process_qpbt_debug_test) i = 0 p = {"alignment": QtCore.Qt.AlignLeft + QtCore.Qt.AlignVCenter} grid = QtWid.QGridLayout() grid.setVerticalSpacing(4) # fmt: off # grid.addWidget(self.qlbl_mux , i, 0, 1, 3); i+=1 grid.addWidget(QtWid.QLabel("Only scan when necessary.", **p2) , i, 0, 1, 2); i+=1 grid.addWidget(QtWid.QLabel("It wears down the multiplexer.", **p2) , i, 0, 1, 2); i+=1 grid.addItem(QtWid.QSpacerItem(1, 3) , i, 0) ; i+=1 grid.addWidget(self.qlbl_mux_state , i, 0, 1, 2); i+=1 grid.addItem(QtWid.QSpacerItem(1, 3) , i, 0) ; i+=1 grid.addWidget(self.qpbt_start_scan , i, 0, 1, 2); i+=1 grid.addItem(QtWid.QSpacerItem(1, 4) , i, 0) ; i+=1 grid.addWidget(QtWid.QLabel("SCPI scan commands:"), i, 0, 1, 2); i+=1 grid.addWidget(self.qpte_SCPI_commands , i, 0, 1, 2); i+=1 grid.addWidget(QtWid.QLabel("Scanning interval [ms]"), i, 0) grid.addWidget(self.qled_scanning_interval_ms , i, 1) ; i+=1 grid.addWidget(QtWid.QLabel("Obtained [ms]") , i, 0) grid.addWidget(self.qled_obtained_interval_ms , i, 1) ; i+=1 grid.addWidget(self.qpbt_reinit , i, 0, 1, 2); i+=1 grid.addItem(QtWid.QSpacerItem(1, 12) , i, 0) ; i+=1 grid.addWidget(QtWid.QLabel("Errors:") , i, 0, 1, 2); i+=1 grid.addWidget(self.qpte_errors , i, 0, 1, 2); i+=1 grid.addWidget(self.qpbt_ackn_errors , i, 0, 1, 2); i+=1 grid.addWidget(self.qlbl_update_counter , i, 0, 1, 2); i+=1 # grid.addWidget(self.qpbt_debug_test , i, 0, 1, 2); i+=1 # fmt: on # Table widget containing the readings of the current scan cycle # ---------------------------------------------------------------- self.qtbl_readings = QtWid.QTableWidget(columnCount=1) self.qtbl_readings.setHorizontalHeaderLabels(["Readings"]) self.qtbl_readings.horizontalHeaderItem(0).setFont(FONT_MONOSPACE_SMALL) self.qtbl_readings.verticalHeader().setFont(FONT_MONOSPACE_SMALL) self.qtbl_readings.verticalHeader().setDefaultSectionSize(24) self.qtbl_readings.setFont(FONT_MONOSPACE_SMALL) # self.qtbl_readings.setMinimumHeight(600) self.qtbl_readings.setFixedWidth(180) self.qtbl_readings.setColumnWidth(0, 110) grid.addWidget(self.qtbl_readings, 0, 2, i, 1) self.qgrp = QtWid.QGroupBox("%s" % self.dev.name) self.qgrp.setStyleSheet(SS_GROUP) self.qgrp.setLayout(grid)
def create_GUI(self): # Safety p = { "alignment": QtCore.Qt.AlignRight, "minimumWidth": 60, "maximumWidth": 30, } self.safe_sens = QtWid.QLineEdit("nan", **p, readOnly=True) self.safe_temp = QtWid.QLineEdit("nan", **p, readOnly=True) self.sub_temp = QtWid.QLineEdit("nan", **p) self.sub_temp.editingFinished.connect(self.send_sub_temp_from_textbox) self.over_temp = QtWid.QLineEdit("nan", **p) self.over_temp.editingFinished.connect( self.send_over_temp_from_textbox) # Control self.pbtn_running = create_Toggle_button("OFFLINE") self.pbtn_running.clicked.connect(self.process_pbtn_running) self.send_setpoint = QtWid.QLineEdit("nan", **p) self.send_setpoint.editingFinished.connect( self.send_setpoint_from_textbox) self.read_setpoint = QtWid.QLineEdit("nan", **p, readOnly=True) self.bath_temp = QtWid.QLineEdit("nan", **p, readOnly=True) self.pt100_temp = QtWid.QLineEdit("nan", **p, readOnly=True) self.status = QtWid.QPlainTextEdit(maximumWidth=180, readOnly=True) self.status.setStyleSheet(SS_TEXTBOX_ERRORS) self.update_counter = QtWid.QLabel("0") i = 0 p = {"alignment": QtCore.Qt.AlignLeft} lbl_temp_unit = "\u00b0%s" % self.dev.state.temp_unit # fmt: off grid = QtWid.QGridLayout() grid.setVerticalSpacing(4) grid.addWidget(QtWid.QLabel("<b>Safety</b>"), i, 0, 1, 3) i += 1 grid.addItem(QtWid.QSpacerItem(1, 6), i, 0) i += 1 grid.addWidget(QtWid.QLabel("Safe sensor"), i, 0) grid.addWidget(self.safe_sens, i, 1) grid.addWidget(QtWid.QLabel(lbl_temp_unit), i, 2) i += 1 grid.addWidget(QtWid.QLabel("Safe temp."), i, 0) grid.addWidget(self.safe_temp, i, 1) grid.addWidget(QtWid.QLabel(lbl_temp_unit), i, 2) i += 1 grid.addWidget(QtWid.QLabel("Sub temp."), i, 0) grid.addWidget(self.sub_temp, i, 1) grid.addWidget(QtWid.QLabel(lbl_temp_unit), i, 2) i += 1 grid.addWidget(QtWid.QLabel("Over temp."), i, 0) grid.addWidget(self.over_temp, i, 1) grid.addWidget(QtWid.QLabel(lbl_temp_unit), i, 2) i += 1 grid.addItem(QtWid.QSpacerItem(1, 10), i, 0) i += 1 grid.addWidget(QtWid.QLabel("<b>Control</b>"), i, 0, 1, 3) i += 1 grid.addItem(QtWid.QSpacerItem(1, 6), i, 0) i += 1 grid.addWidget(self.pbtn_running, i, 0, 1, 3) i += 1 grid.addItem(QtWid.QSpacerItem(1, 8), i, 0) i += 1 grid.addWidget(QtWid.QLabel("Send setpoint"), i, 0) grid.addWidget(self.send_setpoint, i, 1) grid.addWidget(QtWid.QLabel(lbl_temp_unit), i, 2) i += 1 grid.addWidget(QtWid.QLabel("Read setpoint"), i, 0) grid.addWidget(self.read_setpoint, i, 1) grid.addWidget(QtWid.QLabel(lbl_temp_unit), i, 2) i += 1 grid.addItem(QtWid.QSpacerItem(1, 8), i, 0) i += 1 grid.addWidget(QtWid.QLabel("Bath temp."), i, 0) grid.addWidget(self.bath_temp, i, 1) grid.addWidget(QtWid.QLabel(lbl_temp_unit), i, 2) i += 1 grid.addWidget(QtWid.QLabel("Pt100 temp."), i, 0) grid.addWidget(self.pt100_temp, i, 1) grid.addWidget(QtWid.QLabel(lbl_temp_unit), i, 2) i += 1 grid.addItem(QtWid.QSpacerItem(1, 8), i, 0) i += 1 grid.addWidget(QtWid.QLabel("Status"), i, 0, 1, 3) i += 1 grid.addWidget(self.status, i, 0, 1, 3) i += 1 grid.addItem(QtWid.QSpacerItem(1, 4), i, 0) i += 1 grid.addWidget(self.update_counter, i, 0, 1, 3) i += 1 # fmt: on grid.setColumnStretch(0, 0) grid.setColumnStretch(1, 0) grid.setColumnStretch(2, 1) grid.setAlignment(QtCore.Qt.AlignTop) self.grid = grid self.grpb = QtWid.QGroupBox("%s" % self.dev.name) self.grpb.setLayout(self.grid)
def create_GUI(self): # Measure p = {"alignment": QtCore.Qt.AlignRight, "font": FONT_MONOSPACE} self.V_meas = QtWid.QLabel("0.00 V ", **p) self.I_meas = QtWid.QLabel("0.000 A ", **p) self.P_meas = QtWid.QLabel("0.00 W ", **p) # Source p = {"maximumWidth": 60, "alignment": QtCore.Qt.AlignRight} self.pbtn_ENA_output = create_Toggle_button("Output OFF") self.V_source = QtWid.QLineEdit("0.00", **p) self.I_source = QtWid.QLineEdit("0.000", **p) self.P_source = QtWid.QLineEdit("0.00", **p) self.pbtn_ENA_PID = create_Toggle_button( "OFF", minimumHeight=28, minimumWidth=60 ) # Protection self.OVP_level = QtWid.QLineEdit("0.000", **p) self.pbtn_ENA_OCP = create_Toggle_button( "OFF", minimumHeight=28, minimumWidth=60 ) # Questionable condition status registers self.status_QC_OV = create_tiny_error_LED() self.status_QC_OC = create_tiny_error_LED() self.status_QC_PF = create_tiny_error_LED() self.status_QC_OT = create_tiny_error_LED() self.status_QC_INH = create_tiny_error_LED() self.status_QC_UNR = create_tiny_error_LED() # Operation condition status registers self.status_OC_WTG = create_tiny_error_LED() self.status_OC_CV = create_tiny_error_LED() self.status_OC_CC = create_tiny_error_LED() # Final elements self.errors = QtWid.QLineEdit("") self.errors.setStyleSheet(SS_TEXTBOX_ERRORS) self.pbtn_ackn_errors = QtWid.QPushButton("Acknowledge errors") self.pbtn_reinit = QtWid.QPushButton("Reinitialize") self.pbtn_save_defaults = QtWid.QPushButton("Save") self.pbtn_debug_test = QtWid.QPushButton("Debug test") self.lbl_update_counter = QtWid.QLabel("0") i = 0 p = {"alignment": QtCore.Qt.AlignLeft + QtCore.Qt.AlignVCenter} grid = QtWid.QGridLayout() grid.setVerticalSpacing(0) # fmt: off grid.addWidget(self.V_meas , i, 0, 1, 4); i+=1 grid.addWidget(self.I_meas , i, 0, 1, 4); i+=1 grid.addWidget(self.P_meas , i, 0, 1, 4); i+=1 grid.addItem(QtWid.QSpacerItem(1, 8) , i, 0) ; i+=1 grid.addWidget(self.pbtn_ENA_output , i, 0, 1, 4); i+=1 grid.addItem(QtWid.QSpacerItem(1, 10) , i, 0) ; i+=1 grid.addWidget(QtWid.QLabel("Source:") , i, 0, 1, 4); i+=1 grid.addItem(QtWid.QSpacerItem(1, 4) , i, 0) ; i+=1 grid.addWidget(QtWid.QLabel("Voltage") , i, 0, 1, 2) grid.addWidget(self.V_source , i, 2) grid.addWidget(QtWid.QLabel("V", **p) , i, 3) ; i+=1 grid.addItem(QtWid.QSpacerItem(1, 2) , i, 0) ; i+=1 grid.addWidget(QtWid.QLabel("Current") , i, 0, 1, 2) grid.addWidget(self.I_source , i, 2) grid.addWidget(QtWid.QLabel("A", **p) , i, 3) ; i+=1 grid.addItem(QtWid.QSpacerItem(1, 2) , i, 0) ; i+=1 grid.addWidget(QtWid.QLabel("Power PID") , i, 0, 1, 2) grid.addWidget(self.pbtn_ENA_PID , i, 2, QtCore.Qt.AlignLeft); i+=1 grid.addItem(QtWid.QSpacerItem(1, 2) , i, 0) ; i+=1 grid.addWidget(QtWid.QLabel("Power") , i, 0, 1, 2) grid.addWidget(self.P_source , i, 2) grid.addWidget(QtWid.QLabel("W", **p) , i, 3) ; i+=1 grid.addItem(QtWid.QSpacerItem(1, 10) , i, 0) ; i+=1 grid.addWidget(QtWid.QLabel("Protection:") , i, 0, 1, 4); i+=1 grid.addItem(QtWid.QSpacerItem(1, 4) , i, 0) ; i+=1 grid.addWidget(QtWid.QLabel("OVP") , i, 0, 1, 2) grid.addWidget(self.OVP_level , i, 2) grid.addWidget(QtWid.QLabel("V", **p) , i, 3) ; i+=1 grid.addItem(QtWid.QSpacerItem(1, 2) , i, 0) ; i+=1 grid.addWidget(QtWid.QLabel("OCP") , i, 0, 1, 2) grid.addWidget(self.pbtn_ENA_OCP , i, 2, QtCore.Qt.AlignLeft); i+=1 grid.addItem(QtWid.QSpacerItem(1, 10) , i, 0) ; i+=1 grid.addWidget(self.status_QC_OV , i, 0) grid.addWidget(QtWid.QLabel("OV") , i, 1) grid.addWidget(QtWid.QLabel("| over-voltage") , i, 2, 1, 2); i+=1 grid.addWidget(self.status_QC_OC , i, 0) grid.addWidget(QtWid.QLabel("OC") , i, 1) grid.addWidget(QtWid.QLabel("| over-current") , i, 2, 1, 2); i+=1 grid.addWidget(self.status_QC_PF , i, 0) grid.addWidget(QtWid.QLabel("PF") , i, 1) grid.addWidget(QtWid.QLabel("| AC power failure"), i, 2, 1, 2); i+=1 grid.addWidget(self.status_QC_OT , i, 0) grid.addWidget(QtWid.QLabel("OT") , i, 1) grid.addWidget(QtWid.QLabel("| over-temperature"), i, 2, 1, 2); i+=1 grid.addWidget(self.status_QC_INH , i, 0) grid.addWidget(QtWid.QLabel("INH") , i, 1) grid.addWidget(QtWid.QLabel("| output inhibited"), i, 2, 1, 2); i+=1 grid.addWidget(self.status_QC_UNR , i, 0) grid.addWidget(QtWid.QLabel("UNR") , i, 1) grid.addWidget(QtWid.QLabel("| unregulated") , i, 2, 1, 2); i+=1 grid.addItem(QtWid.QSpacerItem(1, 10) , i, 0) ; i+=1 grid.addWidget(self.status_OC_WTG , i, 0) grid.addWidget(QtWid.QLabel("WTG") , i, 1) grid.addWidget(QtWid.QLabel("| waiting for trigger"), i, 2, 1, 2); i+=1 grid.addWidget(self.status_OC_CV , i, 0) grid.addWidget(QtWid.QLabel("CV") , i, 1) grid.addWidget(QtWid.QLabel("| constant voltage"), i, 2, 1, 2); i+=1 grid.addWidget(self.status_OC_CC , i, 0) grid.addWidget(QtWid.QLabel("CC") , i, 1) grid.addWidget(QtWid.QLabel("| constant current"), i, 2, 1, 2); i+=1 grid.addItem(QtWid.QSpacerItem(1, 10) , i, 0) ; i+=1 grid.addWidget(QtWid.QLabel("Errors") , i, 0, 1, 2) grid.addWidget(self.errors , i, 2, 1, 2); i+=1 grid.addItem(QtWid.QSpacerItem(1, 4) , i, 0) ; i+=1 grid.addWidget(self.pbtn_ackn_errors , i, 0, 1, 4); i+=1 hbox = QtWid.QHBoxLayout() hbox.addWidget(self.pbtn_save_defaults) hbox.addWidget(self.pbtn_reinit) grid.addLayout(hbox , i, 0, 1, 4); i+=1 grid.addItem(QtWid.QSpacerItem(1, 4) , i, 0) ; i+=1 grid.addWidget(self.lbl_update_counter , i, 0, 1, 4); i+=1 # grid.addWidget(self.pbtn_debug_test , i, 0, 1, 4); i+=1 # fmt: on grid.setColumnStretch(0, 0) grid.setColumnStretch(1, 0) grid.setColumnStretch(2, 0) grid.setColumnStretch(3, 1) grid.setAlignment(QtCore.Qt.AlignTop) # grid.setAlignment(QtCore.Qt.AlignLeft) self.grid = grid self.grpb = QtWid.QGroupBox("%s" % self.dev.name) self.grpb.setStyleSheet(SS_GROUP) self.grpb.setLayout(self.grid)
def create_GUI(self): # Measure p = {"alignment": QtCore.Qt.AlignCenter, "font": FONT_MONOSPACE} self.V_meas = QtWid.QLabel(" 0.000 V", **p) self.I_meas = QtWid.QLabel(" 0.000 A", **p) self.P_meas = QtWid.QLabel(" 0.000 W", **p) # Source p = {"maximumWidth": 60, "alignment": QtCore.Qt.AlignRight} self.pbtn_ENA_output = create_Toggle_button("Output OFF") self.pbtn_ENA_output.clicked.connect(self.process_pbtn_ENA_output) self.V_source = QtWid.QLineEdit("0.000", **p) self.V_source.editingFinished.connect(self.send_V_source_from_textbox) self.I_source = QtWid.QLineEdit("0.000", **p) self.I_source.editingFinished.connect(self.send_I_source_from_textbox) # Protection self.OVP_level = QtWid.QLineEdit("0.0", **p) self.OVP_level.editingFinished.connect( self.send_OVP_level_from_textbox) self.OCP_level = QtWid.QLineEdit("0.00", **p) self.OCP_level.editingFinished.connect( self.send_OCP_level_from_textbox) # Trips # self.status_LSR_TRIP_AUX = create_tiny_error_LED() self.status_LSR_TRIP_SENSE = create_tiny_error_LED() self.status_LSR_TRIP_OTP = create_tiny_error_LED() self.status_LSR_TRIP_OCP = create_tiny_error_LED() self.status_LSR_TRIP_OVP = create_tiny_error_LED() # Modes # self.status_LSR_MODE_AUX_CC = create_tiny_error_LED() self.status_LSR_MODE_CC = create_tiny_error_LED() self.status_LSR_MODE_CV = create_tiny_error_LED() # Final elements self.pbtn_reset_trips = QtWid.QPushButton("Reset trips") self.pbtn_reset_trips.clicked.connect(self.process_pbtn_reset_trips) self.pbtn_save_settings = QtWid.QPushButton("Save settings") self.pbtn_save_settings.clicked.connect( self.process_pbtn_save_settings) self.pbtn_load_settings = QtWid.QPushButton("Load settings") self.pbtn_load_settings.clicked.connect( self.process_pbtn_load_settings) self.lbl_update_counter = QtWid.QLabel("0") i = 0 p = {"alignment": QtCore.Qt.AlignLeft + QtCore.Qt.AlignVCenter} grid = QtWid.QGridLayout() grid.setVerticalSpacing(0) # fmt: off grid.addWidget(self.V_meas, i, 0, 1, 4) i += 1 grid.addWidget(self.I_meas, i, 0, 1, 4) i += 1 grid.addWidget(self.P_meas, i, 0, 1, 4) i += 1 grid.addItem(QtWid.QSpacerItem(1, 8), i, 0) i += 1 grid.addWidget(self.pbtn_ENA_output, i, 0, 1, 4) i += 1 grid.addItem(QtWid.QSpacerItem(1, 10), i, 0) i += 1 grid.addWidget(QtWid.QLabel("Source:"), i, 0, 1, 4) i += 1 grid.addItem(QtWid.QSpacerItem(1, 4), i, 0) i += 1 grid.addWidget(QtWid.QLabel("Voltage"), i, 0, 1, 2) grid.addWidget(self.V_source, i, 2) grid.addWidget(QtWid.QLabel("V", **p), i, 3) i += 1 grid.addItem(QtWid.QSpacerItem(1, 2), i, 0) i += 1 grid.addWidget(QtWid.QLabel("Current"), i, 0, 1, 2) grid.addWidget(self.I_source, i, 2) grid.addWidget(QtWid.QLabel("A", **p), i, 3) i += 1 grid.addItem(QtWid.QSpacerItem(1, 10), i, 0) i += 1 grid.addWidget(QtWid.QLabel("Protection:"), i, 0, 1, 4) i += 1 grid.addItem(QtWid.QSpacerItem(1, 4), i, 0) i += 1 grid.addWidget(QtWid.QLabel("OVP"), i, 0, 1, 2) grid.addWidget(self.OVP_level, i, 2) grid.addWidget(QtWid.QLabel("V", **p), i, 3) i += 1 grid.addItem(QtWid.QSpacerItem(1, 2), i, 0) i += 1 grid.addWidget(QtWid.QLabel("OCP"), i, 0, 1, 2) grid.addWidget(self.OCP_level, i, 2) grid.addWidget(QtWid.QLabel("A", **p), i, 3) i += 1 grid.addItem(QtWid.QSpacerItem(1, 10), i, 0) i += 1 grid.addWidget(self.status_LSR_TRIP_OVP, i, 0) grid.addWidget(QtWid.QLabel("over-voltage trip"), i, 1, 1, 3) i += 1 grid.addWidget(self.status_LSR_TRIP_OCP, i, 0) grid.addWidget(QtWid.QLabel("over-current trip"), i, 1, 1, 3) i += 1 grid.addWidget(self.status_LSR_TRIP_OTP, i, 0) grid.addWidget(QtWid.QLabel("over-temperature trip"), i, 1, 1, 3) i += 1 grid.addWidget(self.status_LSR_TRIP_SENSE, i, 0) grid.addWidget(QtWid.QLabel("sense trip"), i, 1, 1, 3) i += 1 grid.addItem(QtWid.QSpacerItem(1, 10), i, 0) i += 1 grid.addWidget(self.status_LSR_MODE_CV, i, 0) grid.addWidget(QtWid.QLabel("constant-voltage mode"), i, 1, 1, 3) i += 1 grid.addWidget(self.status_LSR_MODE_CC, i, 0) grid.addWidget(QtWid.QLabel("constant-current mode"), i, 1, 1, 3) i += 1 grid.addItem(QtWid.QSpacerItem(1, 10), i, 0) i += 1 grid.addWidget(self.pbtn_reset_trips, i, 0, 1, 4) i += 1 grid.addItem(QtWid.QSpacerItem(1, 10), i, 0) i += 1 grid.addWidget(self.pbtn_save_settings, i, 0, 1, 4) i += 1 grid.addWidget(self.pbtn_load_settings, i, 0, 1, 4) i += 1 grid.addItem(QtWid.QSpacerItem(1, 4), i, 0) i += 1 grid.addWidget(self.lbl_update_counter, i, 0, 1, 4) i += 1 # fmt: on grid.setColumnStretch(0, 0) grid.setColumnStretch(1, 0) grid.setColumnStretch(2, 0) grid.setColumnStretch(3, 1) grid.setAlignment(QtCore.Qt.AlignTop) # grid.setAlignment(QtCore.Qt.AlignLeft) self.grid = grid self.grpb = QtWid.QGroupBox("%s" % self.dev.name) self.grpb.setLayout(self.grid)
def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setWindowTitle("Dodecahedron control") self.setGeometry(350, 60, 1200, 900) self.setStyleSheet(SS_TEXTBOX_READ_ONLY + SS_GROUP) # ------------------------- # Top frame # ------------------------- # Left box self.qlbl_update_counter = QtWid.QLabel("0") self.qlbl_DAQ_rate = QtWid.QLabel("DAQ: nan Hz") self.qlbl_DAQ_rate.setStyleSheet("QLabel {min-width: 7em}") vbox_left = QtWid.QVBoxLayout() vbox_left.addWidget(self.qlbl_update_counter, stretch=0) vbox_left.addStretch(1) vbox_left.addWidget(self.qlbl_DAQ_rate, stretch=0) # Middle box self.qlbl_title = QtWid.QLabel( "Dodecahedron control", font=QtGui.QFont("Palatino", 14, weight=QtGui.QFont.Bold), ) self.qlbl_title.setAlignment(QtCore.Qt.AlignCenter) self.qlbl_cur_date_time = QtWid.QLabel("00-00-0000 00:00:00") self.qlbl_cur_date_time.setAlignment(QtCore.Qt.AlignCenter) self.qpbt_record = create_Toggle_button( "Click to start recording to file" ) # fmt: off self.qpbt_record.clicked.connect(lambda state: log.record(state)) # pylint: disable=unnecessary-lambda # fmt: on vbox_middle = QtWid.QVBoxLayout() vbox_middle.addWidget(self.qlbl_title) vbox_middle.addWidget(self.qlbl_cur_date_time) vbox_middle.addWidget(self.qpbt_record) # Right box self.qpbt_exit = QtWid.QPushButton("Exit") self.qpbt_exit.clicked.connect(self.close) self.qpbt_exit.setMinimumHeight(30) self.qlbl_recording_time = QtWid.QLabel(alignment=QtCore.Qt.AlignRight) vbox_right = QtWid.QVBoxLayout() vbox_right.addWidget(self.qpbt_exit, stretch=0) vbox_right.addStretch(1) vbox_right.addWidget(self.qlbl_recording_time, stretch=0) # Round up top frame hbox_top = QtWid.QHBoxLayout() hbox_top.addLayout(vbox_left, stretch=0) hbox_top.addStretch(1) hbox_top.addLayout(vbox_middle, stretch=0) hbox_top.addStretch(1) hbox_top.addLayout(vbox_right, stretch=0) # ------------------------- # Bottom frame # ------------------------- # Charts # ------------------------- self.gw = pg.GraphicsLayoutWidget() # Plot: Julabo temperatures p = {"color": "#EEE", "font-size": "10pt"} self.pi_julabo = self.gw.addPlot(row=0, col=0) self.pi_julabo.setLabel("left", text="temperature (°C)", **p) # Plot: Arduino temperatures self.pi_temp = self.gw.addPlot(row=1, col=0) self.pi_temp.setLabel("left", text="temperature (°C)", **p) # Plot: Arduino humidity self.pi_humi = self.gw.addPlot(row=2, col=0) self.pi_humi.setLabel("left", text="humidity (%)", **p) # Plot: Arduino pressure self.pi_pres = self.gw.addPlot(row=3, col=0) self.pi_pres.setLabel("left", text="pressure (mbar)", **p) self.plots = [self.pi_julabo, self.pi_temp, self.pi_humi, self.pi_pres] for plot in self.plots: plot.setClipToView(True) plot.showGrid(x=1, y=1) plot.setLabel("bottom", text="history (s)", **p) plot.setMenuEnabled(True) plot.enableAutoRange(axis=pg.ViewBox.XAxis, enable=False) plot.enableAutoRange(axis=pg.ViewBox.YAxis, enable=True) plot.setAutoVisible(y=True) plot.setRange(xRange=[-CHART_HISTORY_TIME, 0]) # Curves capacity = round(CHART_HISTORY_TIME * 1e3 / DAQ_INTERVAL_MS) PEN_01 = pg.mkPen(color=[255, 255, 0], width=3) PEN_02 = pg.mkPen(color=[252, 15, 192], width=3) PEN_03 = pg.mkPen(color=[0, 255, 255], width=3) PEN_04 = pg.mkPen(color=[255, 255, 255], width=3) PEN_05 = pg.mkPen(color=[255, 127, 39], width=3) PEN_06 = pg.mkPen(color=[0, 255, 0], width=3) self.tscurve_julabo_setp = HistoryChartCurve( capacity=capacity, linked_curve=self.pi_julabo.plot(pen=PEN_05, name="Julabo setp."), ) self.tscurve_julabo_bath = HistoryChartCurve( capacity=capacity, linked_curve=self.pi_julabo.plot(pen=PEN_06, name="Julabo bath"), ) self.tscurve_ds_temp = HistoryChartCurve( capacity=capacity, linked_curve=self.pi_temp.plot(pen=PEN_01, name="DS temp."), ) self.tscurve_bme_temp = HistoryChartCurve( capacity=capacity, linked_curve=self.pi_temp.plot(pen=PEN_02, name="BME temp."), ) self.tscurve_bme_humi = HistoryChartCurve( capacity=capacity, linked_curve=self.pi_humi.plot(pen=PEN_03, name="BME humi."), ) self.tscurve_bme_pres = HistoryChartCurve( capacity=capacity, linked_curve=self.pi_pres.plot(pen=PEN_04, name="BME pres."), ) self.tscurves = [ self.tscurve_julabo_setp, self.tscurve_julabo_bath, self.tscurve_ds_temp, self.tscurve_bme_temp, self.tscurve_bme_humi, self.tscurve_bme_pres, ] # Group `Readings` # ------------------------- legend = LegendSelect( linked_curves=self.tscurves, hide_toggle_button=True ) p = { "readOnly": True, "alignment": QtCore.Qt.AlignRight, "maximumWidth": 54, } self.qlin_ds_temp = QtWid.QLineEdit(**p) self.qlin_bme_temp = QtWid.QLineEdit(**p) self.qlin_bme_humi = QtWid.QLineEdit(**p) self.qlin_bme_pres = QtWid.QLineEdit(**p) # fmt: off legend.grid.setHorizontalSpacing(6) legend.grid.addWidget(self.qlin_ds_temp , 2, 2) legend.grid.addWidget(QtWid.QLabel("± 0.5 °C"), 2, 3) legend.grid.addWidget(self.qlin_bme_temp , 3, 2) legend.grid.addWidget(QtWid.QLabel("± 0.5 °C"), 3, 3) legend.grid.addWidget(self.qlin_bme_humi , 4, 2) legend.grid.addWidget(QtWid.QLabel("± 3 %") , 4, 3) legend.grid.addWidget(self.qlin_bme_pres , 5, 2) legend.grid.addWidget(QtWid.QLabel("± 1 mbar"), 5, 3) # fmt: on qgrp_readings = QtWid.QGroupBox("Readings") qgrp_readings.setLayout(legend.grid) # Group 'Log comments' # ------------------------- self.qtxt_comments = QtWid.QTextEdit() grid = QtWid.QGridLayout() grid.addWidget(self.qtxt_comments, 0, 0) qgrp_comments = QtWid.QGroupBox("Log comments") qgrp_comments.setLayout(grid) # Group 'Charts' # ------------------------- self.plot_manager = PlotManager(parent=self) self.plot_manager.add_autorange_buttons(linked_plots=self.plots) self.plot_manager.add_preset_buttons( linked_plots=self.plots, linked_curves=self.tscurves, presets=[ { "button_label": "01:00", "x_axis_label": "history (sec)", "x_axis_divisor": 1, "x_axis_range": (-60, 0), }, { "button_label": "10:00", "x_axis_label": "history (min)", "x_axis_divisor": 60, "x_axis_range": (-10, 0), }, { "button_label": "30:00", "x_axis_label": "history (min)", "x_axis_divisor": 60, "x_axis_range": (-30, 0), }, { "button_label": "60:00", "x_axis_label": "history (min)", "x_axis_divisor": 60, "x_axis_range": (-60, 0), }, { "button_label": "120:00", "x_axis_label": "history (min)", "x_axis_divisor": 60, "x_axis_range": (-120, 0), }, ], ) self.plot_manager.add_clear_button(linked_curves=self.tscurves) self.plot_manager.perform_preset(1) qgrp_chart = QtWid.QGroupBox("Charts") qgrp_chart.setLayout(self.plot_manager.grid) vbox = QtWid.QVBoxLayout() vbox.addWidget(qgrp_readings) vbox.addWidget(qgrp_comments) vbox.addWidget(qgrp_chart, alignment=QtCore.Qt.AlignLeft) vbox.addStretch() # Round up bottom frame hbox_bot = QtWid.QHBoxLayout() hbox_bot.addWidget(self.gw, 1) hbox_bot.addLayout(vbox, 0) hbox_bot.addWidget( qdev_julabo.grpb, alignment=QtCore.Qt.AlignTop, stretch=0 ) # ------------------------- # Round up full window # ------------------------- vbox = QtWid.QVBoxLayout(self) vbox.addLayout(hbox_top, stretch=0) vbox.addSpacerItem(QtWid.QSpacerItem(0, 10)) vbox.addLayout(hbox_bot, stretch=1)
def create_GUI(self): # Groupbox "Alarm values" # ----------------------- p = { "alignment": QtCore.Qt.AlignRight, "minimumWidth": 50, "maximumWidth": 30, "readOnly": True, } self.LO_flow = QtWid.QLineEdit(**p) self.HI_flow = QtWid.QLineEdit(**p) self.LO_pres = QtWid.QLineEdit(**p) self.HI_pres = QtWid.QLineEdit(**p) self.LO_temp = QtWid.QLineEdit(**p) self.HI_temp = QtWid.QLineEdit(**p) self.pbtn_read_alarm_values = QtWid.QPushButton("Read") self.pbtn_read_alarm_values.setMinimumSize(50, 30) p = {"alignment": QtCore.Qt.AlignCenter} grid = QtWid.QGridLayout() # fmt: off grid.addWidget( QtWid.QLabel("Values can be set in the chiller's menu", **p), 0, 0, 1, 4) grid.addWidget(QtWid.QLabel("LO"), 1, 1) grid.addWidget(QtWid.QLabel("HI"), 1, 2) grid.addWidget(QtWid.QLabel("Flow rate"), 2, 0) grid.addWidget(self.LO_flow, 2, 1) grid.addWidget(self.HI_flow, 2, 2) grid.addWidget(QtWid.QLabel("LPM"), 2, 3) grid.addWidget(QtWid.QLabel("Pressure"), 3, 0) grid.addWidget(self.LO_pres, 3, 1) grid.addWidget(self.HI_pres, 3, 2) grid.addWidget(QtWid.QLabel("bar"), 3, 3) grid.addWidget(QtWid.QLabel("Temperature"), 4, 0) grid.addWidget(self.LO_temp, 4, 1) grid.addWidget(self.HI_temp, 4, 2) grid.addWidget(QtWid.QLabel(CHAR_DEG_C), 4, 3) grid.addWidget(self.pbtn_read_alarm_values, 5, 0) # fmt: on self.grpb_alarms = QtWid.QGroupBox("Alarm values") self.grpb_alarms.setStyleSheet(SS_GROUP) self.grpb_alarms.setLayout(grid) # Groupbox "PID feedback" # ----------------------- p = { "alignment": QtCore.Qt.AlignRight, "minimumWidth": 50, "maximumWidth": 30, "readOnly": True, } self.PID_P = QtWid.QLineEdit(**p) self.PID_I = QtWid.QLineEdit(**p) self.PID_D = QtWid.QLineEdit(**p) self.pbtn_read_PID_values = QtWid.QPushButton("Read") self.pbtn_read_PID_values.setMinimumSize(50, 30) p = {"alignment": QtCore.Qt.AlignCenter} grid = QtWid.QGridLayout() # fmt: off grid.addWidget( QtWid.QLabel("Values can be set in the chiller's menu", **p), 0, 0, 1, 3) grid.addWidget(QtWid.QLabel("P", **p), 1, 0) grid.addWidget(self.PID_P, 1, 1) grid.addWidget(QtWid.QLabel("% span of 100" + CHAR_DEG_C), 1, 2) grid.addWidget(QtWid.QLabel("I", **p), 2, 0) grid.addWidget(self.PID_I, 2, 1) grid.addWidget(QtWid.QLabel("repeats/minute"), 2, 2) grid.addWidget(QtWid.QLabel("D", **p), 3, 0) grid.addWidget(self.PID_D, 3, 1) grid.addWidget(QtWid.QLabel("minutes"), 3, 2) grid.addWidget(self.pbtn_read_PID_values, 4, 0) # fmt: on self.grpb_PID = QtWid.QGroupBox("PID feedback") self.grpb_PID.setStyleSheet(SS_GROUP) self.grpb_PID.setLayout(grid) # Groupbox "Status bits" # ---------------------- # fmt: off self.SB_tripped = create_error_LED() self.SB_tripped.setText("No faults") self.SB_high_temp_fixed = create_tiny_error_LED() self.SB_low_temp_fixed = create_tiny_error_LED() self.SB_high_temp = create_tiny_error_LED() self.SB_low_temp = create_tiny_error_LED() self.SB_high_pressure = create_tiny_error_LED() self.SB_low_pressure = create_tiny_error_LED() self.SB_drip_pan = create_tiny_error_LED() self.SB_high_level = create_tiny_error_LED() self.SB_phase_monitor = create_tiny_error_LED() self.SB_motor_overload = create_tiny_error_LED() self.SB_LPC = create_tiny_error_LED() self.SB_HPC = create_tiny_error_LED() self.SB_external_EMO = create_tiny_error_LED() self.SB_local_EMO = create_tiny_error_LED() self.SB_low_flow = create_tiny_error_LED() self.SB_low_level = create_tiny_error_LED() self.SB_sense_5V = create_tiny_error_LED() self.SB_invalid_level = create_tiny_error_LED() self.SB_low_fixed_flow_warning = create_tiny_error_LED() self.SB_high_pressure_factory = create_tiny_error_LED() self.SB_low_pressure_factory = create_tiny_error_LED() p = {'alignment': QtCore.Qt.AlignRight} grid = QtWid.QGridLayout() grid.addWidget(self.SB_tripped, 0, 0, 1, 2) grid.addItem(QtWid.QSpacerItem(1, 12), 1, 0) grid.addWidget(QtWid.QLabel("high temp fixed fault", **p), 2, 0) grid.addWidget(self.SB_high_temp_fixed, 2, 1) grid.addWidget(QtWid.QLabel("low temp fixed fault", **p), 3, 0) grid.addWidget(self.SB_low_temp_fixed, 3, 1) grid.addWidget(QtWid.QLabel("high temp fault/warning", **p), 4, 0) grid.addWidget(self.SB_high_temp, 4, 1) grid.addWidget(QtWid.QLabel("low temp fault/warning", **p), 5, 0) grid.addWidget(self.SB_low_temp, 5, 1) grid.addWidget(QtWid.QLabel("high pressure fault/warning", **p), 6, 0) grid.addWidget(self.SB_high_pressure, 6, 1) grid.addWidget(QtWid.QLabel("low pressure fault/warning", **p), 7, 0) grid.addWidget(self.SB_low_pressure, 7, 1) grid.addWidget(QtWid.QLabel("drip pan fault", **p), 8, 0) grid.addWidget(self.SB_drip_pan, 8, 1) grid.addWidget(QtWid.QLabel("high level fault", **p), 9, 0) grid.addWidget(self.SB_high_level, 9, 1) grid.addWidget(QtWid.QLabel("phase monitor fault", **p), 10, 0) grid.addWidget(self.SB_phase_monitor, 10, 1) grid.addWidget(QtWid.QLabel("motor overload fault", **p), 11, 0) grid.addWidget(self.SB_motor_overload, 11, 1) grid.addWidget(QtWid.QLabel("LPC fault", **p), 12, 0) grid.addWidget(self.SB_LPC, 12, 1) grid.addWidget(QtWid.QLabel("HPC fault", **p), 13, 0) grid.addWidget(self.SB_HPC, 13, 1) grid.addWidget(QtWid.QLabel("external EMO fault", **p), 14, 0) grid.addWidget(self.SB_external_EMO, 14, 1) grid.addWidget(QtWid.QLabel("local EMO fault", **p), 15, 0) grid.addWidget(self.SB_local_EMO, 15, 1) grid.addWidget(QtWid.QLabel("low flow fault", **p), 16, 0) grid.addWidget(self.SB_low_flow, 16, 1) grid.addWidget(QtWid.QLabel("low level fault", **p), 17, 0) grid.addWidget(self.SB_low_level, 17, 1) grid.addWidget(QtWid.QLabel("sense 5V fault", **p), 18, 0) grid.addWidget(self.SB_sense_5V, 18, 1) grid.addWidget(QtWid.QLabel("invalid level fault", **p), 19, 0) grid.addWidget(self.SB_invalid_level, 19, 1) grid.addWidget(QtWid.QLabel("low fixed flow warning", **p), 20, 0) grid.addWidget(self.SB_low_fixed_flow_warning, 20, 1) grid.addWidget(QtWid.QLabel("high pressure factory fault", **p), 21, 0) grid.addWidget(self.SB_high_pressure_factory, 21, 1) grid.addWidget(QtWid.QLabel("low pressure factory fault", **p), 22, 0) grid.addWidget(self.SB_low_pressure_factory, 22, 1) # fmt: on self.grpb_SBs = QtWid.QGroupBox("Status bits") self.grpb_SBs.setStyleSheet(SS_GROUP) self.grpb_SBs.setLayout(grid) # Groupbox "Control" # ------------------ p = { "alignment": QtCore.Qt.AlignRight, "minimumWidth": 50, "maximumWidth": 30, } self.lbl_offline = QtWid.QLabel( "OFFLINE", visible=False, font=QtGui.QFont("Palatino", 14, weight=QtGui.QFont.Bold), alignment=QtCore.Qt.AlignCenter, ) # fmt: off self.pbtn_on = create_Toggle_button("Off") self.powering_down = create_tiny_error_LED() self.send_setpoint = QtWid.QLineEdit(**p) self.read_setpoint = QtWid.QLineEdit(**p, readOnly=True) self.read_temp = QtWid.QLineEdit(**p, readOnly=True) self.read_flow = QtWid.QLineEdit(**p, readOnly=True) self.read_supply = QtWid.QLineEdit(**p, readOnly=True) self.read_suction = QtWid.QLineEdit(**p, readOnly=True) self.lbl_update_counter = QtWid.QLabel("0") grid = QtWid.QGridLayout() grid.addWidget(self.lbl_offline, 0, 0, 1, 3) grid.addWidget(self.pbtn_on, 1, 0, 1, 3) grid.addWidget( QtWid.QLabel("Is powering up/down?", alignment=QtCore.Qt.AlignRight), 2, 0, 1, 2) grid.addWidget(self.powering_down, 2, 2) grid.addItem(QtWid.QSpacerItem(1, 12), 3, 0) grid.addWidget(QtWid.QLabel("Send setpoint"), 4, 0) grid.addWidget(QtWid.QLabel("Read setpoint"), 5, 0) grid.addWidget(self.send_setpoint, 4, 1) grid.addWidget(self.read_setpoint, 5, 1) grid.addWidget(QtWid.QLabel(CHAR_DEG_C), 4, 2) grid.addWidget(QtWid.QLabel(CHAR_DEG_C), 5, 2) grid.addItem(QtWid.QSpacerItem(1, 12), 6, 0) grid.addWidget(QtWid.QLabel("Read temp"), 7, 0) grid.addWidget(self.read_temp, 7, 1) grid.addWidget(QtWid.QLabel(CHAR_DEG_C), 7, 2) grid.addWidget(QtWid.QLabel("Read flow"), 8, 0) grid.addWidget(self.read_flow, 8, 1) grid.addWidget(QtWid.QLabel("LPM"), 8, 2) grid.addWidget(QtWid.QLabel("Read supply"), 9, 0) grid.addWidget(self.read_supply, 9, 1) grid.addWidget(QtWid.QLabel("bar"), 9, 2) grid.addWidget(QtWid.QLabel("Read suction"), 10, 0) grid.addWidget(self.read_suction, 10, 1) grid.addWidget(QtWid.QLabel("bar"), 10, 2) grid.addItem(QtWid.QSpacerItem(1, 12), 11, 0) grid.addWidget(QtWid.QLabel("Nominal values @ 15-02-2018:"), 12, 0, 1, 3) grid.addWidget(QtWid.QLabel("Read flow"), 13, 0) grid.addWidget(QtWid.QLabel("80 ", alignment=QtCore.Qt.AlignRight), 13, 1) grid.addWidget(QtWid.QLabel("LPM"), 13, 2) grid.addWidget(QtWid.QLabel("Read supply"), 14, 0) grid.addWidget(QtWid.QLabel("2.9 ", alignment=QtCore.Qt.AlignRight), 14, 1) grid.addWidget(QtWid.QLabel("bar"), 14, 2) grid.addWidget(QtWid.QLabel("Read suction"), 15, 0) grid.addWidget(QtWid.QLabel("40 ", alignment=QtCore.Qt.AlignRight), 15, 1) grid.addWidget(QtWid.QLabel("bar"), 15, 2) grid.addWidget(self.lbl_update_counter, 16, 0, 1, 2) # fmt: on self.grpb_control = QtWid.QGroupBox("Control") self.grpb_control.setStyleSheet(SS_GROUP) self.grpb_control.setLayout(grid) # -------------------------------------- # Round up final QtWid.QHBoxLayout() # -------------------------------------- vbox = QtWid.QVBoxLayout() vbox.addWidget(self.grpb_alarms) vbox.addWidget(self.grpb_PID) vbox.setAlignment(self.grpb_alarms, QtCore.Qt.AlignTop) vbox.setAlignment(self.grpb_PID, QtCore.Qt.AlignTop) vbox.setAlignment(QtCore.Qt.AlignTop) self.hbly_GUI = QtWid.QHBoxLayout() self.hbly_GUI.addLayout(vbox) self.hbly_GUI.addWidget(self.grpb_SBs) self.hbly_GUI.addWidget(self.grpb_control) self.hbly_GUI.addStretch(1) self.hbly_GUI.setAlignment(self.grpb_SBs, QtCore.Qt.AlignTop) self.hbly_GUI.setAlignment(self.grpb_control, QtCore.Qt.AlignTop) self.hbly_GUI.setAlignment(QtCore.Qt.AlignTop)
def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setWindowTitle("E. coli sauna") self.setGeometry(350, 50, 960, 800) self.setStyleSheet(SS_TEXTBOX_READ_ONLY + SS_GROUP) # ------------------------- # Top frame # ------------------------- # Left box self.qlbl_update_counter = QtWid.QLabel("0") self.qlbl_DAQ_rate = QtWid.QLabel("DAQ: nan Hz") self.qlbl_DAQ_rate.setStyleSheet("QLabel {min-width: 7em}") vbox_left = QtWid.QVBoxLayout() vbox_left.addWidget(self.qlbl_update_counter, stretch=0) vbox_left.addStretch(1) vbox_left.addWidget(self.qlbl_DAQ_rate, stretch=0) # Middle box self.qlbl_title = QtWid.QLabel( "", font=QtGui.QFont("Palatino", 14, weight=QtGui.QFont.Bold), ) self.qlbl_title.setAlignment(QtCore.Qt.AlignCenter) self.qlbl_cur_date_time = QtWid.QLabel("00-00-0000 00:00:00") self.qlbl_cur_date_time.setAlignment(QtCore.Qt.AlignCenter) self.qpbt_record = create_Toggle_button( "Click to start recording to file") self.qlbl_warning = QtWid.QLabel( "Do not exceed 5.5 W as the heaters will reach >90 °C.", font=QtGui.QFont("Palatino", 8, weight=QtGui.QFont.Bold), ) self.qlbl_warning.setStyleSheet( "QLabel {color: darkred; alignment: AlignCenter}") self.qlbl_warning.setAlignment(QtCore.Qt.AlignCenter) self.qpbt_record.clicked.connect(lambda state: log.record(state)) vbox_middle = QtWid.QVBoxLayout() vbox_middle.addWidget(self.qlbl_title) vbox_middle.addWidget(self.qlbl_cur_date_time) vbox_middle.addWidget(self.qpbt_record) vbox_middle.addWidget(self.qlbl_warning) # Right box self.qpbt_exit = QtWid.QPushButton("Exit") self.qpbt_exit.clicked.connect(self.close) self.qpbt_exit.setMinimumHeight(30) self.qlbl_recording_time = QtWid.QLabel(alignment=QtCore.Qt.AlignRight) vbox_right = QtWid.QVBoxLayout() vbox_right.addWidget(self.qpbt_exit, stretch=0) vbox_right.addStretch(1) vbox_right.addWidget(self.qlbl_recording_time, stretch=0) # Round up top frame hbox_top = QtWid.QHBoxLayout() hbox_top.addLayout(vbox_left, stretch=0) hbox_top.addStretch(1) hbox_top.addLayout(vbox_middle, stretch=0) hbox_top.addStretch(1) hbox_top.addLayout(vbox_right, stretch=0) # ------------------------- # Bottom frame # ------------------------- # Group 'PID control' # ------------------------- p = { "alignment": QtCore.Qt.AlignRight, "maximumWidth": 48, } self.qpbt_pid_enabled = create_Toggle_button("PID OFF") self.qpbt_pid_enabled.clicked.connect( lambda state: self.process_qpbt_pid_enabled(state)) self.qlin_pid_temp_setp = QtWid.QLineEdit("%.1f" % PID_TEMP_SETPOINT, **p) self.qlin_pid_temp_setp.editingFinished.connect( self.process_qlin_pid_temp_setp) self.qlin_pid_Kp = QtWid.QLineEdit("%.1f" % PID_Kp, **p) self.qlin_pid_Kp.editingFinished.connect(self.process_qlin_pid_Kp) self.qlin_pid_Ki = QtWid.QLineEdit("%.0e" % PID_Ki, **p) self.qlin_pid_Ki.editingFinished.connect(self.process_qlin_pid_Ki) self.qlin_pid_V_clamp = QtWid.QLineEdit("%.1f" % PID_V_clamp, **p) self.qlin_pid_V_clamp.editingFinished.connect( self.process_qlin_pid_V_clamp) # fmt: off grid = QtWid.QGridLayout() grid.setVerticalSpacing(2) grid.addWidget(self.qpbt_pid_enabled, 0, 0, 1, 3) grid.addItem(QtWid.QSpacerItem(1, 2), 1, 0) grid.addWidget(QtWid.QLabel("Setpoint"), 2, 0) grid.addWidget(self.qlin_pid_temp_setp, 2, 1) grid.addWidget(QtWid.QLabel("°C"), 2, 2) grid.addItem(QtWid.QSpacerItem(1, 10), 3, 0) grid.addWidget(QtWid.QLabel("Parameters:"), 4, 0, 1, 3) grid.addItem(QtWid.QSpacerItem(1, 4), 5, 0) grid.addWidget(QtWid.QLabel("K_p"), 6, 0) grid.addWidget(self.qlin_pid_Kp, 6, 1) grid.addWidget(QtWid.QLabel("K_i"), 7, 0) grid.addWidget(self.qlin_pid_Ki, 7, 1) grid.addWidget(QtWid.QLabel("1/s"), 7, 2) grid.addWidget(QtWid.QLabel("Output clamp"), 8, 0) grid.addWidget(self.qlin_pid_V_clamp, 8, 1) grid.addWidget(QtWid.QLabel("V"), 8, 2) # fmt: on qgrp_PID = QtWid.QGroupBox("PID feedback") qgrp_PID.setLayout(grid) self.vbox_control = QtWid.QVBoxLayout() self.vbox_control.addWidget(qdev_psu.grpb, stretch=0) self.vbox_control.addWidget(qgrp_PID, stretch=0) self.vbox_control.addStretch() # Charts # ------------------------- self.gw = pg.GraphicsLayoutWidget() # Plot: Temperatures p = {"color": "#EEE", "font-size": "10pt"} self.pi_temp = self.gw.addPlot(row=0, col=0) self.pi_temp.setLabel("left", text="temperature (°C)", **p) # Plot: Humidity self.pi_humi = self.gw.addPlot(row=1, col=0) self.pi_humi.setLabel("left", text="humidity (%)", **p) # Plot: heater power self.pi_power = self.gw.addPlot(row=2, col=0) self.pi_power.setLabel("left", text="power (W)", **p) self.plots = [self.pi_temp, self.pi_humi, self.pi_power] for plot in self.plots: plot.setClipToView(True) plot.showGrid(x=1, y=1) plot.setLabel("bottom", text="history (s)", **p) plot.setMenuEnabled(True) plot.enableAutoRange(axis=pg.ViewBox.XAxis, enable=False) plot.enableAutoRange(axis=pg.ViewBox.YAxis, enable=True) plot.setAutoVisible(y=True) plot.setRange(xRange=[-CHART_HISTORY_TIME, 0]) # Curves capacity = round(CHART_HISTORY_TIME * 1e3 / DAQ_INTERVAL_MS) PEN_01 = pg.mkPen(color=[255, 255, 0], width=3) PEN_02 = pg.mkPen(color=[0, 255, 255], width=3) PEN_03 = pg.mkPen(color=[255, 0, 0], width=3) self.tscurve_dht22_temp = HistoryChartCurve( capacity=capacity, linked_curve=self.pi_temp.plot(pen=PEN_01, name="temperature"), ) self.tscurve_dht22_humi = HistoryChartCurve( capacity=capacity, linked_curve=self.pi_humi.plot(pen=PEN_02, name="humidity"), ) self.tscurve_power = HistoryChartCurve( capacity=capacity, linked_curve=self.pi_power.plot(pen=PEN_03, name="heater power"), ) self.tscurves = [ self.tscurve_dht22_temp, self.tscurve_dht22_humi, self.tscurve_power, ] # Group `Readings` # ------------------------- legend = LegendSelect(linked_curves=self.tscurves, hide_toggle_button=True) p = { "readOnly": True, "alignment": QtCore.Qt.AlignRight, "maximumWidth": 54, } self.qlin_ds_temp = QtWid.QLineEdit(**p) self.qlin_dht22_temp = QtWid.QLineEdit(**p) self.qlin_dht22_humi = QtWid.QLineEdit(**p) self.qlin_power = QtWid.QLineEdit(**p) # fmt: off legend.grid.setHorizontalSpacing(6) legend.grid.addWidget(self.qlin_dht22_temp, 0, 2) legend.grid.addWidget(QtWid.QLabel("± 0.5 °C"), 0, 3) legend.grid.addWidget(self.qlin_dht22_humi, 1, 2) legend.grid.addWidget(QtWid.QLabel("± 3 %"), 1, 3) legend.grid.addWidget(self.qlin_power, 2, 2) legend.grid.addWidget(QtWid.QLabel("± 0.05 W"), 2, 3) # fmt: on qgrp_readings = QtWid.QGroupBox("Readings") qgrp_readings.setLayout(legend.grid) # Group 'Log comments' # ------------------------- self.qtxt_comments = QtWid.QTextEdit() grid = QtWid.QGridLayout() grid.addWidget(self.qtxt_comments, 0, 0) qgrp_comments = QtWid.QGroupBox("Log comments") qgrp_comments.setLayout(grid) # Group 'Charts' # ------------------------- self.plot_manager = PlotManager(parent=self) self.plot_manager.add_autorange_buttons(linked_plots=self.plots) self.plot_manager.add_preset_buttons( linked_plots=self.plots, linked_curves=self.tscurves, presets=[ { "button_label": "03:00", "x_axis_label": "history (sec)", "x_axis_divisor": 60, "x_axis_range": (-3, 0), }, { "button_label": "10:00", "x_axis_label": "history (min)", "x_axis_divisor": 60, "x_axis_range": (-10, 0), }, { "button_label": "30:00", "x_axis_label": "history (min)", "x_axis_divisor": 60, "x_axis_range": (-30, 0), }, { "button_label": "60:00", "x_axis_label": "history (min)", "x_axis_divisor": 60, "x_axis_range": (-60, 0), }, { "button_label": "120:00", "x_axis_label": "history (min)", "x_axis_divisor": 60, "x_axis_range": (-120, 0), }, ], ) self.plot_manager.add_clear_button(linked_curves=self.tscurves) self.plot_manager.perform_preset(1) qgrp_chart = QtWid.QGroupBox("Charts") qgrp_chart.setLayout(self.plot_manager.grid) vbox = QtWid.QVBoxLayout() vbox.addWidget(qgrp_readings) vbox.addWidget(qgrp_comments) vbox.addWidget(qgrp_chart, alignment=QtCore.Qt.AlignLeft) vbox.addStretch() # ------------------------- # Round up full window # ------------------------- self.hbox_bot = QtWid.QHBoxLayout() self.hbox_bot.addLayout(self.vbox_control, 0) self.hbox_bot.addWidget(self.gw, 1) self.hbox_bot.addLayout(vbox, 0) vbox = QtWid.QVBoxLayout(self) vbox.addLayout(hbox_top, stretch=0) vbox.addSpacerItem(QtWid.QSpacerItem(0, 10)) vbox.addLayout(self.hbox_bot, stretch=1)