Source code for pylab_ml.gui.instruments.smu.smu

# -*- coding: utf-8 -*-
"""
This script defines a GUI class for a Source Measure Unit (SMU) instrument, which is part of the PyLab-ML project.
The GUI allows users to interact with the SMU instrument, send MQTT commands, and receive updates.
The class inherits from a base instrument GUI class and implements specific functionality for the SMU instrument.

Created on Mon Jan  3 09:19:17 2022

TODO:
    Bug: no bugs known, but in work.....
"""

import sys
import qdarkstyle

# import numpy as np
import os
from PyQt5 import QtWidgets
from pylab_ml.gui.instruments.base_instrument import Gui as Guibase
from pylab_ml.gui.instruments.base_instrument import load_ui

__author__ = "Zlin526F"
__credits__ = ["Zlin526F"]
__email__ = "Zlin526F@github"
__version__ = "0.0.1"


[docs] class Gui(Guibase): """ This class defines a GUI for a Source Measure Unit (SMU) instrument. Inherited from base_instrument status """ _states = { "connect": ["connect", "color: rgb(0, 255, 0)"], # overwrite the definitions in base_instrument "disconnect": ["disconnect", "color: rgb(255, 0, 0)"], "on": ["running", "color: rgb(0, 255, 0)"], "off": ["waiting for start...", "color: palette(HighlightedText)"], } _color_display_enable = "color: rgb(0, 255, 255);background-color: rgb(0, 0, 0);" _color_display_disable = "color: #d9d9d9;background-color: rgb(0, 0, 0);"
[docs] def __init__(self, parent=None, name="scope", parentwindow=None, channel=None): """ Initialize the GUI for the SMU instrument. Parameters ---------- parent : QWidget, optional The parent widget for the GUI. name : str, optional The name of the instrument. parentwindow : QWidget, optional The parent window for the GUI. channel : int, optional The channel number for the instrument. """ super().__init__(grandparent=parent, name=name, parentwindow=parentwindow) self.myframe = load_ui(self.gui.myframe, __file__) # bgcolor = self.gui.palette().color(QtGui.QPalette.Background).name() # getRgb() self.myadjustUI() self.gui.closeEvent = self.close self.parent = parent self.mqtt_initlist = [ "output_function", "Voltage", "Current", ] # all attributes do you need for the initialisation from mqtt. Widgets start with MQTT will add automaticaly' self.smustatus = ""
# self.gui.myframe.setEnabled(True)
[docs] def myadjustUI(self): """Adjust the GUI elements for the SMU instrument.""" # set icons: self.gui.runToolBar.setVisible(False) # self.add_menuicon('onoff') # add existing icon and connection from the base-instrument self.myframe.MQTT_SET_voltage.setKeyboardTracking(False) # QDoubleSpinBox end input with return self.myframe.MQTT_i_clamp.setKeyboardTracking(False) self.myframe.MQTT_stime.setKeyboardTracking(False) self.myframe.MQTT_sweepto.setKeyboardTracking(False) # set connection fom Gui-object (widgets) to functions: self.myframe.sweep.stateChanged.connect(lambda: self.sweep(self.myframe.sweep)) # QCheckBox self.mqttConnectWidgets() # connect all widget which the objectname start with MQTT # connect Gui-objects (widgets) to own ('complex') functions widget = self.myframe.output_function widget.activated.connect(lambda widget, obj=widget: self.gui2mqtt(obj)) self._output_function = -1 self.output_function = "DC_VOLTAGE" self.myframe.PBsweep.clicked.connect(self.gui2sweep) self.myframe.MQTT_sweepto.valueChanged.disconnect() # connect Gui-objects (widgets) with a mouse click to get a mqtt message self.myframe.mousePressEvent = self.mqttMeasureEvent self.sweep(self.myframe.sweep) geometry = self.gui.geometry() wh = self.myframe.geometry() self.gui.setWindowTitle(f' {os.path.basename(__file__).split(".")[0]} (Version: {__version__})') self.myframe.setGeometry(geometry.x(), geometry.y(), wh.width() + 100, wh.height() + 250)
[docs] def mqttMeasureEvent(self, event): """Handle mouse press events on the main frame by publishing MQTT commands to measure and check completion.""" self.grandparent.mqtt.publish_get(self.instName, "measure") self.grandparent.mqtt.publish_get(self.instName, "cmpl")
# ====================================================== # attributes which connect to an extern call (mqtt-command)
[docs] def mqttreceive(self, instName, msg): """ Common MQTT receive messages, get raw MQTT data for more information. Parameters ---------- instName : str The name of the instrument. msg : dict The MQTT message received. """ self.logger.debug(f" {instName}.mqttreceive: {msg} ") if super().mqttreceive(instName, msg): return self.logger.debug(f" {instName}.mqttreceive: continue search ... with {msg} ") # if you change with the mqtt command a widget, you have to use the widget.blockSignals(True/False) if "cmd" in tuple(msg.keys()) and "payload" in tuple(msg.keys()): value = msg["payload"] if msg["cmd"] == "measure": # special handling from mqtt commands # self.myframe.MQTT_GET_current.blockSignals(True) self.myframe.MQTT_GET_voltage.setProperty("value", value[0]) self.myframe.MQTT_GET_current.setProperty("value", value[1]) elif msg["cmd"] == "Voltage": self.myframe.MQTT_SET_voltage.blockSignals(True) self.myframe.MQTT_SET_voltage.setProperty("value", value) self.myframe.MQTT_SET_voltage.blockSignals(False) # self.logger.info(f" {instName}: {msg['cmd']} should do something with value = {value} -> implement it !!!!!!!!!!!!!!!!!") elif msg["cmd"] == "Current": self.myframe.MQTT_SET_current.blockSignals(True) self.myframe.MQTT_SET_current.setProperty("value", value) self.myframe.MQTT_SET_current.blockSignals(False) else: self.logger.warning(f" {instName} {msg['cmd']} not found -> do nothing")
# ====================================================================================== # definitions from 'complex' mqtt commands, if you need only a connection between the mqtt-command and a widget, start the name of your widget with MQTT_ @property def channel(self): """Get the current channel of the instrument.""" return self.id @channel.setter def channel(self, msg): """Set the current channel of the instrument.""" self.id = msg @property def output_function(self): # connect to QCombobox """Get the current output function of the instrument.""" return self._output_function # if self.gui.output_function.currentIndex() != self._output_function: # self.publish_set(self.gui.output_function.currentText()) @output_function.setter def output_function(self, val): """Set the current output function of the instrument.""" if val.find("DC_VOLTAGE") == 0 and self._output_function != 0: self.myframe.MQTT_SET_voltage.show() self.myframe.MQTT_SET_current.hide() self.myframe.MQTT_v_range.show() self.myframe.MQTT_i_range.hide() self.myframe.MQTT_i_clamp.show() self.myframe.MQTT_v_clamp.hide() self.myframe.MQTT_I_range.show() self.myframe.MQTT_V_range.hide() self.myframe.Lfunction.setText("Voltage") self.myframe.Llimit.setText("Current") self.myframe.MQTT_SET_voltage.setSuffix(" V") self.myframe.MQTT_sweepto.setSuffix(" V") self.myframe.MQTT_i_clamp.setSuffix(" A") self.myframe.si1.setText("V") self.myframe.si2.setText("A") self._output_function = 0 self.myframe.output_function.setCurrentIndex(0) elif val.find("DC_CURRENT") == 0 and self._output_function != 1: self.myframe.MQTT_SET_voltage.hide() self.myframe.MQTT_SET_current.show() self.myframe.MQTT_v_range.hide() self.myframe.MQTT_i_range.show() self.myframe.MQTT_i_clamp.hide() self.myframe.MQTT_v_clamp.show() self.myframe.MQTT_I_range.hide() self.myframe.MQTT_V_range.show() self.myframe.Lfunction.setText("Current") self.myframe.Llimit.setText("Voltage") self.myframe.MQTT_SET_current.setSuffix(" A") self.myframe.MQTT_sweepto.setSuffix(" A") self.myframe.MQTT_v_clamp.setSuffix(" V") self.myframe.si1.setText("V") self.myframe.si2.setText("A") self._output_function = 1 self.myframe.output_function.setCurrentIndex(1) self.sweep(self.myframe.sweep) @property def cmpl(self): pass @cmpl.setter def cmpl(self, val): if self._output_function == 0 and val: self.myframe.Lcmpl.setStyleSheet(self._color_display_enable) self.myframe.Lcc.setStyleSheet(self._color_display_enable) self.myframe.Lcv.setStyleSheet(self._color_display_disable) elif self._output_function == 1 and val: self.myframe.Lcmpl.setStyleSheet(self._color_display_enable) self.myframe.Lcc.setStyleSheet(self._color_display_disable) self.myframe.Lcv.setStyleSheet(self._color_display_enable) else: self.myframe.Lcmpl.setStyleSheet(self._color_display_disable) self.myframe.Lcc.setStyleSheet(self._color_display_disable) self.myframe.Lcv.setStyleSheet(self._color_display_disable) # end extern calling attributes (mqtt) # ====================================================================================== # # connected GUI-function to buttons or menues #
[docs] def gui2sweep(self): """Handle the click event of the sweep button by publishing MQTT commands to set the voltage or current based on the selected output function.""" if self._output_function == 0: self.publish("voltage", [self.myframe.MQTT_SET_voltage.value(), self.myframe.MQTT_sweepto.value()]) elif self._output_function == 1: self.publish("current", [self.myframe.MQTT_SET_current.value(), self.myframe.MQTT_sweepto.value()])
[docs] def close(self, event=None): """Handle the close event for the GUI by publishing an 'off' command and then calling the base class's close method.""" self.publish("off()") super().close()
@property def smustatus(self): """Get the current status of the SMU.""" return self._smustatus @smustatus.setter def smustatus(self, msg): """Set the current status of the SMU and update the GUI.""" if msg != "": print("Error: {}".format(msg)) # self.gui.status.setText(self._translate("Form", "Current")) self.myframe.status.setText(msg) self._smustatus = msg
[docs] def sweep(self, b): """Handle the state change of the sweep checkbox and show/hide related GUI elements accordingly.""" if b.isChecked(): self.myframe.Lfrom.show() self.myframe.Lto.show() self.myframe.MQTT_SET_voltage.blockSignals(True) self.myframe.MQTT_SET_current.blockSignals(True) self.myframe.MQTT_sweepto.show() self.myframe.Ltime.show() self.myframe.MQTT_stime.show() self.myframe.PBsweep.show() else: self.myframe.Lfrom.hide() self.myframe.Lto.hide() self.myframe.MQTT_SET_voltage.blockSignals(False) self.myframe.MQTT_SET_current.blockSignals(False) self.myframe.MQTT_sweepto.hide() self.myframe.Ltime.hide() self.myframe.MQTT_stime.hide() self.myframe.PBsweep.hide()
if __name__ == "__main__": # from pylab_ml.common.mqtt_client import mqtt_init # broker = 127.0.0.1' # message_client = 'ate/DT1604092/matrix' # mqttclient = mqtt_init() # prepare mqtt # mqttclient.init(None, message_client=message_client.split('/')[0]) # mqtt client connect to broker # mqttclient.init() app = QtWidgets.QApplication(sys.argv) app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5()) window = Gui(app) app.exec_() # window.scope.anim.event_source.stop()