added README.md, complete the influx for V2

This commit is contained in:
Ryan Tang 2024-07-31 16:16:51 -05:00
parent 760e2387d7
commit 6bbf93bf7d
5 changed files with 266 additions and 26 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
__pycache__
*.txt
*.csv

211
HVGUI.py
View File

@ -3,22 +3,59 @@
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
ColStrList = ["Name", "Ch", 'On/Off', "Set V [V]", "Set I [uA]", "Out V [V]", "Out I [uA]"]
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 = []
@ -26,6 +63,7 @@ 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'))
@ -37,7 +75,7 @@ class MyWindow(QMainWindow):
super().__init__()
self.setWindowTitle("Iseg Controller")
self.setGeometry(100, 100, 500, 200)
self.setGeometry(100, 100, 600, 200)
widget = QWidget()
layout = QVBoxLayout()
@ -56,6 +94,34 @@ class MyWindow(QMainWindow):
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, 1, 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, 1, 1)
self.chkDB = QCheckBox("Enable DataBase Output", self)
gLayout.addWidget(self.chkDB, 0, 2)
#=========== set tab
self.tabWidget = QTabWidget(self)
layout.addWidget(self.tabWidget)
@ -74,7 +140,12 @@ class MyWindow(QMainWindow):
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:
@ -110,7 +181,7 @@ class MyWindow(QMainWindow):
# #------------ V out
if j == 5:
self.txtVOut[k][i].setText("{:.2f}".format(outVList[k][i]))
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)
@ -118,21 +189,41 @@ class MyWindow(QMainWindow):
# #------------ I out
if j == 6:
self.txtIOut[k][i].setText("{:.2f}".format(outIList[k][i]))
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))
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 : darkgreen;")
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):
@ -147,6 +238,15 @@ class MyWindow(QMainWindow):
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())
@ -168,31 +268,100 @@ class MyWindow(QMainWindow):
#---------------------------------
def updateTimer(self):
self.time += 1
print(f'Time: {self.time}')
# outVList = mpod.GetAllOutputHV()
# outIList = mpod.GetAllLC()
# # print(outVList)
# 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 = []
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("{:.2f}".format(outVList[k][i]))
self.txtIOut[k][i].setText("{:.2f}".format(outIList[k][i]))
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("Ch",int(chList[i] + 100 * k)).field("value",float(outVList[i])))
# points.append(Point("LeakageCurrent").tag("Ch",int(chList[i] + 100 * k)).field("value",float(outIList[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)
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)

View File

@ -98,6 +98,9 @@ class Channel:
return get_value(self.bdCh + "PDown")
def SetName(self, name : str):
set_value(self.bdCh + "Name", name)
def SetV0Set(self, volt: float):
set_value(self.bdCh + "V0Set", volt)
@ -164,3 +167,13 @@ class Board:
for i in range(48):
pvList.append('solarisHV:' + self.id + ":" + f"{i:03d}" + ":" + PV_Name)
return epics.caget_many(pvList)
def PutPV(self, PV_Name : str, ValueList ):
pvList = []
for i in range(48):
pvList.append('solarisHV:' + self.id + ":" + f"{i:03d}" + ":" + PV_Name)
if len(ValueList) == len(pvList):
epics.caput_many(pvList, ValueList)
else:
print("PutPV: Value List size does not match channel number")

28
README.md Normal file
View File

@ -0,0 +1,28 @@
# About
This is a HV controller for the python Qt6 GUI for CAEN SY4527 + A4528 CPU module. It communicate the built-in EPICS server to control and retrive parameters. It can also push the current Voltage and leakage current to influxDB via network connection.
# Require package
in Ubuntu 20+
~>sudo apt install python3-pyqt6 snmp snmp-mibs-downloader curl python3-pip
~>python3 -m pip install pyqt6 influxdb-client
# Code
### HVLibrary.py
this is the library to setup the basic of epics. User need to modify the IP and hostName.
### HVGUI.py
this is the GUI code.
# DataBase connection
The program use the influxdb_client to push data to a influx database. In influxDB V2, a token is needed for secure connection. For security, a token should be save in INFLUX_TOKEN.txt, the program will load it for token. The IP address, org, bucket are hardcoded, so please change it as needed.
# Usage
~>./HVGUI.py

35
test.py
View File

@ -52,6 +52,10 @@ import HVLibrary as hv
# hv.epics.caput('solarisHV:03:015:Pw', 1)
# hv.epics.cainfo('solarisHV:03:015:Pw')
# hv.epics.cainfo('solarisHV:03:015:VMon')
# hv.epics.cainfo('solarisHV:03:015:V0Set')
# hv.epics.cainfo('solarisHV:03:015:Status')
# hv.epics.cainfo('solarisHV:03:BdStatus')
# m1 = hv.epics.caget('solarisHV:03:015:Pw', use_monitor= False)
@ -66,10 +70,31 @@ import HVLibrary as hv
# hv.epics.camonitor('solarisHV:03:015:Pw')
pvList = []
for i in range(48):
pvList.append('solarisHV:03:' + f"{i:03d}" + ":VMon")
# pvList = []
# pvValue = []
# for i in range(10):
# pvList.append('solarisHV:03:' + f"{i:03d}" + ":V0Set")
# pvValue.append(10)
haha = hv.epics.caget_many(pvList)
# # haha = hv.epics.caget_many(pvList)
# haha = hv.epics.caput_many(pvList, pvValue)
# print(haha)
import influxdb_client
from influxdb_client import InfluxDBClient, Point, WritePrecision
from influxdb_client.client.write_api import SYNCHRONOUS, ASYNCHRONOUS
ip = "192.168.0.200:8086"
write_client = influxdb_client.InfluxDBClient(url=ip)
bucket = "HV"
write_api = write_client.write_api(write_options=ASYNCHRONOUS)
points = []
points.append(Point("Voltage").tag("Bd", 3).tag("Ch", 0).field("value",float(10)))
write_api.write(bucket=bucket, record=points)
print(haha)