#!/usr/bin/python3 import HVLibrary as hv import sys import datetime import csv import socket import time print("================== SOLARIS HV Controller for CAEN SY4527") #-----------assign a port, to prevent the script run mulitple time s = socket.socket() host = socket.gethostname() port = 4305 s.bind((host,port)) #------ database import influxdb_client from influxdb_client import InfluxDBClient, Point, WritePrecision from influxdb_client.client.write_api import SYNCHRONOUS, ASYNCHRONOUS with open('INFLUX_TOKEN.txt', 'r') as f: token = f.readline().replace('\n', '') org = "Argonne National Laboratory" databaseIP = "http://192.168.0.200:8086" write_client = influxdb_client.InfluxDBClient(url=databaseIP, token=token, org=org) bucket = "CAEN_SY4527" write_api = write_client.write_api(write_options=ASYNCHRONOUS) print("------- Database") print(" IP : " + databaseIP) print(" Buket : " + bucket) print(" token : " + token) pushToDB = False print("--------- Generating GUI") #------ GUI from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QCheckBox, QLineEdit, QLabel, QVBoxLayout, QWidget, QTabWidget, QGridLayout, QMessageBox, QFileDialog, QProgressBar from PyQt6.QtCore import Qt, QThread, QTimer, QObject, pyqtSignal from functools import partial nMod = 2 nChPerMod = [48, 48] updateTime = 3 #sec ###################################### bd = [] for k in range(nMod): bd.append(hv.Board(3 + k)) ColStrList = ["Name", "Ch", 'On/Off', "Set V [V]", "Set I [uA]", "Out V [V]", "Out I [uA]"] NameList = [] V0SetList = [] I0SetList = [] OnOffList = [] outVList = [] outIList = [] for k in range(nMod): NameList.append(bd[k].GetPV('Name')) V0SetList.append(bd[k].GetPV('V0Set')) I0SetList.append(bd[k].GetPV('I0Set')) OnOffList.append(bd[k].GetPV('Pw')) outVList.append(bd[k].GetPV('VMon')) outIList.append(bd[k].GetPV('IMon')) class MyWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Iseg Controller") self.setGeometry(100, 100, 600, 200) widget = QWidget() layout = QVBoxLayout() widget.setLayout(layout) self.setCentralWidget(widget) self.txtName = [[QLineEdit() for _ in range(rows)] for rows in nChPerMod] self.txtV = [[QLineEdit() for _ in range(rows)] for rows in nChPerMod] self.txtI = [[QLineEdit() for _ in range(rows)] for rows in nChPerMod] self.txtVOut = [[QLineEdit() for _ in range(rows)] for rows in nChPerMod] self.txtIOut = [[QLineEdit() for _ in range(rows)] for rows in nChPerMod] self.chkON = [[QCheckBox() for _ in range(rows)] for rows in nChPerMod] self.timer = QTimer(self) self.timer.timeout.connect(self.updateTimer) self.timer.start(updateTime*1000) self.time = 0 #=========== database and refresh time gLayout = QGridLayout() layout.addLayout(gLayout) # lbIP = QLabel("Database IP : ", self) # lbIP.setAlignment(Qt.AlignmentFlag.AlignRight) # gLayout.addWidget(lbIP, 0, 0) # self.txtIP = QLineEdit(self) # self.txtIP.setText(IP) # self.txtIP.textChanged.connect(partial(self.TextChange, self.txtIP)) # self.txtIP.returnPressed.connect(partial(self.UnSetTextColor, self.txtIP)) # gLayout.addWidget(self.txtIP, 0, 1) lb1 = QLabel("Refresh period [sec] :", self) lb1.setAlignment(Qt.AlignmentFlag.AlignRight) gLayout.addWidget(lb1, 0, 0) self.txtRefresh = QLineEdit(self) self.txtRefresh.setText(str(updateTime)) self.txtRefresh.textChanged.connect(partial(self.TextChange, self.txtRefresh)) self.txtRefresh.returnPressed.connect(self.SetTimer) self.txtRefresh.returnPressed.connect(partial(self.UnSetTextColor, self.txtRefresh)) gLayout.addWidget(self.txtRefresh, 0, 1) self.chkDB = QCheckBox("Enable DataBase Output", self) gLayout.addWidget(self.chkDB, 0, 2) #=========== set tab self.tabWidget = QTabWidget(self) layout.addWidget(self.tabWidget) for k in range(0, nMod): tab = QWidget(self) layout_tab = QGridLayout() layout_tab.setAlignment(Qt.AlignmentFlag.AlignTop) tab.setLayout(layout_tab) for index, lb in enumerate(ColStrList): qlb = QLabel(lb, tab) layout_tab.addWidget(qlb, 0, index) for i in range(nChPerMod[k]) : for j, lb in enumerate(ColStrList) : #------------ name if j == 0: self.txtName[k][i].setText(NameList[k][i]) layout_tab.addWidget(self.txtName[k][i], 1+i, j) self.txtName[k][i].returnPressed.connect(partial(self.SetName, k, i) ) self.txtName[k][i].returnPressed.connect(partial(self.UnSetTextColor, self.txtName[k][i])) self.txtName[k][i].textChanged.connect(partial(self.TextChange, self.txtName[k][i])) #------------ Ch if j == 1: qlb = QLabel(str(i), tab) layout_tab.addWidget(qlb, 1+i, j, alignment=Qt.AlignmentFlag.AlignCenter) #------------ On/Off if j == 2: self.chkON[k][i].setChecked( OnOffList[k][i] == 1) layout_tab.addWidget(self.chkON[k][i], 1+i, j, alignment=Qt.AlignmentFlag.AlignCenter) self.chkON[k][i].clicked.connect(partial(self.SetOnOff, k, i)) # #------------ V set if j == 3: self.txtV[k][i].setText(str(V0SetList[k][i])) self.txtV[k][i].setAlignment(Qt.AlignmentFlag.AlignRight) layout_tab.addWidget(self.txtV[k][i], 1+i, j) self.txtV[k][i].returnPressed.connect(partial(self.SetHV, k, i) ) self.txtV[k][i].returnPressed.connect(partial(self.UnSetTextColor, self.txtV[k][i])) self.txtV[k][i].textChanged.connect(partial(self.TextChange, self.txtV[k][i])) # #------------ I set if j == 4: self.txtI[k][i].setText(str(I0SetList[k][i])) self.txtI[k][i].setAlignment(Qt.AlignmentFlag.AlignRight) layout_tab.addWidget(self.txtI[k][i], 1+i, j) self.txtI[k][i].returnPressed.connect(partial(self.SetI, k, i) ) self.txtI[k][i].returnPressed.connect(partial(self.UnSetTextColor, self.txtI[k][i])) self.txtI[k][i].textChanged.connect(partial(self.TextChange, self.txtI[k][i])) # #------------ V out if j == 5: self.txtVOut[k][i].setText("{:.3f}".format(outVList[k][i])) self.txtVOut[k][i].setAlignment(Qt.AlignmentFlag.AlignRight) layout_tab.addWidget(self.txtVOut[k][i], 1+i, j) self.txtVOut[k][i].setReadOnly(True) self.txtVOut[k][i].setStyleSheet("background-color: lightgrey; color: black;") # #------------ I out if j == 6: self.txtIOut[k][i].setText("{:.3f}".format(outIList[k][i])) self.txtIOut[k][i].setAlignment(Qt.AlignmentFlag.AlignRight) layout_tab.addWidget(self.txtIOut[k][i], 1+i, j) self.txtIOut[k][i].setReadOnly(True) self.txtIOut[k][i].setStyleSheet("background-color: lightgrey; color: black;") self.tabWidget.addTab(tab, "Mod-" + str(k+3)) #============= Save setting sLayout = QGridLayout() layout.addLayout(sLayout) bLoad = QPushButton("Load", self) bLoad.clicked.connect(self.LoadSetting) sLayout.addWidget(bLoad, 0, 0) self.txtFile = QLineEdit(self) self.txtFile.textChanged.connect(partial(self.TextChange, self.txtFile)) sLayout.addWidget(self.txtFile, 0, 1) bSave = QPushButton("Save", self) bSave.clicked.connect(self.SaveSetting) sLayout.addWidget(bSave, 0, 3) #================================= def UnSetTextColor(self, qLineEdit : QLineEdit): qLineEdit.setStyleSheet("") def TextChange(self, qLineEdit : QLineEdit): qLineEdit.setStyleSheet("color : green;") def SetTimer(self): sec = float(self.txtRefresh.text()) self.timer.stop() self.timer.start(int(sec * 1000)) #--------------------------------- def SetOnOff(self, mod, ch): state = self.chkON[mod][ch].checkState() if state == Qt.CheckState.Checked: bd[mod].Channel[ch].SetPowerOnOff(1) else: bd[mod].Channel[ch].SetPowerOnOff(0) value = bd[mod].Channel[ch].GetPowerOnOff() OnOffList[mod][ch] = value print("mod : " + str(mod) + ", ch : " + str(ch) + " | " + str(state) + " | " + str(value)) self.chkON[mod][ch].setChecked(value == 1) #--------------------------------- def SetName(self, mod, ch): value = self.txtName[mod][ch].text() print("mod : " + str(mod) + ", ch : " + str(ch) + " | " + value) bd[mod].Channel[ch].SetName(value) newValue = bd[mod].Channel[ch].GetName() NameList[mod][ch] = newValue self.txtName[mod][ch].setText(newValue) #--------------------------------- def SetHV(self, mod, ch): value = float(self.txtV[mod][ch].text()) print("mod : " + str(mod) + ", ch : " + str(ch) + " | " + str(value)) bd[mod].Channel[ch].SetV0Set(value) newValue = bd[mod].Channel[ch].GetV0Set() V0SetList[mod][ch] = newValue self.txtV[mod][ch].setText("{:.1f}".format(newValue)) #--------------------------------- def SetI(self, mod, ch): value = float(self.txtI[mod][ch].text()) print("mod : " + str(mod) + ", ch : " + str(ch) + " | " + str(value)) bd[mod].Channel[ch].SetI0Set(value) newValue = bd[mod].Channel[ch].GetI0Set() I0SetList[mod][ch] = newValue self.txtI[mod][ch].setText("{:.1f}".format(newValue)) #--------------------------------- def updateTimer(self): self.time += 1 # print(f'Time: {self.time}') outVList.clear() outIList.clear() for k in range(2): outVList.append(bd[k].GetPV('VMon')) outIList.append(bd[k].GetPV('IMon')) if self.chkDB.checkState() == Qt.CheckState.Checked: points = [] for k in range(0, nMod): for i in range(bd[k].numCh) : self.txtVOut[k][i].setText("{:.3f}".format(outVList[k][i])) self.txtIOut[k][i].setText("{:.3f}".format(outIList[k][i])) if self.chkDB.checkState() == Qt.CheckState.Checked: points.append(Point("Voltage").tag("bd", int(k)).tag("Ch",int(i)).field("value",float(outVList[k][i]))) points.append(Point("LeakageCurrent").tag("bd", int(k)).tag("Ch",int(i)).field("value",float(outIList[k][i]))) if self.chkDB.checkState() == Qt.CheckState.Checked: write_api.write(bucket=bucket, org=org, record=points) def SaveSetting(self): fileName = self.txtFile.text() if fileName == "" : msg_box = QMessageBox() msg_box.setWindowTitle("Information") msg_box.setText("Type file name first, then save.") msg_box.setIcon(QMessageBox.Icon.Information) msg_box.setStandardButtons(QMessageBox.StandardButton.Ok) msg_box.exec() return pos = fileName.rfind('.') if pos == -1: fileName = fileName + ".csv" self.txtFile.setText(fileName) outfile = open(fileName, "w") csv_writer = csv.writer(outfile) for k in range(0, nMod): for i in range(bd[k].numCh) : papap = [str(k), str(i), self.txtName[k][i].text(), self.txtV[k][i].text(),self.txtI[k][i].text()] csv_writer.writerow( papap ) outfile.close() self.txtFile.setStyleSheet("") msg_box = QMessageBox() msg_box.setWindowTitle("Information") msg_box.setText("Setting saved to " + fileName + " as a csv file.") msg_box.setIcon(QMessageBox.Icon.Information) msg_box.setStandardButtons(QMessageBox.StandardButton.Ok) msg_box.exec() def LoadSetting(self): file_path, _ = QFileDialog.getOpenFileName(self, "Open File", "", "CSV Files (*.csv);;All Files (*)") if file_path: infile = open(file_path, "r") csv_reader = csv.reader(infile) row_count = sum(1 for row in csv_reader) infile.seek(0) count = 0 for row in csv_reader: mod = row[0] ch = row[1] if mod.isdigit() and ch.isdigit(): chID = int(ch) modID = int(mod) NameList[modID][chID] = row[2] V0SetList[modID][chID] = float(row[3]) I0SetList[modID][chID] = float(row[4]) for k in range(nMod): bd[k].PutPV('Name', NameList[k]) bd[k].PutPV('V0Set', V0SetList[k]) bd[k].PutPV('I0Set', I0SetList[k]) self.txtFile.setText(file_path) self.txtFile.setStyleSheet("") NameList.clear() V0SetList.clear() I0SetList.clear() for k in range(0, nMod): NameList.append(bd[k].GetPV('Name')) V0SetList.append(bd[k].GetPV('V0Set')) I0SetList.append(bd[k].GetPV('I0Set')) for i in range(bd[k].numCh) : self.txtName[k][i].setText(NameList[k][i]) self.txtV[k][i].setText(str(V0SetList[k][i])) self.txtI[k][i].setText(str(I0SetList[k][i])) self.txtName[k][i].setStyleSheet("") self.txtV[k][i].setStyleSheet("") self.txtI[k][i].setStyleSheet("") if __name__ == "__main__": app = QApplication(sys.argv) window = MyWindow() window.show() sys.exit(app.exec())