Files
hush/src/gui.py

1263 lines
48 KiB
Python

'''The GUI module for Savings Overview and magnet control
'''
import decimal
import getpass
import os
import random
import socket
import threading
import time
from datetime import timedelta
#from qtpy import QtCore, QtGui
from qtpy.QtGui import QColor, QPixmap
from qtpy.QtCore import __version__ as QT_VERSION_STR
from qtpy.QtCore import QEventLoop, Qt, QTimer, Slot
from qtpy.QtWidgets import (
QApplication, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QMessageBox,
QPushButton, QTabBar, QTabWidget, QTableWidgetItem, QTextEdit, QVBoxLayout,
QWidget)
from common.packages import elog
from apps4ops.bdbase.utils import _line
from apps4ops.bdbase.enumkind import MsgSeverity
from caqtwidgets.pvwidgets import (
CAQLabel, CAQLineEdit, CAQMessageButton, CAQTableWidget, CAQTextEntry,
QHLine)
_pymodule = os.path.basename(__file__)
class AppGui(QWidget):
''' Main GUI class
'''
def __init__(self, parent):
#super(AppGui, self).__init__()
# using Python 3 style super() without arguments
super().__init__()
self.parent = parent
self.cafe = self.parent.cafe
self.cyca = self.parent.cyca
self.check_status = self.parent.check_status
self.check_status_list = self.parent.check_status_list
self.elog_enum = self.parent.elog_enum
self.send_to_log_window = self.parent.send_to_log_window
self.show_log_message = self.parent.show_log_message
self.statusbar = self.parent.statusbar
self.gui_frame = self.parent.gui_frame
self.gui_header = self.parent.gui_header
self.font_gui = self.parent.gui_frame.font_gui
self.input_parameters = self.parent.input_parameters
self.input_labels = self.parent.input_labels
self.expert_parameters = self.parent.expert_parameters
self.gui_frame.expert_parameters_group.setFixedWidth(260)
self.gui_frame.expert_parameters_group.setFixedHeight(130)
self.gui_frame.operator_parameters_group.setFixedWidth(260)
self.gui_frame.operator_parameters_group.setFixedHeight(130)
self.gui_frame.measurement_tab_wgt.setFixedWidth(496)
self.gui_frame.measurement_tab_wgt.setFixedHeight(210)
# self.gui_frame.operator_wgt.setFixedHeight(240)
# self.gui_frame.expert_wgt.setFixedHeight(240)
self.gui_frame.central_tab_widget.tabBar().setTabText(0, "Control")
self.gui_frame.central_tab_widget.tabBar().setTabText(1, "IOC")
self.expert_labels = self.parent.expert_labels
self.settings = self.parent.settings
self.lock = threading.Lock()
self.timer = QTimer()
self.timer.setSingleShot(True)
self.obj_to_upper = bool(random.randint(1, 10) > 3)
self.table_sol_dict = {}
self.table_pwr_dict = {}
self.offtime_dict = {}
self.I_min = 1.0
self.with_rf = False
self.sec_state_list = ["ZIP2-HUSH:STATE", "ZIW2-HUSH:STATE",
"ZPK1-HUSH:STATE", "ZPK2-HUSH:STATE",
"ZSINQ-HUSH:STATE", "ZUCN-HUSH:STATE"]
self.cafe.openPrepare()
self.cafe.open(["ZHIPA-HUSH:LASTPWR", "ZHIPA-HUSH:TOTPWR",
"ZHIPA-HUSH:LASTSAVE", "ZHIPA-HUSH:TOTSAVE"])
self.cafe.open(self.sec_state_list)
self.cafe.open("UCN:BEAMREQ:STATUS")
self.cafe.openNowAndWait(0.1)
self.cafe.monitor("UCNQ:BEAMREQ:STATUS")
idx = self.settings.data["header"].index("IP2")
self.sectorI_dict = {}
for sector in self.settings.data["header"][idx:]:
self.sectorI_dict[sector] = 0
self.sector_designated_magnet_standby_dict = {}
self.sector_designated_magnet_values_dict = {}
for sector in self.settings.data["header"][idx:]:
self.sector_designated_magnet_standby_dict[sector] = {}
self.sector_designated_magnet_values_dict[sector] = {}
self.sector_designated_magnet_standby_dict[
sector] = self.get_standby_dict(sector)
self.sector_designated_magnet_values_dict[
sector] = self.get_standby_dict(sector)
print(sector, self.sector_designated_magnet_standby_dict[sector])
wgt = self.group_sector_qtabwidget()
self.gui_frame.measurement_layout.addWidget(
wgt, 0, 1, 6, 3, alignment=Qt.AlignTop)
status_wgt = self.group_sector_status()
self.gui_frame.measurement_layout.addWidget(
status_wgt, 2, 0, 2, 1, alignment=Qt.AlignTop) # | Qt.AlignHCenter)
self.gui_frame.results_wgt.setFixedWidth(1500)
self.gui_frame.results_wgt.setFixedHeight(860)
self.gui_frame.results_wgt.setLayout(self.gui_frame.results_layout)
self.gui_frame.results_layout.addWidget(
self.reset_ioc_sm(), 0, 0, 1, 1, Qt.AlignCenter)
sec_prefix_list = [
sub[0: sub.index("-")] for sub in self.sec_state_list]
self.gui_frame.results_layout.addWidget(
self.reset_ioc_saving(sec_prefix_list), 0, 1, 1, 1, Qt.AlignCenter)
label = QLabel()
pixmap = QPixmap(":/Hush.jpg")
pixmap.scaled(180, 180, Qt.KeepAspectRatio)
label.setFixedWidth(180)
label.setFixedHeight(180)
label.setPixmap(pixmap)
label.setScaledContents(True)
self.gui_frame.results_layout.addWidget(
label, 0, 2, 1, 1, Qt.AlignLeft)
self.gui_frame.results_layout.setContentsMargins(10, 40, 10, 10)
self.gui_frame.results_layout.setVerticalSpacing(20)
self.gui_frame.results_layout.setHorizontalSpacing(10)
self.gui_frame.results_layout.addWidget(
self.reset_lastpwr(), 1, 0, 1, 1,
Qt.AlignmentFlag(Qt.AlignTop | Qt.AlignCenter))
ucn_line = ["PK1", "PK2", "UCN"]
sinq_line = ["PK1", "PK2", "SINQ"]
pk1_line = ["IW2"]
pk2_line = ["IW2"]
for sector in self.settings.data["header"][idx:]:
gateway_indices = self.get_standby_index_list(sector)
for idx in gateway_indices:
pv_name_gw = self.table_sol_dict[sector].pv_gateway[idx].pv_name
pvd = self.cafe.getPVCache(pv_name_gw, dt="float")
#print(sector, "pv_name_gw", pv_name_gw, flush=True)
# pvd.show()
self.table_sol_dict[sector].pv_gateway[
idx].trigger_monitor_float.emit(
pvd.value[0], pvd.status, pvd.alarmSeverity)
def enable_disable_ucn(sect, sector_line, value):
self.sectorI_dict[sect] = value
beam_req_running = True
beam_req_status = self.cafe.getCache("UCNQ:BEAMREQ:STATUS")
#print(" beam_req_status", beam_req_status, flush=True)
if beam_req_status is not None:
if beam_req_status == "stopped":
beam_req_running = False
for sector in sector_line:
beam_req_flag = True
if sector == "UCN":
beam_req_flag = beam_req_running
# if self.sectorI_dict['UCN'] > self.I_min or self.sectorI_dict[
# 'SINQ'] > self.I_min:
if self.sectorI_dict[sector] > self.I_min or beam_req_flag:
if self.table_sol_dict[
sector].standby_value_button.isEnabled():
self.table_sol_dict[
sector].standby_value_button.setEnabled(False)
else:
if not self.table_sol_dict[
sector].standby_value_button.isEnabled():
self.table_sol_dict[
sector].standby_value_button.setEnabled(True)
def enable_disable_end(sect, sector_line, value):
self.sectorI_dict[sect] = value
for sector in sector_line:
# if self.sectorI_dict['UCN'] > self.I_min or self.sectorI_dict[
# 'SINQ'] > self.I_min:
if self.sectorI_dict[sector] > self.I_min:
if self.table_sol_dict[
sector].standby_value_button.isEnabled():
self.table_sol_dict[
sector].standby_value_button.setEnabled(False)
else:
if not self.table_sol_dict[
sector].standby_value_button.isEnabled():
self.table_sol_dict[
sector].standby_value_button.setEnabled(True)
def enable_disable_pk(sect, sector_line, value):
self.sectorI_dict[sect] = value
for sector in sector_line:
if self.sectorI_dict["PK1"] > self.I_min or self.sectorI_dict[
"PK2"] > self.I_min:
if self.table_sol_dict[
sector].standby_value_button.isEnabled():
self.table_sol_dict[
sector].standby_value_button.setEnabled(False)
else:
if not self.table_sol_dict[
sector].standby_value_button.isEnabled():
self.table_sol_dict[
sector].standby_value_button.setEnabled(True)
def receive_ucn_update(value, status, alarm_severity):
del status, alarm_severity
enable_disable_ucn("UCN", ucn_line, value)
def receive_sinq_update(value, status, alarm_severity):
del status, alarm_severity
enable_disable_end("SINQ", sinq_line, value)
def receive_pk1_update(value, status, alarm_severity):
del status, alarm_severity
enable_disable_pk("PK1", pk1_line, value)
def receive_pk2_update(value, status, alarm_severity):
del status, alarm_severity
enable_disable_pk("PK2", pk2_line, value)
self.gui_header.beam_current_wgt_dict[
"UCN"].trigger_monitor_float.connect(receive_ucn_update)
self.gui_header.beam_current_wgt_dict[
"SINQ"].trigger_monitor_float.connect(receive_sinq_update)
self.gui_header.beam_current_wgt_dict[
"PK1"].trigger_monitor_float.connect(receive_pk1_update)
self.gui_header.beam_current_wgt_dict[
"PK2"].trigger_monitor_float.connect(receive_pk2_update)
# Not required any longer
@Slot(int, str, object)
def receive_sec_state(handle, pv, pvdata):
del handle
pvsplit = pv.split("-")
secsplit = pvsplit[0].split("Z")
sec = secsplit[1]
if pvdata.status == self.cyca.ICAFE_CA_OP_CONN_DOWN:
return
# But is SHIFTTYPE CORRECT?
#is_shift_type_ok = True
#shift_type = self.cafe.getCache("ZORG:SHIFT-TYPE", 'str')
# if shift_type is not None:
# if shift_type not in ['Produktion', 'Strahlentwicklung']:
# is_shift_type_ok = False
def already_in_standby():
devices = self.settings.data[sec]["iocDevice"]
pv_list = []
standby_value_list = []
for magnet in devices:
pv_list.append(magnet + ":SOL:2")
idx = self.settings.data[sec]["device"].index(magnet)
standby_value = self.settings.data[sec]["standby"][idx]
standby_value_list.append(standby_value)
value_list, status, status_list = self.cafe.getScalarList(
pv_list, cacheFlag=True)
if status != self.cyca.ICAFE_NORMAL:
self.check_status_list(_pymodule, "getScalarListCache",
pv_list, status_list, _line())
# check standby values
in_standby = True
for value, standby in zip(value_list, standby_value_list):
# if abs(value) < abs(standby)*0.8 or abs(value) >
# abs(standby)*1.2:
if abs(value) > abs(standby) * 1.2:
in_standby = False
break
return in_standby
if pvdata.value[0] == "ON" and not already_in_standby():
print("sec-ON", secsplit[1], flush=True)
self.table_sol_dict[sec].init_value_button.setEnabled(True)
self.table_pwr_dict[sec].init_value_button.setEnabled(True)
else:
print("sec-OFF", secsplit[1], flush=True)
self.table_sol_dict[sec].init_value_button.setEnabled(False)
self.table_pwr_dict[sec].init_value_button.setEnabled(False)
#print("sec", secsplit[1], flush=True)
# April 2024 - NOT REQUIRED
# for state in self.sec_state_list:
#### self.cafe.monitor(state, receive_sec_state)
def get_standby_index_list(self, sec):
devices = self.settings.data[sec]["iocDevice"]
standby_index_list = []
for magnet in devices:
# get standby values
idx = self.settings.data[sec]["device"].index(magnet)
standby_index_list.append(idx)
return standby_index_list
def get_standby_list(self, sec):
devices = self.settings.data[sec]["iocDevice"]
pv_standby_list = []
for magnet in devices:
pv_magnet = magnet + ":SOL:2"
pv_standby_list.append(pv_magnet)
return pv_standby_list
def get_standby_dict(self, sec):
devices = self.settings.data[sec]["iocDevice"]
pv_standby_dict = {}
for magnet in devices:
pv_magnet = magnet + ":SOL:2"
# get standby values
idx = self.settings.data[sec]["device"].index(magnet)
standby_value = self.settings.data[sec]["standby"][idx]
pv_standby_dict[pv_magnet] = standby_value
return pv_standby_dict
def is_sector_standby(self, sector, pv_name, value):
self.sector_designated_magnet_values_dict[sector][pv_name] = value
#print(self.sector_designated_magnet_values_dict[sector], flush=True)
is_standby = True
for pv in self.sector_designated_magnet_values_dict[sector]:
val_now = self.sector_designated_magnet_values_dict[sector][pv]
val_standby = self.sector_designated_magnet_standby_dict[sector][pv]
#print(sector, val_now, val_standby)
if abs(val_now) > (1.2 * abs(val_standby)):
is_standby = False
break
with self.lock:
if not is_standby:
if not self.table_sol_dict[sector].init_value_button.isEnabled(
):
self.table_sol_dict[sector].init_value_button.setEnabled(
True)
if not self.table_pwr_dict[sector].init_value_button.isEnabled(
):
self.table_pwr_dict[sector].init_value_button.setEnabled(
True)
else:
if self.table_sol_dict[sector].init_value_button.isEnabled():
self.table_sol_dict[sector].init_value_button.setEnabled(
False)
if self.table_pwr_dict[sector].init_value_button.isEnabled():
self.table_pwr_dict[sector].init_value_button.setEnabled(
False)
@Slot(float, int, int)
def designated_magnet_cb(self, value, status, alarm_severity):
#print("designated_magnet_cb", status, flush=True)
if status == self.cyca.ICAFE_CA_OP_CONN_DOWN:
return
sender = self.sender()
sector = sender.sector
pv_name = sender.pv_name
# print("local_cb", sender.pv_name, value, status, alarm_severity,
# flush=True)
self.timer.singleShot(
0, lambda: self.is_sector_standby(sector, pv_name, value))
#print("designated_magnet_cb end for sector", sector, flush=True)
def group_sector_status(self):
qgrid = QGridLayout()
# Connect all channels
# Heading
idx = self.settings.data["header"].index("IP2")
# Sector
qlp = QLabel("Power \n(kW)")
f = qlp.font()
f.setPixelSize(13)
qlp.setFont(f)
qlp.setAlignment(Qt.AlignCenter)
qli = QLabel("Initial \n(kW)")
f = qli.font()
f.setPixelSize(13)
qli.setFont(f)
qli.setAlignment(Qt.AlignCenter)
qgrid.addWidget(qli, 0, 1, 1, 1)
qsa = QLabel("Saving \n(MWh)")
f = qsa.font()
f.setPixelSize(13)
qsa.setFont(f)
qsa.setAlignment(Qt.AlignCenter)
qti = QLabel("Time in \nSaving Mode")
f = qti.font()
f.setPixelSize(13)
qti.setFont(f)
qti.setAlignment(Qt.AlignCenter)
qtotsav = QLabel("Tot Saved \n(MWh)")
f = qtotsav.font()
f.setPixelSize(13)
qtotsav.setFont(f)
qtotsav.setAlignment(Qt.AlignCenter)
qgrid.addWidget(qlp, 0, 2, 1, 1)
qgrid.addWidget(qsa, 0, 3, 1, 1)
qgrid.addWidget(qti, 0, 4, 1, 1)
qgrid.addWidget(qtotsav, 0, 5, 1, 1)
for i, sector in enumerate(self.settings.data["header"][idx:]):
a, b, c, d, e, f = self.sector_status(sector)
a.setContentsMargins(2, 0, 0, 0)
qgrid.addWidget(a, i + 1, 0, 1, 1)
qgrid.addWidget(b, i + 1, 1, 1, 1)
qgrid.addWidget(c, i + 1, 2, 1, 1)
qgrid.addWidget(d, i + 1, 3, 1, 1)
qgrid.addWidget(e, i + 1, 4, 1, 1)
qgrid.addWidget(f, i + 1, 5, 1, 1)
qh_line = QHLine()
qh_line.setFixedHeight(10)
row = qgrid.rowCount()
qgrid.addWidget(qh_line, row, 1, 1, 5)
#qgrid.setRowMinimumHeight(row, 60)
qtot = QLabel("Total:")
fnt = qtot.font()
fnt.setPixelSize(13)
qtot.setFont(fnt)
qgrid.addWidget(qtot, row + 1, 0, 1, 1)
qgrid.addWidget(
CAQLineEdit(self, pv_name="ZHIPA-HUSH:LASTPWR", show_units=True),
row + 1, 1, 1, 1)
qgrid.addWidget(
CAQLineEdit(self, pv_name="ZHIPA-HUSH:TOTPWR", show_units=True),
row + 1, 2, 1, 1)
qgrid.addWidget(
CAQLineEdit(self, pv_name="ZHIPA-HUSH:LASTSAVE", show_units=False),
row + 1, 3, 1, 1)
qgrid.addWidget(
CAQLineEdit(self, pv_name="ZHIPA-HUSH:TOTSAVE", show_units=False),
row + 1, 5, 1, 1)
qgrid.setContentsMargins(9, 20, 9, 9)
qw = QGroupBox("Savings Overview")
qw.setContentsMargins(9, 9, 9, 9)
qw.setObjectName("OUTER")
qw.setLayout(qgrid)
qw.setFixedWidth(496) # 480
qw.setFixedHeight(346) # 480
return qw
def sector_status(self, sector):
'''Create each sector line for inclusion into group
'''
device = "Z" + sector + "-HUSH"
# Qlabel
qsector = QLabel(sector + ":")
f = qsector.font()
f.setPixelSize(13)
qsector.setFont(f)
color = "black"
try:
color = self.settings.data[sector]["color"]
except KeyError as ex:
print(ex, self.settings.data[sector])
color_str = "color : {0};".format(color)
incolor = "QLabel {" + color_str + "}"
qsector.setStyleSheet(incolor)
# Savings
pv_pwr_tot = device + ":TOTPWR"
pv_pwr_last = device + ":LASTPWR"
pv_pwr_saved = device + ":LASTSAVE"
pv_pwr_timeout = device + ":OFFTIME"
pv_pwr_totsave = device + ":TOTSAVE"
self.cafe.openPrepare()
self.cafe.open([pv_pwr_tot, pv_pwr_last, pv_pwr_saved, pv_pwr_timeout])
self.cafe.openNowAndWait(2.0)
time.sleep(0.1)
def cb_outtime(handle, pv, pvdata):
try:
delta = "{}".format(str(timedelta(seconds=(pvdata.value[0]))))
if delta == "0:00:00":
delta = "0 s "
self.offtime_dict[pv].setAlignment(Qt.AlignRight)
elif ", " in delta:
le_split = delta.split(", ")
if len(le_split) == 2:
if len(le_split[1]) == len("0:00:00"):
delta = le_split[0] + ", " + le_split[1]
if "days," in delta:
delta = delta.replace("days,", "d")
elif "day," in delta:
delta = delta.replace("day,", "d")
self.offtime_dict[pv].setText(delta)
except KeyError:
pass
#now = QDateTime.currentDateTime()
#xdate = QDate(now.date().year(), 1, 15)
#xstart = QDateTime(xdate)
qpinit = CAQLineEdit(self, pv_name=pv_pwr_last, show_units=False)
qpnow = CAQLineEdit(self, pv_name=pv_pwr_tot, show_units=False)
qpsave = CAQLineEdit(self, pv_name=pv_pwr_saved, show_units=False)
qptotsave = CAQLineEdit(self, pv_name=pv_pwr_totsave, show_units=False)
qptime = CAQLineEdit(self, pv_name=pv_pwr_timeout,
monitor_callback=cb_outtime, show_units=True)
self.offtime_dict[pv_pwr_timeout] = qptime
qptime.setFixedWidth(104)
return qsector, qpinit, qpnow, qpsave, qptime, qptotsave
def group_sector_qtabwidget(self):
idx_inj = self.settings.data["header"].index("INJ2")
idx = self.settings.data["header"].index("IP2")
# open all PVS
pv = []
for sector in self.settings.data["header"][idx_inj:]:
device_list = self.settings.data[sector]["device"]
attribute_list = self.settings.data[sector]["attribute"]
for att in attribute_list:
for dev in device_list:
pv.append(dev + ":" + att)
self.cafe.openPrepare()
self.cafe.open(pv)
self.cafe.openNowAndWait(1.0)
# self.cafe.supplementHandles()
sector_wgt_dict = {}
sector_wgt_dict["INJ2"] = self.ca_table_rf_widget(sector="INJ2")
for sector in self.settings.data["header"][idx:]:
sector_wgt_dict[sector] = self.ca_table_sector_widget(
sector=sector)
sector_tab_widget = QTabWidget()
sector_tab_widget.setFont(self.font_gui)
sector_tab_widget.setStyleSheet("QTabBar {font-size: 12pt;}")
sector_tab_widget.tabBar().setShape(QTabBar.TriangularNorth)
for i, sector in enumerate(self.settings.data["header"][idx:]):
sector_tab_widget.addTab(sector_wgt_dict[sector], sector)
color = self.settings.data[sector]["color"]
sector_tab_widget.tabBar().setTabTextColor(i, QColor(color))
sector_tab_widget.addTab(sector_wgt_dict["INJ2"], "RF")
color = self.settings.data["INJ2"]["color"]
sector_tab_widget.tabBar().setTabTextColor(
len(self.settings.data["header"][idx:]), QColor(color))
return sector_tab_widget
def ca_table_rf_widget(self, sector: str = ""):
device_list = self.settings.data[sector]["device"]
attribute_list = self.settings.data[sector]["attribute"]
pv_dict = {}
for att in attribute_list:
pv_dict[att] = [] # [None] * len(device_list)
for dev in device_list:
pv_dict[att].append(dev + ":" + att)
try:
CR1IN_idx = pv_dict["IST:2"].index("CR1IN:IST:2")
except ValueError:
CR1IN_idx = 3
table_pwr = [None] * 2
table_pwr[0] = CAQTableWidget(
self, pv_list=pv_dict["IST:2"][0:CR1IN_idx], show_units=False,
notify_freq_hz=0, suffix="MW",
notify_unison=False, scale_factor=0.001, show_timestamp=False,
init_column=True, pv_list_show=device_list[0:CR1IN_idx])
table_pwr[1] = CAQTableWidget(
self, pv_list=pv_dict["IST:2"][CR1IN_idx:], show_units=False,
notify_freq_hz=0, suffix="MW",
notify_unison=False, scale_factor=0.001, show_timestamp=False,
init_column=True, pv_list_show=device_list[CR1IN_idx:])
for tab in table_pwr:
header_item = QTableWidgetItem()
header_init = QTableWidgetItem()
#header_standby = QTableWidgetItem()
header_value = QTableWidgetItem()
f = header_value.font()
f.setPixelSize(13)
header_item.setFont(f)
header_item.setText("Device")
header_init.setFont(f)
header_init.setText("Init. Value")
header_value.setFont(f)
header_value.setText("IST:2")
tab.setContentsMargins(15, 0, 15, 10)
tab.setHorizontalHeaderItem(0, header_item)
tab.setHorizontalHeaderItem(1, header_init)
tab.setHorizontalHeaderItem(2, header_value)
tab.setColumnWidth(0, 80)
tab.setColumnWidth(1, 88)
tab.setColumnWidth(2, 88)
tab.setFixedWidth(304)
tab.restore_layout.removeWidget(tab.restore_value_button)
tab.restore_value_button.deleteLater()
tab.restore_value_button = None
tab.init_value_button.setToolTip(
("Shows initial, pre-standby values. Update is also " +
"executed automatically before the standby procedure."))
box = QVBoxLayout()
box.addWidget(table_pwr[0])
box.addWidget(table_pwr[1])
box.setAlignment(Qt.AlignTop | Qt.AlignLeft)
box.setSpacing(10)
qw = QWidget()
qw.setLayout(box)
obj_name = self.settings.data[sector]["colorObj"]
if self.obj_to_upper:
obj_name = obj_name.upper()
qw.setObjectName(obj_name)
return qw
def on_sector_standby(self):
target = self.sender()
sector = target.sector
table = self.table_sol_dict[sector]
def is_update_enabled():
'''Check if update buttons are enabled
if NOT, then do not allow inital values values to be updated"
'''
return bool(
self.table_pwr_dict[sector].init_value_button.isEnabled(
) and table.init_value_button.isEnabled())
# if self.table_pwr_dict[sector].init_value_button.isEnabled() \
# and table.init_value_button.isEnabled():
# return True
# else:
# return False
def write_to_restore_ucn():
if sector != "UCN":
return
restore_pvs = self.settings.data["RestoreUCN"]["PV"]
default_values = self.settings.data["RestoreUCN"]["value"]
#print(restore_pvs, default_values, flush=True)
values_dict = self.table_sol_dict["UCN"].get_init_values()
#print(values_dict, flush=True)
values = []
pvs = []
for pv, val in zip(restore_pvs, default_values):
pv_indict = pv[-4:] + ":SOL:2"
try:
_val = values_dict[pv_indict]
if _val > 0.8 * val:
pvs.append(pv)
values.append(_val)
except KeyError as ex:
print("ex", ex)
if pvs:
status, status_list = self.cafe.setScalarList(pvs, values)
if status != self.cyca.ICAFE_NORMAL:
self.send_to_log_window(pv_list=pvs, status=status,
status_list=status_list,
operation="set", pymodule=_pymodule,
line=_line())
if sector == "UCN":
write_to_restore_ucn()
QApplication.processEvents(QEventLoop.AllEvents, 1)
# Do NOT do updates if in standby mode!
# Update button is disabled when in standby
# disenable widgets to avoid circular behaviour since
# updates of SOL also update PWR, and vice-versa
# Do not click if already on standby!!
with self.lock:
update_enabled = is_update_enabled()
if update_enabled:
self.table_pwr_dict[sector].init_value_button.setEnabled(False)
table.init_value_button.click()
time.sleep(0.05)
self.table_pwr_dict[sector].init_value_button.setEnabled(True)
table.init_value_button.setEnabled(False)
self.table_pwr_dict[sector].init_value_button.click()
time.sleep(0.05)
self.table_sol_dict[sector].init_value_button.setEnabled(True)
QApplication.processEvents(QEventLoop.AllEvents, 1)
if not self.input_parameters["simulation"]:
if sector == "UCN":
write_to_restore_ucn()
status, status_list, pv_list = table.set_standby_values()
if status != self.cyca.ICAFE_NORMAL:
#self.check_status_list(pv_list, status_list, _line())
self.check_status_list(
_pymodule, "setScalarList", pv_list, status_list, _line())
# Seqeuncer ONLY determines when to go into STANDBY mode
# and NOT the HLA
##pv = 'Z' + target.sector + "-HUSH:STATE"
##stat = self.cafe.set(pv, 0)
##self.check_status(pv, stat, _line())
# Disable because table.set_standby_values() enables it
if not update_enabled:
with self.lock:
self.table_pwr_dict[sector].init_value_button.setEnabled(False)
table.init_value_button.setEnabled(False)
def on_sector_restore(self):
target = self.sender()
sector = target.sector
table = self.table_sol_dict[sector]
if not self.input_parameters["simulation"]:
status, status_list, pv_list = table.restore_init_values()
if status != self.cyca.ICAFE_NORMAL:
#self.check_status_list(pv_list, status_list, _line())
self.check_status_list(
_pymodule, "setScalarList", pv_list, status_list, _line())
# Seqeuncer ONLY determines when to go into STANDBY mode
# and NOT the HLA
#pv = "Z" + target.sector + "-HUSH:STATE"
#stat = self.cafe.set(pv, 1)
#self.check_status(pv, stat, _line())
table_pwr = self.table_pwr_dict[sector]
row_pwr_dict = table_pwr.get_init_values()
sum_pwr = sum(list(row_pwr_dict.values()))
#pv_last_pwr = "SEC-" + target.sector + ":LASTPWR"
pv_last_pwr = "Z" + target.sector + "-HUSH:LASTPWR"
stat = self.cafe.set(pv_last_pwr, sum_pwr)
#self.check_status(pv_last_pwr, stat, _line())
self.check_status(_pymodule, "set", pv_last_pwr, stat, _line())
def ca_table_sector_widget(self, sector: str = ""):
device_list = self.settings.data[sector]["device"]
attribute_list = self.settings.data[sector]["attribute"]
try:
standby_values = self.settings.data[sector]["standby"]
except KeyError as ex:
print("On Standby values not given", ex)
pv_dict = {}
for att in attribute_list:
pv_dict[att] = [] # [None] * len(device_list)
for dev in device_list:
pv_dict[att].append(dev + ":" + att)
self.cafe.openPrepare()
# for key, val in pv_dict.items():
for val in pv_dict.values():
self.cafe.open(val)
self.cafe.openNowAndWait(2.0)
time.sleep(0.05)
try:
_delay = self.input_parameters["delayRamp"]
except KeyError:
_delay = 0.09
pass
pvlist = self.get_standby_list(sector)
for pv in pvlist:
value = self.cafe.getCache(pv)
if value is not None:
self.sector_designated_magnet_values_dict[sector][pv] = value
table_sol = CAQTableWidget(
self, pv_list=pv_dict["SOL:2"], show_units=True, notify_freq_hz=0,
notify_unison=False, scale_factor=1, show_timestamp=False,
init_column=True, pv_list_show=device_list, standby_column=True,
standby_values=standby_values, set_delay=_delay)
table_sol.restore_value_button.setToolTip(
("Restore devices to their pre-standby values"))
table_sol.init_value_button.setToolTip(
("Shows initial, pre-standby values. Update is also " +
"executed automatically before the standby procedure."))
table_sol.standby_value_button.sector = sector
table_sol.standby_value_button.clicked.disconnect()
table_sol.standby_value_button.clicked.connect(self.on_sector_standby)
table_sol.restore_value_button.sector = sector
table_sol.restore_value_button.clicked.disconnect()
table_sol.restore_value_button.clicked.connect(self.on_sector_restore)
self.table_sol_dict[sector] = table_sol
table_ist = CAQTableWidget(
self, pv_list=pv_dict["IST:2"], show_units=True, notify_freq_hz=2,
notify_unison=True, scale_factor=1, show_timestamp=False,
init_column=False, pv_list_show=[False])
table_pwr = CAQTableWidget(
self, pv_list=pv_dict["PWR:2"], show_units=False, notify_freq_hz=0,
suffix="kW",
notify_unison=False, scale_factor=0.001, show_timestamp=False,
init_column=True, init_list=pv_dict["PWR:2"], pv_list_show=[False])
table_pwr.init_value_button.setToolTip(
("Shows initial, pre-standby values. Update is also " +
"executed automatically before the standby procedure."))
self.table_pwr_dict[sector] = table_pwr
header_item = QTableWidgetItem()
header_init = QTableWidgetItem()
header_standby = QTableWidgetItem()
header_value = QTableWidgetItem()
f = header_value.font()
f.setPixelSize(13)
header_item.setFont(f)
header_item.setText("Device")
header_init.setFont(f)
header_init.setText("Init. Value")
header_standby.setFont(f)
header_standby.setText("Standby")
header_value.setFont(f)
header_value.setText("SOL:2")
table_sol.setContentsMargins(15, 0, 15, 10)
table_sol.setHorizontalHeaderItem(0, header_item)
table_sol.setHorizontalHeaderItem(1, header_init)
table_sol.setHorizontalHeaderItem(2, header_standby)
table_sol.setHorizontalHeaderItem(3, header_value)
table_sol.setColumnWidth(0, 80)
table_sol.setColumnWidth(1, 88)
table_sol.setColumnWidth(2, 80)
table_sol.setColumnWidth(3, 88)
table_sol.setFixedWidth(386)
ioc_magnets = []
for i, device in enumerate(device_list):
if device in self.settings.data[sector]["iocDevice"]:
ioc_magnets.append(i)
header_value = QTableWidgetItem()
f = header_value.font()
f.setPixelSize(13)
header_value.setFont(f)
header_value.setText("IST:2")
table_ist.setContentsMargins(15, 0, 15, 10)
table_ist.setHorizontalHeaderItem(0, header_value)
table_ist.setColumnWidth(0, 90)
table_ist.setFixedWidth(140)
header_init = QTableWidgetItem()
f = header_init.font()
header_init.setFont(f)
header_init.setText("Init. Value")
header_value = QTableWidgetItem()
f = header_value.font()
f.setPixelSize(13)
header_value.setFont(f)
header_value.setText("PWR:2")
table_pwr.setContentsMargins(15, 0, 15, 10)
table_pwr.setHorizontalHeaderItem(0, header_init)
table_pwr.setHorizontalHeaderItem(1, header_value)
table_pwr.setColumnWidth(0, 88)
table_pwr.setColumnWidth(1, 88)
table_pwr.setFixedWidth(226)
for i in ioc_magnets:
table_sol.paint_rows(row_range=[i, i + 1], reset=False,
columns=[0, 1])
table_ist.paint_rows(row_range=[i, i + 1], reset=False)
table_pwr.paint_rows(row_range=[i, i + 1], reset=False)
pvI = self.settings.data[sector]["current"]
I = self.cafe.getCache(pvI)
if I is not None:
if I < self.I_min:
try:
values = self.settings.data[sector]["ref"]
table_sol.set_init_values(values)
except KeyError:
pass
try:
pwr_values = self.settings.data[sector]["pwrref"]
table_pwr.set_init_values(pwr_values)
except KeyError:
pass
gateway_indices = self.get_standby_index_list(sector)
for idx in gateway_indices:
table_sol.pv_gateway[idx].sector = sector
table_sol.pv_gateway[idx].trigger_monitor_float.connect(
self.designated_magnet_cb)
def on_sol_update():
table_sol.init_value_button.setEnabled(False)
table_pwr.init_value_button.click()
time.sleep(0.1)
table_sol.init_value_button.setEnabled(True)
#pv = "SEC-" + table_pwr.init_value_button.sector + ":LASTPWR"
pv = "Z" + table_pwr.init_value_button.sector + "-HUSH:LASTPWR"
_sum = sum(table_pwr.get_init_values().values())
#print("SUM up all the values", pv, _sum, flush=True)
stat = self.cafe.set(pv, _sum)
#self.check_status(pv, stat, _line())
self.check_status(_pymodule, "set", pv, stat, _line())
def on_init_update():
table_pwr.init_value_button.setEnabled(False)
table_sol.init_value_button.click()
time.sleep(0.1)
table_pwr.init_value_button.setEnabled(True)
table_sol.init_value_button.sector = sector
table_sol.init_value_button.clicked.connect(on_sol_update)
table_pwr.init_value_button.sector = sector
table_pwr.init_value_button.clicked.connect(on_init_update)
hbox = QHBoxLayout()
hbox.addWidget(table_sol)
hbox.addWidget(table_ist)
hbox.addWidget(table_pwr)
hbox.setSpacing(10)
hbox.setAlignment(Qt.AlignTop)
qw = QWidget()
qw.setLayout(hbox)
obj_name = self.settings.data[sector]["colorObj"]
if self.obj_to_upper:
obj_name = obj_name.upper()
qw.setObjectName(obj_name)
return qw
def clear_saving(self, sector_prefix_list: list = None):
if not sector_prefix_list:
return
qm = QMessageBox()
mess = ("This action will reset the energy saving account to zero. \n" +
"This is typically undertaken at the end of the calendar " +
"year. \n\n" +
"Present accounting figures will be entered in the elogbook\n" +
"Are you sure you wish to continue with the reset?")
reply = qm.warning(self, "Reset Accounting", mess,
QMessageBox.Yes | QMessageBox.No)
if reply == QMessageBox.No:
return
self.parent.prepare_elog_message()
print("message", self.parent.message, flush=True)
print("logbook", self.parent.logbook, flush=True)
url = self.settings.data["ElogBooks"][self.parent.logbook]["url"]
print("url", url, flush=True)
logbook = elog.open(url, user="robot", password="robot")
# QApplication.processEvents()
attributes = {}
attributes["Autor"] = getpass.getuser()
attributes["Author"] = getpass.getuser()
attributes["Application"] = self.parent.appname
attributes["Titel"] = self.parent.title
attributes["Title"] = self.parent.title
attributes["When"] = str(time.time())
attributes["Wann"] = str(time.time())
if "Sandkasten" in self.parent.logbook:
attributes["Eintrag"] = "Anregung"
elif "Bestandesaufnahme" in self.parent.logbook:
attributes["Konsole"] = socket.gethostname().split(".")[0]
attributes["Ort"] = "Global"
elif "Strahlentwicklung" in self.parent.logbook:
pass
# HIPA Log Book
else:
attributes["Eintrag"] = self.elog_enum.eintrag.INFO.name
attributes["Effekt"] = self.elog_enum.effekt.NONE.name # keiner
# "Elektorversogung"
attributes["System"] = self.elog_enum.system.ELECTRICAL_SUPPLY.name
attributes["Ort"] = self.elog_enum.ort.GLOBAL.name
log_mess = self.parent.message.replace("<br>", "\n")
try:
logbook.post(log_mess, attributes=attributes)
self.show_log_message(MsgSeverity.INFO, _pymodule, _line(),
log_mess)
self.statusbar.showMessage("Reset Savings Account." +
"Last values sent to elog")
except Exception as ex:
print("Exception in sendelog.py", str(ex), flush=True)
mess = "Failed to write last saving values to elog:" + str(ex)
self.show_log_message(
MsgSeverity.ERROR, _pymodule, _line(), mess)
self.statusbar.showMessage(mess)
for sector in sector_prefix_list:
self.sector_sm_off(sector)
for sector in sector_prefix_list:
self.clear_sector_saving(sector)
def sector_sm_off(self, sector_prefix: str = None):
if not sector_prefix:
return
pv1 = sector_prefix + "-HUSH:SEQ-ONOFF"
stat = self.cafe.set(pv1, 0)
self.check_status(_pymodule, "set", pv1, stat, _line())
time.sleep(0.05)
QApplication.processEvents()
return
def clear_sector_saving(self, sector_prefix: str = None):
if not sector_prefix:
return
pv1 = sector_prefix + "-HUSH:SEQ-ONOFF"
pv2 = sector_prefix + "-HUSH:TOTSAVE"
pv3 = sector_prefix + "-HUSH:OFFTIME"
stat = self.cafe.set(pv1, 0)
self.check_status(_pymodule, "set", pv1, stat, _line())
off_time = self.cafe.get(pv3)
self.check_status(_pymodule, "get", pv3, None, _line())
iloop = 0
if off_time is not None:
while off_time > 0 and iloop < 100:
time.sleep(0.1)
off_time_tmp = self.cafe.get(pv3)
off_time = off_time_tmp if off_time_tmp is not None else 0
iloop += 1
QApplication.processEvents()
else:
time.sleep(0.1)
print("SECTOR ILOOP", sector_prefix, iloop)
stat = self.cafe.set(pv1, 1)
self.check_status(_pymodule, "set", pv1, stat, _line())
stat = self.cafe.set(pv2, 0)
self.check_status(_pymodule, "set", pv2, stat, _line())
return
def reset_ioc_saving(self, sector_prefix_list: list = None):
if not sector_prefix_list:
return
qpb = QPushButton("Reset Account")
qpb.setObjectName("WriteData")
qpb.clicked.connect(lambda: self.clear_saving(sector_prefix_list))
qpb.setFixedHeight(40) # self.gui_frame.widget_height)
qpb.setFixedWidth(160)
qtext = QTextEdit()
qtext.setText("""<br>&nbsp;&nbsp;The Reset Account Button resets
Total Power Saved (MWh) to zero. <br>
&nbsp;&nbsp;This is typically executed at the end of the calendar
year.<br>
&nbsp;&nbsp;The present energy saving figures will be entered into
the elogbook.<br>
&nbsp;&nbsp;The button prompts the user for confirmation before
proceeding.<br>
""")
qtext.setReadOnly(True)
qtext.setStyleSheet("background-color: QColor(0, 0, 50, 10);")
qtext.setFixedHeight(104)
qtext.setFixedWidth(440)
qgrid = QGridLayout()
qgrid.setSpacing(0)
qgrid.addWidget(qtext, 0, 0, 1, 1, Qt.AlignHCenter)
qgrid.addWidget(qpb, 1, 0, 1, 1, Qt.AlignHCenter)
qw = QGroupBox("HUSH! Accounting")
qw.setContentsMargins(5, 10, 5, 0)
qw.setAlignment(Qt.AlignTop)
qw.setObjectName("OUTER")
qw.setLayout(qgrid)
qw.setFixedWidth(460)
qw.setFixedHeight(280)
return qw
def reset_ioc_sm(self):
msg_button = [None] * len(self.sec_state_list)
monitor_seq_onoff = [None] * len(self.sec_state_list)
monitor_seq_state = [None] * len(self.sec_state_list)
monitor_standby_state = [None] * len(self.sec_state_list)
qgrid = QGridLayout()
qreset = QLabel("Reset")
qreset.setAlignment(Qt.AlignBottom | Qt.AlignHCenter)
qsm = QLabel("SM ")
qsm.setAlignment(Qt.AlignBottom | Qt.AlignHCenter)
qss = QLabel("Sequencer State ")
qss.setAlignment(Qt.AlignBottom | Qt.AlignHCenter)
qstandby = QLabel("ON or \nStandby")
qstandby.setAlignment(Qt.AlignBottom | Qt.AlignHCenter)
qgrid.addWidget(qreset, 0, 0, 1, 1)
qgrid.addWidget(qsm, 0, 1, 1, 1)
qgrid.addWidget(qss, 0, 2, 1, 1)
qgrid.addWidget(qstandby, 0, 3, 1, 1)
for i, pv in enumerate(self.sec_state_list):
pvsplit = pv.split("-")
sec = pvsplit[0][1:]
pv_seq_onoff = pv.replace("STATE", "SEQ-ONOFF")
pv_seq_state = pv.replace("STATE", "SEQ-STATE")
msg_button[i] = CAQMessageButton(
self, pv_name=pv_seq_onoff, msg_label=sec,
msg_press_value="Off", msg_release_value="On")
msg_button[i].setFixedWidth(60)
monitor_seq_onoff[i] = CAQLabel(self, pv_name=pv_seq_onoff)
monitor_seq_state[i] = CAQLabel(self, pv_name=pv_seq_state)
monitor_standby_state[i] = CAQLabel(self, pv_name=pv)
qgrid.addWidget(msg_button[i], i + 1, 0, 1, 1, Qt.AlignLeft)
qgrid.addWidget(monitor_seq_onoff[i], i + 1, 1, 1, 1, Qt.AlignLeft)
qgrid.addWidget(monitor_seq_state[i], i + 1, 2, 1, 1, Qt.AlignLeft)
qgrid.addWidget(
monitor_standby_state[i],
i + 1,
3,
1,
1,
Qt.AlignLeft)
qgrid.setContentsMargins(9, 9, 9, 9)
qgrid.setSpacing(10)
qw = QGroupBox("State Machine")
qw.setContentsMargins(5, 10, 5, 0)
qw.setAlignment(Qt.AlignTop)
qw.setObjectName("OUTER")
qw.setLayout(qgrid)
qw.setFixedWidth(460)
qw.setFixedHeight(280)
return qw
def reset_lastpwr(self):
sector_label = [None] * len(self.sec_state_list)
pv_initpwr = [None] * len(self.sec_state_list)
pv_lastpwr = [None] * len(self.sec_state_list)
qgrid = QGridLayout()
qsection = QLabel("Section")
qsection.setAlignment(
Qt.AlignmentFlag(
Qt.AlignBottom | Qt.AlignHCenter))
qnominal = QLabel("Nominal \n Value (kW)")
qnominal.setAlignment(
Qt.AlignmentFlag(
Qt.AlignBottom | Qt.AlignHCenter))
qset = QLabel("Set \n Value (kW)")
qset.setAlignment(Qt.AlignmentFlag(Qt.AlignBottom | Qt.AlignHCenter))
qgrid.addWidget(qsection, 0, 0, 1, 1)
qgrid.addWidget(qnominal, 0, 1, 1, 1)
qgrid.addWidget(qset, 0, 2, 1, 1)
for i, pv in enumerate(self.sec_state_list):
pvsplit = pv.split("-")
sector = pvsplit[0][1:]
sum_pwr = round(sum(self.settings.data[sector]["pwrref"]), 3)
pv_initpwr_value = decimal.Decimal(format(sum_pwr, ".3f"))
pv_lastpwr_name = pv.replace("STATE", "LASTPWR")
qsector = QLabel(sector + ":")
f = qsector.font()
f.setPixelSize(14)
qsector.setFont(f)
color = "black"
try:
color = self.settings.data[sector]["color"]
except KeyError as ex:
print(ex, self.settings.data[sector])
weight = "medium"
color_str = "color : {0}; font-weight:{1};".format(color, weight)
incolor = "QLabel {" + color_str + "}"
qsector.setStyleSheet(incolor)
sector_label[i] = qsector
ql = QLabel(str(pv_initpwr_value))
ql.setFont(f)
pv_initpwr[i] = ql
ca_qtext_entry = CAQTextEntry(self, pv_name=pv_lastpwr_name)
f = ca_qtext_entry.font()
f.setPixelSize(8)
ca_qtext_entry.setFont(f)
pv_lastpwr[i] = ca_qtext_entry
qgrid.addWidget(sector_label[i], i + 1, 0, 1, 1, Qt.AlignLeft)
qgrid.addWidget(pv_initpwr[i], i + 1, 1, 1, 1, Qt.AlignRight)
qgrid.addWidget(pv_lastpwr[i], i + 1, 2, 1, 1, Qt.AlignLeft)
qgrid.setContentsMargins(9, 9, 9, 9)
qgrid.setSpacing(10)
qw = QGroupBox("Last Power")
qw.setContentsMargins(5, 10, 5, 0)
qw.setAlignment(Qt.AlignTop)
qw.setObjectName("OUTER")
qw.setLayout(qgrid)
qw.setFixedWidth(240)
qw.setFixedHeight(280)
return qw