diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bb40eab
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+*.*~
+*.*-*
+*.*+*
+help/*.*~
+help/*.*-*
+help/*.*+*
+src/*.*~
+src/*.*-*
+src/*.*+*
+pyrcc5/*.*~
+pyrcc5/*.*-*
+pyrcc5/*.*+*
diff --git a/help/README.md b/help/README.md
new file mode 100644
index 0000000..a7f649a
--- /dev/null
+++ b/help/README.md
@@ -0,0 +1,6 @@
+# to compile hush.qrc:
+make
+# to install compiled hush_respources.py
+make install
+
+The latter installs hush_respources.py to the ../pyqrcc5 directory
\ No newline at end of file
diff --git a/help/hush.qrc b/help/hush.qrc
new file mode 100644
index 0000000..eefb6cb
--- /dev/null
+++ b/help/hush.qrc
@@ -0,0 +1,10 @@
+
This hush application inherits from the Window base class.
+
information concerning this application, such as configuration parameters or other, may be entered, e.g., here
+ +These web pages are to be completed by the application owner.
+
+
+
+
+
diff --git a/help/make_and_install.sh b/help/make_and_install.sh
new file mode 100644
index 0000000..e7c2b22
--- /dev/null
+++ b/help/make_and_install.sh
@@ -0,0 +1,2 @@
+make compile
+make install
diff --git a/help/makefile b/help/makefile
new file mode 100644
index 0000000..3ff7d5e
--- /dev/null
+++ b/help/makefile
@@ -0,0 +1,9 @@
+compile:
+ pyrcc5 hush.qrc > hush_resources.py
+
+install:
+ if [ ! -f hush_resources.py ]; then echo "pyrcc5 compilation of resources.qrc failed"; fi
+ if [ -f hush_resources.py -a -f ../pyrcc5/hush_resources.py-- ]; then cp ../pyrcc5/hush_resources.py-- ../pyrcc5/hush_resources.py---; fi
+ if [ -f hush_resources.py -a -f ../pyrcc5/hush_resources.py- ]; then cp ../pyrcc5/hush_resources.py- ../pyrcc5/hush_resources.py--; fi
+ if [ -f hush_resources.py -a -f ../pyrcc5/hush_resources.py ]; then cp ../pyrcc5/hush_resources.py ../pyrcc5/hush_resources.py-; fi
+ if [ -f hush_resources.py ]; then cp hush_resources.py ../pyrcc5/hush_resources.py; fi
diff --git a/help/page1.html b/help/page1.html
new file mode 100755
index 0000000..6fa49c5
--- /dev/null
+++ b/help/page1.html
@@ -0,0 +1,7 @@
+
Page 1 of web help
+ +etc... etc...
+ diff --git a/help/page2.html b/help/page2.html new file mode 100755 index 0000000..10f6352 --- /dev/null +++ b/help/page2.html @@ -0,0 +1,7 @@ +Page 2 of web help
+ +etc... etc...
+ diff --git a/help/page3.html b/help/page3.html new file mode 100755 index 0000000..f12e898 --- /dev/null +++ b/help/page3.html @@ -0,0 +1,7 @@ +Page 3 of web help
+ +etc... etc...
+ diff --git a/help/page4.html b/help/page4.html new file mode 100755 index 0000000..64c0eb6 --- /dev/null +++ b/help/page4.html @@ -0,0 +1,7 @@ +Page 4 of web help
+ +etc... etc...
+ diff --git a/help/page5.html b/help/page5.html new file mode 100755 index 0000000..639d750 --- /dev/null +++ b/help/page5.html @@ -0,0 +1,7 @@ +Page 5 of web help
+ +etc... etc...
+ diff --git a/hush.json b/hush.json new file mode 100755 index 0000000..d850efd --- /dev/null +++ b/hush.json @@ -0,0 +1,78 @@ +{ + "menuFlags":{ + "hasFile": 0, + "loadInitFile": 0, + "hasDaq": 0, + "hasH5": 0, + "hasEpics": 0 + }, + "hdf": { + "destination" : "./" + }, + "G1":{ + "standby": [-6.867, 6.867, 9.155, 6.867, 6.867, 9.155, 6.867, -6.867, 6.867, 6.867], + "ref" : [-33.18, 33.18, 118.9, 19.45, 19.45, 118,9, 33.18, -33.18, 43.47826, 45.7666], + "pwrref" : [0.10, 0.10, 0.55, 0.10, 0.10, 0.25, 0.100, -0.10, 0.10, -0.10], + "iocDevice" : ["AME1", "AME2", "QME10"] + }, + "SH":{ + "standby": [-4, 3, 3, -4, 9, 4, -5, -4, + 4, 9], + "ref" : [-34.048, 26.68, 26.68, -34.05, 87.764, 37.424, -47.207, -38.156, + 36.977, 87.642], + "pwrref" : [0.5, 0.3, 0.3, 0.5, 5.5, 0.146, 0.16, 0.343, + 0.43, 0.0], + "iocDevice" : ["QMA7", "AMA2", "QMA12"] + }, + "G2":{ + "standby" : [-4.90, 4.0, -4, 5, -3, -4, 4, -4, + 5, 5, -4, 11, 11, 25], + "ref": [-41.056, 36.548, -30.490, 52.433, -27.636, -37.412, 41.966, -37.296, + 51.200, 53.657, -41.966, 109.543, 109.405, 251.492], + "pwrref" : [0.7, 0.54, 0.39, 1.15, 0.32, 0.375, 0.466, 0.377, + 0.70, 0.771, 0.46, 7.1, 7.1, 21], + "iocDevice" : ["QMB2", "QMB4", "AMF1"] + }, + "O2":{ + "standby": [-4, 3, 3, -4, 6, 3, -3, 3, + -5, 2], + "ref" : [-40.85, 26.974, 26.974, -40.851, 45.988, 30.890, -29.542, 33.742, + -45.960, 20.165], + "pwrref" : [0.68, 0.3, 0.3, 0.67, 1.0, 0.4, 0.36, 0.47, + 0.89, 0.17], + "iocDevice" : ["QMC2", "AMC1", "QMC7"] + }, + "PIF":{ + "standby": [-4, 4, 4, -4, 14, 6, -6, 4, + -6, 3], + "ref" : [-36.159, 34.434, 42.277, -43, 135, 61, -62, 37, + -55, 30], + "pwrref" : [0.16, 0.16, 0.28, 0.31, 3.7, 0.6, 0.73, 0.25, + 0.59, 0.145], + "iocDevice" : ["QMD2", "AMD1", "QMD9"] + }, + "G3":{ + "standby": [-4, 7, -4], + "ref" : [-40.388, 68.393, -34.805], + "pwrref" : [0.64, 1.8, 0.46], + "iocDevice" : ["QMD10", "QMD11", "QMD12"] + }, + "Parameters":{ + + "drawLine" : {"flag" : 0, "data":{ "widget": "QHLine", "text" : "None", "value" : "None"}}, + "delayRamp" : {"flag" : 1, "data":{ "widget": "QDoubleSpinBox", "text" : "Ramp delay (s):", + "value" : 0.1, "min": 0.00, "max": 0.20, "step": 0.01, + "tooltip":"Wait time between sending set point to each magnet in 'Restore'/'Standby' "}}, + "drawLine2" : {"flag" : 0, "data":{ "widget": "QHLine", "text" : "None", "value" : "None"}} + + }, + "Expert":{ + "debug": {"flag" : 0, "data":{ "widget": "None", "text" : "Debug", "value" : 0}}, + "simulation": {"flag" : 1, "data":{ "widget": "None", "text" : "Dry run", "value" : 1}} + }, + "GUI": { + "resultsTabTitle" : "Results", + "subResultsTabTitle" : [], + "resultsSeq" : [] + } +} diff --git a/hush.py b/hush.py new file mode 100644 index 0000000..92d7502 --- /dev/null +++ b/hush.py @@ -0,0 +1,229 @@ +import inspect +import logging +import os +import platform +import random +import sys +import time + + +from qtpy import QtCore, QtGui +from qtpy.QtGui import QColor, QFont, QIcon +from qtpy.QtCore import __version__ as QT_VERSION_STR +from qtpy.QtCore import ( + PYQT_VERSION_STR, QFile, QIODevice, Qt, QThread, Signal, Slot) +from qtpy.QtWidgets import ( + QApplication, QDockWidget, QGridLayout, QGroupBox, QHBoxLayout, QLabel, + QMainWindow, QMessageBox, QProgressBar, QPushButton, QSizePolicy, + QSpacerItem, QTabWidget, QTableWidget, QTableWidgetItem, QVBoxLayout, + QWidget) + +from apps4ops.bdbase.base import BaseWindow +from apps4ops.bdbase.enumkind import MsgSeverity, UserMode, Facility +from apps4ops.bdbase.helpbrowser import HelpBrowser +from apps4ops.proscan.sendelogproscan import QSendToELOG + +from apps4ops.proscan.enumkind import ElogPROSCAN + +from src.gui import AppGui +from pyrcc5 import hush_resources + +_pymodule = os.path.basename(__file__) +_appname, _appext = _pymodule.split(".") +_appversion = "1.0.0" +#_title = """Power Usage & Saving Hierarchy""" #, HUSH!""" +_title = """HUSH!""" + +def _line(): + """Macro to return the current line number. + + The current line number within the file is used when + reporting messages to the message logging window. + + Returns: + int: Current line number. + """ + return inspect.currentframe().f_back.f_lineno + +class StartMain(BaseWindow): + trigger_log_message = Signal(str, str, int, str, dict) + + def __init__(self, parent=None): + super(StartMain, self).__init__( + parent=parent, pymodule=_pymodule, appversion=_appversion, + title=_title, user_mode=UserMode.OPERATION, facility=Facility.PROSCAN, + has_optics=False, has_procedure=False) + + self.appname = _appname + self.gui = AppGui(self) + + + @Slot() + def send_to_elog(self): + + @Slot() + def save_fig_thread_finished(): + + time.sleep(0.2) + + if self.all_data: + QSendToELOG(self, logbook=self.logbook, + eintragIdx=self.eintrag_idx, + systemIdx=self.system_idx, + effektIdx=self.effekt_idx, + title=self.title, + message=self.message, + attachFile=self.attach_files) + + time.sleep(1.0) + return + + #if not self.verify_send_to_elog(): + # return + + + elog = ElogPROSCAN() + + + self.system_idx = elog.system.GENERAL + self.eintrag_idx = elog.eintrag.INFO + self.effekt_idx = elog.effekt.NO + + + self.attach_files = [] + + _simulation = self.input_parameters['simulation'] + + if self.all_data: + if self.all_data['Input data'] is not None: + try: + _simulation = self.all_data['Input data']['simulation'] + except KeyError: + _simulation = self.input_parameters['simulation'] + pass + + + self.logbook = "Sandkasten" if _simulation else "Proscan" + self.title = _title + + sector = ["Copyright © Paul Scherrer Institut (PSI). + All rights reserved.
+Author: J. Chrin, Spring 2023
+(EPICS db adapted from A. Kovach, 2016)
+
IOC Administrator: H. Lutz
+1st Responsible: J. Chrin + or 3301 (Control Room)
+ +Initiates energy saving procedures and records power saved
+Python {2} - Qt {3} - PyQt {4}
+ cafe {5} - epics {6} on {7}""".format(
+ _pymodule, _appversion, platform.python_version(),
+ QT_VERSION_STR, PYQT_VERSION_STR,
+ self.cafe.CAFE_version(), self.cafe.EPICS_version(),
+ platform.system()))
+ QApplication.processEvents()
+
+ @Slot()
+ def show_help(self):
+ """ Invoke help pages from hush_resources
+ """
+ index_html ="index.html" #self.appname + "/index.html"
+ help_base = ":" # + self.appname
+ help_page = HelpBrowser(help_base, index_html, self)
+ help_page.show()
+
+#########################################################################
+if __name__ == "__main__":
+
+ app = QApplication(sys.argv)
+ splash = BaseWindow.initialize_application(
+ app, appname=_appname, delay=20, facility=Facility.PROSCAN)
+
+ myapp = StartMain()
+
+ myapp.show()
+
+ if splash is not None:
+ splash.finish(myapp)
+
+ app.exec_()
+
diff --git a/hush.sh b/hush.sh
new file mode 100755
index 0000000..a832307
--- /dev/null
+++ b/hush.sh
@@ -0,0 +1,99 @@
+#!/bin/bash
+cd /proscan/bd/applications/hush/hla/1.0.0
+
+# For use if script is sourced rather than executed
+appNameDefault="hush.sh"
+
+module unload gcc
+module load gcc/7.3.0
+
+if [ -z "$PS1" ] # no prompt?
+### if [ -v PS1 ] # On Bash 4.2+ ...
+then
+ # non-interactive
+ echo "Non-interactive script"
+else
+ # interactive
+ echo "Interactive/sourced script"
+fi
+
+# Select Python Version here. Currently one of 3.5, 3.7
+PYTHON_VERSION=3.7
+
+if [ "$1" ]; then
+
+ if [ "$1" == "3.5" -o "$1" == "35" ]; then
+ echo "Using default version $PYTHON_VERSION"
+ elif [ "$1" == "3.7" -o "$1" == "37" ]; then
+ PYTHON_VERSION=3.7
+ else
+ echo "Requested Python version is not supported"
+ echo "Using default version $PYTHON_VERSION"
+ fi
+
+fi
+
+echo "PYTHON_VERSION $PYTHON_VERSION"
+
+_EPICS_HOST_ARCH=${RHREL}-x86_64
+#_EPICS_HOST_ARCH=${EPICS_HOST_ARCH}
+. /opt/gfa/python $PYTHON_VERSION
+
+#/sf/bd/applications/OnlineModel/current/PythonModule:/sf/bd/applications/OnlineModel/current
+#/sf/bd/applications/OnlineModel/default/scripts/VA:
+
+#C_EXT version for Py 3.7:
+export PYTHONPATH=.:/opt/gfa/cafe/python/pycafe/cafe-1.19.3/lib/${_EPICS_HOST_ARCH}:/proscan/bd/applications/deps/apps4ops/v1.7.0
+
+
+echo $PYTHONPATH
+
+STDOUT_DIR="/tmp"
+#Set to 0 if you do not wish std::out to write to logger
+STDOUT_FLAG=1
+
+if [ "$#" -gt "0" ]; then
+ appName=$0
+ if [ "$appName" == "-bash" ]; then
+ appName=$appNameDefault
+ fi
+else
+appName=$appNameDefault
+fi
+
+#echo "$appName $@ $#"
+baseName="${appName##*/}"
+name=$(echo "$baseName" | cut -f 1 -d '.')
+nameLog=${name}-$USER
+echo "Application: $name"
+echo "nameLog: $nameLog"
+
+#Configuration files can be overwritten
+#python ${name}.py -s="/sf/bd/deps/pyqtacc/common/config/style.json" -f="/sf/bd/deps/pyqtacc/v1.0.0/pyqtacc/qrc_resources/facility/sf/config/base.json" -q="/sf/bd/deps/pyqtacc/common/config/acc.qss" &
+
+if [ "${STDOUT_FLAG}" -gt "0" ] ; then
+#if changing the std::out destination, remember to also change it in your json config file (for reading)
+ if test -f "$STDOUT_DIR/${nameLog}.log---"; then
+ rm -f $STDOUT_DIR/${nameLog}.log---
+ fi
+ if test -f "$STDOUT_DIR/${nameLog}.log--"; then
+ cp $STDOUT_DIR/${nameLog}.log-- $STDOUT_DIR/${nameLog}.log---
+ rm -f $STDOUT_DIR/${nameLog}.log--
+ fi
+ if test -f "$STDOUT_DIR/${nameLog}.log-"; then
+ cp $STDOUT_DIR/${nameLog}.log- $STDOUT_DIR/${nameLog}.log--
+ rm -f $STDOUT_DIR/${nameLog}.log-
+ fi
+ if test -f "$STDOUT_DIR/${nameLog}.log"; then
+ cp $STDOUT_DIR/${nameLog}.log $STDOUT_DIR/${nameLog}.log-
+ rm -f $STDOUT_DIR/${nameLog}.log
+ fi
+
+ python ${name}.py -u ${name}.json >> $STDOUT_DIR/${nameLog}.log 2>&1 &
+ chmod 777 $STDOUT_DIR/${nameLog}.log
+else
+#Run instead without std::out
+ python ${name}.py -u ${name}.json &
+fi
+
+
diff --git a/pyrcc5/hush_resources.py b/pyrcc5/hush_resources.py
new file mode 100644
index 0000000..e9707eb
--- /dev/null
+++ b/pyrcc5/hush_resources.py
@@ -0,0 +1,197 @@
+# -*- coding: utf-8 -*-
+
+# Resource object code
+#
+# Created by: The Resource Compiler for PyQt5 (Qt v5.15.3)
+#
+# WARNING! All changes made in this file will be lost!
+
+from PyQt5 import QtCore
+
+qt_resource_data = b"\
+\x00\x00\x00\xa7\
+\x3c\
+\x68\x74\x6d\x6c\x3e\x3c\x68\x65\x61\x64\x3e\x3c\x74\x69\x74\x6c\
+\x65\x3e\x57\x65\x62\x20\x48\x65\x6c\x70\x3c\x2f\x74\x69\x74\x6c\
+\x65\x3e\x3c\x2f\x68\x65\x61\x64\x3e\x0a\x3c\x62\x6f\x64\x79\x3e\
+\x0a\x0a\x3c\x70\x3e\x3c\x62\x3e\x50\x61\x67\x65\x20\x31\x20\x6f\
+\x66\x20\x77\x65\x62\x20\x68\x65\x6c\x70\x3c\x2f\x62\x3e\x3c\x2f\
+\x70\x3e\x0a\x3c\x70\x3e\x20\x20\x3c\x61\x20\x68\x72\x65\x66\x3d\
+\x22\x70\x61\x67\x65\x32\x2e\x68\x74\x6d\x6c\x22\x3e\x20\x4e\x65\
+\x78\x74\x3c\x2f\x61\x3e\x3c\x2f\x70\x3e\x0a\x3c\x70\x3e\x3c\x62\
+\x3e\x65\x74\x63\x2e\x2e\x2e\x3c\x2f\x62\x3e\x20\x65\x74\x63\x2e\
+\x2e\x2e\x3c\x2f\x70\x3e\x0a\x3c\x2f\x62\x6f\x64\x79\x3e\x3c\x2f\
+\x68\x74\x6d\x6c\x3e\x0a\
+\x00\x00\x03\x2c\
+\x3c\
+\x68\x74\x6d\x6c\x3e\x3c\x68\x65\x61\x64\x3e\x3c\x74\x69\x74\x6c\
+\x65\x3e\x48\x79\x70\x65\x72\x20\x50\x6f\x77\x65\x72\x20\x55\x73\
+\x61\x67\x65\x20\x61\x6e\x64\x20\x53\x61\x76\x69\x6e\x67\x20\x48\
+\x69\x67\x68\x6c\x69\x67\x68\x74\x73\x20\x61\x74\x20\x50\x72\x6f\
+\x73\x63\x61\x6e\x2c\x20\x48\x55\x53\x48\x21\x3c\x2f\x74\x69\x74\
+\x6c\x65\x3e\x3c\x2f\x68\x65\x61\x64\x3e\x0a\x3c\x62\x6f\x64\x79\
+\x3e\x0a\x0a\x3c\x68\x35\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\
+\x6f\x6c\x6f\x72\x3a\x67\x72\x61\x79\x3b\x22\x3e\x4a\x61\x6e\x75\
+\x61\x72\x79\x20\x32\x30\x32\x34\x2c\x20\x4a\x61\x6e\x20\x43\x68\
+\x72\x69\x6e\x20\x61\x6e\x64\x20\x2e\x2e\x2e\x3c\x2f\x68\x35\x3e\
+\x0a\x3c\x68\x34\x3e\x20\x3c\x73\x70\x61\x6e\x20\x73\x74\x79\x6c\
+\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x20\x72\x65\x64\x3b\x22\x3e\
+\x48\x3c\x2f\x73\x70\x61\x6e\x3e\x79\x70\x65\x72\x20\x3c\x73\x70\
+\x61\x6e\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\
+\x20\x67\x72\x61\x79\x3b\x22\x3e\x50\x6f\x77\x65\x72\x3c\x2f\x73\
+\x70\x61\x6e\x3e\x20\x3c\x73\x70\x61\x6e\x20\x73\x74\x79\x6c\x65\
+\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x20\x72\x65\x64\x3b\x22\x3e\x55\
+\x3c\x2f\x73\x70\x61\x6e\x3e\x73\x61\x67\x65\x20\x61\x6e\x64\x20\
+\x3c\x73\x70\x61\x6e\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\
+\x6f\x72\x3a\x20\x72\x65\x64\x3b\x22\x3e\x53\x3c\x2f\x73\x70\x61\
+\x6e\x3e\x61\x76\x69\x6e\x67\x20\x3c\x73\x70\x61\x6e\x20\x73\x74\
+\x79\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x20\x72\x65\x64\x3b\
+\x22\x3e\x48\x3c\x2f\x73\x70\x61\x6e\x3e\x69\x67\x68\x6c\x69\x67\
+\x68\x74\x73\x20\x61\x74\x20\x50\x72\x6f\x73\x63\x61\x6e\x2c\x20\
+\x3c\x73\x70\x61\x6e\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\
+\x6f\x72\x3a\x20\x72\x65\x64\x3b\x22\x3e\x48\x55\x53\x48\x21\x3c\
+\x2f\x73\x70\x61\x6e\x3e\x3c\x2f\x68\x34\x3e\x0a\x3c\x68\x32\x20\
+\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x62\x6c\x75\
+\x65\x3b\x22\x3e\x41\x62\x6f\x75\x74\x3c\x2f\x68\x32\x3e\x0a\x0a\
+\x3c\x70\x3e\x54\x68\x69\x73\x20\x3c\x62\x3e\x68\x75\x73\x68\x3c\
+\x2f\x62\x3e\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x20\
+\x69\x6e\x68\x65\x72\x69\x74\x73\x20\x66\x72\x6f\x6d\x20\x74\x68\
+\x65\x20\x57\x69\x6e\x64\x6f\x77\x20\x62\x61\x73\x65\x20\x63\x6c\
+\x61\x73\x73\x2e\x3c\x62\x72\x3e\x20\x20\x0a\x3c\x70\x3e\x69\x6e\
+\x66\x6f\x72\x6d\x61\x74\x69\x6f\x6e\x20\x63\x6f\x6e\x63\x65\x72\
+\x6e\x69\x6e\x67\x20\x74\x68\x69\x73\x20\x61\x70\x70\x6c\x69\x63\
+\x61\x74\x69\x6f\x6e\x2c\x20\x73\x75\x63\x68\x20\x61\x73\x20\x63\
+\x6f\x6e\x66\x69\x67\x75\x72\x61\x74\x69\x6f\x6e\x20\x70\x61\x72\
+\x61\x6d\x65\x74\x65\x72\x73\x20\x6f\x72\x20\x6f\x74\x68\x65\x72\
+\x2c\x20\x6d\x61\x79\x20\x62\x65\x20\x65\x6e\x74\x65\x72\x65\x64\
+\x2c\x20\x65\x2e\x67\x2e\x2c\x20\x3c\x61\x20\x68\x72\x65\x66\x3d\
+\x22\x70\x61\x67\x65\x31\x2e\x68\x74\x6d\x6c\x22\x3e\x68\x65\x72\
+\x65\x3c\x2f\x61\x3e\x3c\x2f\x70\x3e\x0a\x0a\x3c\x68\x32\x20\x73\
+\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x62\x6c\x75\x65\
+\x3b\x22\x3e\x54\x68\x65\x20\x50\x61\x6e\x65\x6c\x3c\x2f\x68\x32\
+\x3e\x0a\x0a\x3c\x70\x3e\x54\x68\x65\x73\x65\x20\x77\x65\x62\x20\
+\x70\x61\x67\x65\x73\x20\x61\x72\x65\x20\x74\x6f\x20\x62\x65\x20\
+\x63\x6f\x6d\x70\x6c\x65\x74\x65\x64\x20\x62\x79\x20\x74\x68\x65\
+\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x20\x6f\x77\x6e\
+\x65\x72\x2e\x3c\x62\x72\x3e\x0a\x0a\x0a\x0a\x0a\x3c\x2f\x62\x6f\
+\x64\x79\x3e\x3c\x2f\x68\x74\x6d\x6c\x3e\x0a\
+\x00\x00\x00\xa7\
+\x3c\
+\x68\x74\x6d\x6c\x3e\x3c\x68\x65\x61\x64\x3e\x3c\x74\x69\x74\x6c\
+\x65\x3e\x57\x65\x62\x20\x48\x65\x6c\x70\x3c\x2f\x74\x69\x74\x6c\
+\x65\x3e\x3c\x2f\x68\x65\x61\x64\x3e\x0a\x3c\x62\x6f\x64\x79\x3e\
+\x0a\x0a\x3c\x70\x3e\x3c\x62\x3e\x50\x61\x67\x65\x20\x34\x20\x6f\
+\x66\x20\x77\x65\x62\x20\x68\x65\x6c\x70\x3c\x2f\x62\x3e\x3c\x2f\
+\x70\x3e\x0a\x3c\x70\x3e\x20\x20\x3c\x61\x20\x68\x72\x65\x66\x3d\
+\x22\x70\x61\x67\x65\x35\x2e\x68\x74\x6d\x6c\x22\x3e\x20\x4e\x65\
+\x78\x74\x3c\x2f\x61\x3e\x3c\x2f\x70\x3e\x0a\x3c\x70\x3e\x3c\x62\
+\x3e\x65\x74\x63\x2e\x2e\x2e\x3c\x2f\x62\x3e\x20\x65\x74\x63\x2e\
+\x2e\x2e\x3c\x2f\x70\x3e\x0a\x3c\x2f\x62\x6f\x64\x79\x3e\x3c\x2f\
+\x68\x74\x6d\x6c\x3e\x0a\
+\x00\x00\x00\x80\
+\x3c\
+\x68\x74\x6d\x6c\x3e\x3c\x68\x65\x61\x64\x3e\x3c\x74\x69\x74\x6c\
+\x65\x3e\x57\x65\x62\x20\x48\x65\x6c\x70\x3c\x2f\x74\x69\x74\x6c\
+\x65\x3e\x3c\x2f\x68\x65\x61\x64\x3e\x0a\x3c\x62\x6f\x64\x79\x3e\
+\x0a\x0a\x3c\x70\x3e\x3c\x62\x3e\x50\x61\x67\x65\x20\x35\x20\x6f\
+\x66\x20\x77\x65\x62\x20\x68\x65\x6c\x70\x3c\x2f\x62\x3e\x3c\x2f\
+\x70\x3e\x0a\x0a\x3c\x70\x3e\x3c\x62\x3e\x65\x74\x63\x2e\x2e\x2e\
+\x3c\x2f\x62\x3e\x20\x65\x74\x63\x2e\x2e\x2e\x3c\x2f\x70\x3e\x0a\
+\x3c\x2f\x62\x6f\x64\x79\x3e\x3c\x2f\x68\x74\x6d\x6c\x3e\x0a\
+\x00\x00\x00\xa7\
+\x3c\
+\x68\x74\x6d\x6c\x3e\x3c\x68\x65\x61\x64\x3e\x3c\x74\x69\x74\x6c\
+\x65\x3e\x57\x65\x62\x20\x48\x65\x6c\x70\x3c\x2f\x74\x69\x74\x6c\
+\x65\x3e\x3c\x2f\x68\x65\x61\x64\x3e\x0a\x3c\x62\x6f\x64\x79\x3e\
+\x0a\x0a\x3c\x70\x3e\x3c\x62\x3e\x50\x61\x67\x65\x20\x33\x20\x6f\
+\x66\x20\x77\x65\x62\x20\x68\x65\x6c\x70\x3c\x2f\x62\x3e\x3c\x2f\
+\x70\x3e\x0a\x3c\x70\x3e\x20\x20\x3c\x61\x20\x68\x72\x65\x66\x3d\
+\x22\x70\x61\x67\x65\x34\x2e\x68\x74\x6d\x6c\x22\x3e\x20\x4e\x65\
+\x78\x74\x3c\x2f\x61\x3e\x3c\x2f\x70\x3e\x0a\x3c\x70\x3e\x3c\x62\
+\x3e\x65\x74\x63\x2e\x2e\x2e\x3c\x2f\x62\x3e\x20\x65\x74\x63\x2e\
+\x2e\x2e\x3c\x2f\x70\x3e\x0a\x3c\x2f\x62\x6f\x64\x79\x3e\x3c\x2f\
+\x68\x74\x6d\x6c\x3e\x0a\
+\x00\x00\x00\xa7\
+\x3c\
+\x68\x74\x6d\x6c\x3e\x3c\x68\x65\x61\x64\x3e\x3c\x74\x69\x74\x6c\
+\x65\x3e\x57\x65\x62\x20\x48\x65\x6c\x70\x3c\x2f\x74\x69\x74\x6c\
+\x65\x3e\x3c\x2f\x68\x65\x61\x64\x3e\x0a\x3c\x62\x6f\x64\x79\x3e\
+\x0a\x0a\x3c\x70\x3e\x3c\x62\x3e\x50\x61\x67\x65\x20\x32\x20\x6f\
+\x66\x20\x77\x65\x62\x20\x68\x65\x6c\x70\x3c\x2f\x62\x3e\x3c\x2f\
+\x70\x3e\x0a\x3c\x70\x3e\x20\x20\x3c\x61\x20\x68\x72\x65\x66\x3d\
+\x22\x70\x61\x67\x65\x33\x2e\x68\x74\x6d\x6c\x22\x3e\x20\x4e\x65\
+\x78\x74\x3c\x2f\x61\x3e\x3c\x2f\x70\x3e\x0a\x3c\x70\x3e\x3c\x62\
+\x3e\x65\x74\x63\x2e\x2e\x2e\x3c\x2f\x62\x3e\x20\x65\x74\x63\x2e\
+\x2e\x2e\x3c\x2f\x70\x3e\x0a\x3c\x2f\x62\x6f\x64\x79\x3e\x3c\x2f\
+\x68\x74\x6d\x6c\x3e\x0a\
+"
+
+qt_resource_name = b"\
+\x00\x0a\
+\x08\x4a\x34\x9c\
+\x00\x70\
+\x00\x61\x00\x67\x00\x65\x00\x31\x00\x2e\x00\x68\x00\x74\x00\x6d\x00\x6c\
+\x00\x0a\
+\x0c\xba\xf2\x7c\
+\x00\x69\
+\x00\x6e\x00\x64\x00\x65\x00\x78\x00\x2e\x00\x68\x00\x74\x00\x6d\x00\x6c\
+\x00\x0a\
+\x08\x7a\x34\x9c\
+\x00\x70\
+\x00\x61\x00\x67\x00\x65\x00\x34\x00\x2e\x00\x68\x00\x74\x00\x6d\x00\x6c\
+\x00\x0a\
+\x08\x8a\x34\x9c\
+\x00\x70\
+\x00\x61\x00\x67\x00\x65\x00\x35\x00\x2e\x00\x68\x00\x74\x00\x6d\x00\x6c\
+\x00\x0a\
+\x08\x6a\x34\x9c\
+\x00\x70\
+\x00\x61\x00\x67\x00\x65\x00\x33\x00\x2e\x00\x68\x00\x74\x00\x6d\x00\x6c\
+\x00\x0a\
+\x08\x5a\x34\x9c\
+\x00\x70\
+\x00\x61\x00\x67\x00\x65\x00\x32\x00\x2e\x00\x68\x00\x74\x00\x6d\x00\x6c\
+"
+
+qt_resource_struct_v1 = b"\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x06\x00\x00\x00\x01\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
+\x00\x00\x00\x82\x00\x00\x00\x00\x00\x01\x00\x00\x05\xb5\
+\x00\x00\x00\x68\x00\x00\x00\x00\x00\x01\x00\x00\x05\x0a\
+\x00\x00\x00\x34\x00\x00\x00\x00\x00\x01\x00\x00\x03\xdb\
+\x00\x00\x00\x4e\x00\x00\x00\x00\x00\x01\x00\x00\x04\x86\
+\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x01\x00\x00\x00\xab\
+"
+
+qt_resource_struct_v2 = b"\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x06\x00\x00\x00\x01\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
+\x00\x00\x01\x8d\x3b\x71\x36\x5d\
+\x00\x00\x00\x82\x00\x00\x00\x00\x00\x01\x00\x00\x05\xb5\
+\x00\x00\x01\x8d\x3b\x71\x36\x75\
+\x00\x00\x00\x68\x00\x00\x00\x00\x00\x01\x00\x00\x05\x0a\
+\x00\x00\x01\x8d\x3b\x71\x36\x78\
+\x00\x00\x00\x34\x00\x00\x00\x00\x00\x01\x00\x00\x03\xdb\
+\x00\x00\x01\x8d\x3b\x71\x36\x90\
+\x00\x00\x00\x4e\x00\x00\x00\x00\x00\x01\x00\x00\x04\x86\
+\x00\x00\x01\x8d\x3b\x71\x36\x94\
+\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x01\x00\x00\x00\xab\
+\x00\x00\x01\x8d\x3b\x78\x4e\xc0\
+"
+
+qt_version = [int(v) for v in QtCore.qVersion().split('.')]
+if qt_version < [5, 8, 0]:
+ rcc_version = 1
+ qt_resource_struct = qt_resource_struct_v1
+else:
+ rcc_version = 2
+ qt_resource_struct = qt_resource_struct_v2
+
+def qInitResources():
+ QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+def qCleanupResources():
+ QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+qInitResources()
diff --git a/src/gui.py b/src/gui.py
new file mode 100644
index 0000000..e0d7ec9
--- /dev/null
+++ b/src/gui.py
@@ -0,0 +1,695 @@
+import inspect
+import os
+import platform
+import random
+import sys
+import time
+from datetime import timedelta
+
+
+from qtpy import QtCore, QtGui
+from qtpy.QtGui import QColor, QFont, QIcon
+from qtpy.QtCore import __version__ as QT_VERSION_STR
+from qtpy.QtCore import (
+ PYQT_VERSION_STR, QDate, QDateTime, QEventLoop, Qt, Signal, Slot)
+from qtpy.QtWidgets import (
+ QApplication, QDockWidget, QFrame, QGridLayout, QGroupBox, QHBoxLayout,
+ QLabel, QMainWindow, QMessageBox, QProgressBar, QPushButton, QSizePolicy,
+ QSpacerItem, QStackedWidget, QTabBar, QTabWidget, QTableWidget,
+ QTableWidgetItem, QVBoxLayout, QWidget)
+
+
+from apps4ops.bdbase.base import BaseWindow
+from apps4ops.bdbase.enumkind import MsgSeverity, UserMode, Facility
+from caqtwidgets.pvwidgets import CAQLabel, CAQLineEdit, CAQTableWidget, QHLine
+
+_pymodule = os.path.basename(__file__)
+
+def _line():
+ """Macro to return the current line number.688
+
+ The current line number within the file is used when
+ reporting messages to the message logging window.
+
+ Returns:
+ int: Current line number.
+ """
+ return inspect.currentframe().f_back.f_lineno
+
+class AppGui(QWidget):
+
+ def __init__(self, parent):
+ super(AppGui, self).__init__()
+ self.parent = parent
+ self.cafe = self.parent.cafe
+ self.cyca = self.parent.cyca
+
+ self.send_to_log_window = self.parent.send_to_log_window
+ 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.operator_parameters_group.setFixedWidth(260)
+ #self.gui_frame.operator_parameters_group.setFixedHeight(260)
+ self.gui_frame.measurement_tab_wgt.setMinimumWidth(440)
+ self.gui_frame.measurement_tab_wgt.setFixedHeight(280)
+ #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.obj_to_upper = True if random.randint(1, 10) > 3 else False
+
+ self.table_sol_dict = {}
+ self.table_pwr_dict = {}
+ self.offtime_dict = {}
+
+ self.I_min = 1.0
+
+
+ sec_state_list = ['PG1-HUSH:STATE', 'PSH-HUSH:STATE',
+ 'PG2-HUSH:STATE', 'PO2-HUSH:STATE',
+ 'PPIF-HUSH:STATE', 'PG3-HUSH:STATE']
+
+ self.cafe.openPrepare()
+ self.cafe.open(['PRO-HUSH:LASTPWR','PRO-HUSH:TOTPWR',
+ 'PRO:LASTSAVE', 'PPO-HUSH:TOTSAVE'])
+ self.cafe.open(sec_state_list)
+ self.cafe.openNowAndWait(0.1)
+
+
+ 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)
+
+ qf = QFrame()
+ qf.setFixedHeight(6)
+ self.gui_frame.measurement_layout.addWidget(
+ qf, 4, 0, 1, 1, alignment=Qt.AlignTop)
+
+ self.sectorI_dict = {}
+ self.sectorI_dict['G1'] = "Geschlossen"
+ self.sectorI_dict['SH'] = "Geschlossen"
+ self.sectorI_dict['G2'] = "Geschlossen"
+ self.sectorI_dict['O2'] = "Geschlossen"
+ self.sectorI_dict['PIF'] = "Geschlossen"
+ self.sectorI_dict['G3'] = "Geschlossen"
+
+ g3_line = ["SH", "PIF", "G3"]
+ pif_line = ["SH", "PIF"]
+ o2_line = ["SH", "O2"]
+ g2_line = ["SH", "G2"]
+
+ def enable_disable_beamline(sect, sector_line, value):
+ self.sectorI_dict[sect] = value
+ #print("sect/value", sect, value)
+ for sector in sector_line:
+ if "Geschlossen" not in self.sectorI_dict[sector]:
+ #print("sector/value", sector, value)
+ if self.table_sol_dict[
+ sector].standby_value_button.isEnabled():
+ self.table_sol_dict[
+ sector].standby_value_button.setEnabled(False)
+ print("DISABLE", sector)
+ else:
+ #print("Geschlossen? sector/value", sector, value)
+ if not self.table_sol_dict[
+ sector].standby_value_button.isEnabled():
+ self.table_sol_dict[
+ sector].standby_value_button.setEnabled(True)
+
+
+ def receive_g3_update(value, status, alarm_severity):
+ print("receive_g3_update", flush=True)
+ enable_disable_beamline('G3', g3_line, value)
+ def receive_o2_update(value, status, alarm_severity):
+ enable_disable_beamline('O2', o2_line, value)
+ def receive_g2_update(value, status, alarm_severity):
+ enable_disable_beamline('G2', g2_line, value)
+ def receive_pif_update(value, status, alarm_severity):
+ enable_disable_beamline('PIF', pif_line, value)
+
+ self.gui_header.beam_current_wgt_dict[
+ "G3"].trigger_monitor_str.connect(receive_g3_update)
+ self.gui_header.beam_current_wgt_dict[
+ "O2"].trigger_monitor_str.connect(receive_o2_update)
+ self.gui_header.beam_current_wgt_dict[
+ "G2"].trigger_monitor_str.connect(receive_g2_update)
+ self.gui_header.beam_current_wgt_dict[
+ "PIF"].trigger_monitor_str.connect(receive_pif_update)
+
+ pvd=self.cafe.getPVCache(self.settings.data["G3"]["status"], dt='str')
+ receive_g3_update(pvd.value[0], pvd.alarmStatus, pvd.alarmSeverity)
+ pvd=self.cafe.getPVCache(self.settings.data["PIF"]["status"], dt='str')
+ receive_pif_update(pvd.value[0], pvd.alarmStatus, pvd.alarmSeverity)
+ pvd=self.cafe.getPVCache(self.settings.data["G2"]["status"], dt='str')
+ receive_g2_update(pvd.value[0], pvd.alarmStatus, pvd.alarmSeverity)
+ pvd=self.cafe.getPVCache(self.settings.data["O2"]["status"], dt='str')
+ receive_o2_update(pvd.value[0], pvd.alarmStatus, pvd.alarmSeverity)
+
+ def receive_sec_state(handle, pv, pvdata):
+ pvsplit = pv.split("-")
+ secsplit = pvsplit[0].split("P")
+ sec = secsplit[1]
+ if pvdata.value[0] == 'ON':
+ #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)
+
+ for state in sec_state_list:
+ self.cafe.monitor(state, receive_sec_state)
+
+
+
+ def group_sector_status(self):
+ qgrid = QGridLayout()
+ #Connect all channels
+ #Heading
+ idx = self.settings.data["header"].index("G1")
+ idx_last = self.settings.data["header"].index("MASTER")
+ #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, 5, 1, 1)
+ qgrid.addWidget(qtotsav, 0, 6, 1, 1)
+
+
+ for i, sector in enumerate(self.settings.data["header"][idx:idx_last]):
+ 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, 5, 1, 1)
+ qgrid.addWidget(f, i+1, 6, 1, 1)
+ _line = QHLine()
+ _line.setFixedHeight(10)
+ _row = qgrid.rowCount()
+ qgrid.addWidget(_line, _row, 1, 1, 6)
+ #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="PRO-HUSH:LASTPWR", show_units=True),
+ _row+1, 1, 1, 1)
+ qgrid.addWidget(
+ CAQLineEdit(self, pv_name="PRO-HUSH:TOTPWR", show_units=True),
+ _row+1, 2, 1, 1)
+ qgrid.addWidget(
+ CAQLineEdit(self, pv_name="PRO-HUSH:LASTSAVE", show_units=True),
+ _row+1, 3, 1, 2)
+ qgrid.addWidget(
+ CAQLineEdit(self, pv_name="PRO-HUSH:TOTSAVE", show_units=True),
+ _row+1, 6, 1, 2)
+
+ qgrid.setContentsMargins(9, 20, 9, 9)
+
+ qw = QGroupBox("Savings Overview")
+ qw.setContentsMargins(9, 9, 9, 9)
+ qw.setObjectName("OUTER")
+ qw.setLayout(qgrid)
+ qw.setFixedWidth(596) #480
+
+ #for column_no in range(0, 5):
+ # qgrid.itemAtPosition(1, column_no).widget().setStyleSheet("QWidget { background: lightblue; }") #addStyleName(
+ #item = qgrid.itemAt(2) #.widget().setStyleSheet("QLabel { background-color: green }")
+ #item.widget().setStyleSheet("background-color: green") #widgets on grid from left to right starting at top rtow
+ return qw
+
+
+
+
+ def sector_status(self, sector):
+ '''Create each sector line for inclusion into group
+ '''
+ #device = "SEC-" + sector
+ device = "P" + 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)
+
+ #print("device", device, flush=True)
+ def cb_outtime(handle, pv, pvdata):
+ try:
+ _delta = "{}".format(str(timedelta(seconds=(pvdata.value[0]))))
+ if ", " in _delta:
+ _split = _delta.split(", ")
+ if len(_split[1]) == len("0:00:00"):
+ _delta = _split[0] + ", " + _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
+
+ #Time to allow cb_outtime to fire
+ time.sleep(0.5)
+
+
+ qptime.setFixedWidth(104)
+
+ #qtdis = QBasicTimer()
+ #qpnow.setAlignment(Qt.AlignRight)
+ #qpnow.style().polish(qpnow)
+ return qsector, qpinit, qpnow, qpsave, qptime, qptotsave
+
+ def group_sector_qtabwidget(self):
+
+ idx_last = self.settings.data["header"].index("MASTER")
+ idx = self.settings.data["header"].index("G1")
+
+ #open all PVS
+ pv = []
+ for sector in self.settings.data["header"][idx:idx_last]:
+
+ 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 = {}
+
+ for sector in self.settings.data["header"][idx:idx_last]:
+ 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:idx_last]):
+ 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 check_status_list(self, pv_list, status_list, line):
+ _brk = ("------------------------------------------------------" +
+ "------------------------------------------------------")
+ self.parent.trigger_log_message.emit(
+ MsgSeverity.INFO.name, _pymodule, line, _brk, {})
+
+ _options = {}
+
+ for pv, stat in zip(pv_list, status_list):
+ if stat != self.cyca.ICAFE_NORMAL:
+ _mess = ("Error in 'set' for " + pv + " ")
+ _options['statusCode'] = (
+ str(stat) + " " +
+ self.cafe.getStatusCodeAsString(stat))
+ _options['statusInfo'] = self.cafe.getStatusInfo(stat)
+
+ self.parent.trigger_log_message.emit(
+ MsgSeverity.WARN.name, _pymodule, line, _mess, _options)
+
+
+ self.parent.trigger_log_message.emit(
+ MsgSeverity.INFO.name, _pymodule, line, _brk, {})
+
+ _mess = ("The following devices reported an error " +
+ "in 'set' operation:")
+ self.parent.trigger_log_message.emit(
+ MsgSeverity.INFO.name, _pymodule, line, _mess, {})
+
+ def check_status(self, pv, stat, line):
+ if stat != self.cyca.ICAFE_NORMAL:
+ _mess = ("Error in 'set' for " + pv + ".")
+ _options = {}
+ _options['statusCode'] = (
+ str(stat) + " " +
+ self.cafe.getStatusCodeAsString(stat))
+ _options['statusInfo'] = self.cafe.getStatusInfo(
+ stat)
+ self.parent.trigger_log_message.emit(
+ MsgSeverity.WARN.name, _pymodule, line,
+ _mess, _options)
+
+ 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"
+ '''
+
+ if self.table_pwr_dict[sector].init_value_button.isEnabled() \
+ and _table.init_value_button.isEnabled():
+ return True
+ else:
+ return False
+
+
+ QApplication.processEvents(QEventLoop.AllEvents, 1.0)
+
+ #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!!
+
+
+ if is_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.0)
+
+
+
+ if not self.input_parameters['simulation']:
+ status, status_list, pv_list = _table.set_standby_values()
+
+ if status != self.cyca.ICAFE_NORMAL:
+ self.check_status_list(pv_list, status_list, _line())
+
+ pv = 'P' + target.sector + "-HUSH:STATE"
+ stat = self.cafe.set(pv, 0)
+ self.check_status(pv, stat, _line())
+
+
+ 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())
+
+ pv = 'P' + 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 = 'P' + target.sector + "-HUSH:LASTPWR"
+
+ stat = self.cafe.set(pv_last_pwr, sum_pwr)
+ self.check_status(pv_last_pwr, stat, _line())
+
+
+ def ca_table_sector_widget(self, sector: str="", color: str="MACHINE"):
+ device_list = self.settings.data[sector]["device"]
+ attribute_list = self.settings.data[sector]["attribute"]
+ try:
+ _standby_values = self.settings.data[sector]["standby"]
+ print("Standby Values", sector, _standby_values, flush=True)
+ except KeyError as ex:
+ print("On Standby values not given for sector {0}".format(sector))
+
+ 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)
+
+ _table_height = 700
+
+ try:
+ _delay = self.input_parameters["delayRamp"]
+ except KeyError:
+ _delay = 0.09
+ pass
+
+ print(pv_dict['SOL:2'], flush=True)
+ print(_standby_values, flush=True)
+ 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'], 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'], 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')
+ 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)
+
+
+ pvStatus = self.settings.data[sector]['status']
+ beamline_status = self.cafe.getCache(pvStatus)
+ if beamline_status is not None:
+ #if I < self.I_min:
+ if "Geschlossen" in beamline_status:
+ 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
+
+ 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 = "P" + 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())
+
+ 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