"""Interface to handle general status."""
import numpy as _np
import logging as _log
from qtpy.QtCore import Qt
from qtpy.QtWidgets import QWidget, QGroupBox, QGridLayout, QLabel
from pydm.widgets.base import PyDMWidget
from siriuspy.envars import VACA_PREFIX
from siriuspy.diagsys.psdiag.csdev import get_ps_diag_status_labels
from siriuspy.diagsys.pudiag.csdev import get_pu_diag_status_labels
from siriuspy.diagsys.lidiag.csdev import get_li_diag_status_labels
from siriuspy.diagsys.rfdiag.csdev import get_rf_diag_status_labels
from siriuspy.namesys import SiriusPVName
from siriuspy.util import get_bit
from siriushla.widgets import PyDMLed
from siriushla.widgets.dialog.pv_status_dialog import StatusDetailDialog
from siriushla.util import run_newprocess
from .util import get_label2devices, get_dev2sub_labels, get_col2dev_count, \
get_sec2dev_laypos
[docs]
class PSMonitor(QWidget):
"""PS Monitor."""
def __init__(self, parent=None, prefix=VACA_PREFIX,
get_label2devices_method=None,
get_dev2sublabels_method=None,
get_col2devcount_method=None,
get_sec2devlaypos_method=None):
"""Init."""
super().__init__(parent)
self._prefix = prefix
self.get_label2devices = \
get_label2devices_method or get_label2devices
self.get_dev2sub_labels = \
get_dev2sublabels_method or get_dev2sub_labels
self.get_col2dev_count = \
get_col2devcount_method or get_col2dev_count
self.get_sec2dev_laypos = \
get_sec2devlaypos_method or get_sec2dev_laypos
self.setObjectName('ASApp')
self._setupUi()
def _setupUi(self):
self.title = QLabel('<h2>PS & PU</h2>',
alignment=Qt.AlignCenter)
self.title.setStyleSheet('max-height:1.29em;')
layout = QGridLayout(self)
layout.setHorizontalSpacing(12)
layout.addWidget(self.title, 0, 0, 1, 2)
for sec in ['LI', 'TB', 'BO', 'TS', 'SI']:
status = self._make_groupbox(sec)
if sec == 'LI':
layout.addWidget(status, 1, 0)
elif sec == 'TB':
layout.addWidget(status, 1, 1)
elif sec == 'BO':
layout.addWidget(status, 2, 0)
elif sec == 'TS':
layout.addWidget(status, 2, 1)
elif sec == 'SI':
layout.addWidget(status, 3, 0, 1, 2)
layout.setColumnStretch(0, 6)
layout.setColumnStretch(1, 5)
self.setStyleSheet("""
QLed {
min-height: 1.1em; max-height: 1.1em;
min-width: 1.1em; max-width: 1.1em;}
""")
def _make_groupbox(self, sec):
status = QGroupBox(sec, self)
status_lay = QGridLayout()
status_lay.setAlignment(Qt.AlignTop)
status.setStyleSheet("QLabel{max-height: 1.4em;}")
status.setLayout(status_lay)
def update_gridpos(row, col, col_count, offset=0):
new_col = offset if col == offset+col_count-1 else col+1
new_row = row+1 if new_col == offset else row
return [new_row, new_col]
row, col = 0, 0
for label, devices in self.get_label2devices(sec).items():
if not devices:
continue
grid = QGridLayout()
grid.setVerticalSpacing(6)
grid.setHorizontalSpacing(6)
if sec == 'BO' and label in ['CH', 'CV']:
desc = QLabel(label, self, alignment=Qt.AlignRight)
grid.addWidget(desc, 0, 0)
for i in range(5):
lbh = QLabel('{0:02d}'.format(i*2+1),
self, alignment=Qt.AlignRight)
lbh.setStyleSheet("QLabel{max-width:2em;}")
grid.addWidget(lbh, 0, i+1)
lbv = QLabel('{0:02d}'.format(i*10),
self, alignment=Qt.AlignRight)
lbv.setStyleSheet("QLabel{max-width:2em;}")
grid.addWidget(lbv, i+1, 0)
aux_row, aux_col, offset = 1, 1, 1
if label == 'CV':
aux = devices.pop(-1)
devices.insert(0, aux)
elif sec == 'SI':
if label not in ['FCH', 'FCV']:
aux = devices.pop(-1)
devices.insert(0, aux)
if label == 'Trims':
aux = devices.pop(-1)
devices.insert(0, aux)
if label in ['QS', 'FCV']:
for i in range(1, 21):
lb = QLabel('{0:02d}'.format(i), self)
grid.addWidget(lb, i+1, (0 if label == 'QS' else 5))
if label in ['QS', 'CH', 'CV', 'Trims', 'FCH', 'FCV']:
aux_row, aux_col = 2, (1 if label == 'QS' else 0)
offset = (1 if label == 'QS' else 0)
i = 0
for text in self.get_dev2sub_labels(label):
lbh = QLabel(text, self, alignment=Qt.AlignCenter)
grid.addWidget(lbh, 1, offset+i)
i += 1
else:
aux_row, aux_col, offset = 1, 0, 0
grid.addWidget(QLabel(label, self), 0, offset, 1, 4)
else:
grid.addWidget(QLabel(label, self), 0, 0, 1, 4)
aux_row, aux_col, offset = 1, 0, 0
for name in devices:
if label == 'Trims' and aux_row in (2, 6, 10, 14, 18) \
and aux_col in (0, 3):
grid.addWidget(QLabel(''), aux_row, aux_col)
aux_col += 1
elif label in ['FCH', 'FCV'] and aux_row == 2 and aux_col == 0:
grid.addWidget(QLabel(''), aux_row, aux_col, 1, 2)
aux_col += 2
led = MyLed(self, SiriusPVName(name).substitute(
prefix=self._prefix, propty='DiagStatus-Mon'), name)
grid.addWidget(led, aux_row, aux_col)
aux_row, aux_col = update_gridpos(
aux_row, aux_col, self.get_col2dev_count(sec, label),
offset)
row, col, rowc, colc = self.get_sec2dev_laypos(sec, label)
status_lay.addLayout(grid, row, col, rowc, colc,
alignment=Qt.AlignTop)
if sec == 'LI':
status_lay.setColumnStretch(0, 2)
status_lay.setColumnStretch(1, 5)
status_lay.setColumnStretch(2, 7)
status_lay.setColumnStretch(3, 3)
status_lay.setColumnStretch(4, 2)
status_lay.setVerticalSpacing(12)
status_lay.setHorizontalSpacing(16)
elif sec == 'SI':
status_lay.setColumnStretch(0, 1)
status_lay.setColumnStretch(1, 2)
status_lay.setColumnStretch(2, 2)
status_lay.setColumnStretch(3, 3)
status_lay.setColumnStretch(4, 3)
status_lay.setColumnStretch(5, 8)
status_lay.setColumnStretch(6, 14)
status_lay.setColumnStretch(7, 3)
status_lay.setColumnStretch(8, 4)
status_lay.setColumnStretch(9, 4)
status_lay.setVerticalSpacing(12)
status_lay.setHorizontalSpacing(12)
else:
status_lay.setVerticalSpacing(12)
status_lay.setHorizontalSpacing(16)
return status
[docs]
class MyLed(PyDMLed):
"""Monitor Led."""
default_colorlist = [PyDMLed.LightGreen, PyDMLed.Yellow, PyDMLed.Red]
def __init__(self, parent=None, init_channel=None, init_tooltip='', **kws):
super().__init__(parent, **kws)
self.setToolTip(init_tooltip)
self.channel = init_channel
self.pvname = SiriusPVName(self.channels()[0].address)
dev = self.pvname.device_name
self.labels = list()
if self.pvname.dis == 'PS':
self.labels = get_ps_diag_status_labels(dev)
elif self.pvname.sec == 'LI':
self.labels = get_li_diag_status_labels(dev)
elif self.pvname.dis == 'PU':
self.labels = get_pu_diag_status_labels()
elif self.pvname.dis == 'RF':
self.labels = get_rf_diag_status_labels(dev)
self.dc_command = ''
if dev.dis == 'PS':
self.dc_command = ['sirius-hla-as-ps-detail.py', dev]
elif dev.dis == 'PU':
if dev.sec == 'LI':
self.dc_command = 'sirius-hla-li-pu-modltr.py'
else:
self.dc_command = ['sirius-hla-as-pu-detail.py', dev]
elif dev.dis == 'RF':
if dev.sec == 'LI':
self.dc_command = 'sirius-hla-li-rf-llrf.py'
else:
sec = self.pvname.sec.lower()
self.dc_command = 'sirius-hla-'+sec+'-rf-control.py'
elif dev.dis == 'EG':
self.dc_command = 'sirius-hla-li-eg-control.py'
[docs]
def mouseDoubleClickEvent(self, _):
"""Reimplement mouseDoubleClickEvent."""
if self.dc_command:
run_newprocess(self.dc_command)
[docs]
def mousePressEvent(self, event):
"""Reimplement mousePressEvent."""
if event.button() == Qt.RightButton and self.labels:
self.msg = StatusDetailDialog(
parent=self.parent(), pvname=self.pvname,
labels=self.labels)
self.msg.open()
super().mousePressEvent(event)
[docs]
def value_changed(self, new_val):
PyDMWidget.value_changed(self, new_val)
if new_val is None:
return
if isinstance(new_val, _np.ndarray):
_log.warning('PyDMLed received a numpy array to ' +
self.channel+' ('+str(new_val)+')!')
return
bits_set = [text for bit, text in enumerate(self.labels)
if get_bit(int(new_val), bit)]
state = 0 if len(bits_set) == 0 \
else 1 if len(bits_set) == 1 and \
bits_set[0] in ['Alarms', 'Alarms - Latch'] else 2
self.setState(state)