You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

330 lines
15 KiB
Python

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import re
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton, QGridLayout, \
QHBoxLayout, QMessageBox, QSplitter, QRadioButton
from UI.ProfibusWidgets.SoftKeyBoardEdit import SoftKeyBoardEdit
from utils import Globals
class ForceButton(QPushButton):
def __init__(self, number = None, valueLabel = None, valueEdit = None, qualityValueLabel = None, \
qualityLineEdit = None, btnName = None):
super().__init__()
self.valueEdit = valueEdit
self.valueLabel = valueLabel
self.qualityValueLabel = qualityValueLabel
self.qualityLineEdit = qualityLineEdit
self.number = number
self.setObjectName('profibusForceBtn')
self.setText(btnName)
class ForceRadioButton(QRadioButton):
def __init__(self, number = None):
super().__init__()
self.number = number
class RightAreaWidgets(QWidget):
def __init__(self, areaWidget, order, byteLineEdit, dataType, deviceName, valueName = None):
super().__init__()
self.areaLineEditValue = []
self.qualityEditValueList = []
self.areaLabel = {}
self.qualityLabel = {}
self.areaWidget = areaWidget
self.devicesManange = self.areaWidget.devicesManange
self.protocolManage = Globals.getValue('protocolManage')
self.order = order
self.byteLineEdit = byteLineEdit
self.dataType = dataType
self.deviceName = deviceName
self.valueName = valueName
if '主站' in self.deviceName and self.dataType == 'AI' or ('从站' in self.deviceName and self.dataType == 'AO'):
self.force = False
elif '主站' in self.deviceName and self.dataType == 'DI' or ('从站' in self.deviceName and self.dataType == 'DO'):
self.force = False
else:
self.force = True
self.addLayout()
# self.setStyleSheet("background-color: black")
def addLayout(self):
self.setLayout(self.areaLayout())
def areaLayout(self):
areaLayout = QVBoxLayout()
areaLayout.setContentsMargins(0, 0, 0, 0)
if self.dataType in ['AI','AO']:
hLayout = QHBoxLayout()
hLayout.addWidget(QSplitter())
hLayout.addLayout(self.dateLayout(0))
hLayout.addWidget(QSplitter())
areaLayout.addWidget(QSplitter())
areaLayout.addLayout(hLayout)
areaLayout.addWidget(QSplitter())
else:
byteLineEdit = int(self.byteLineEdit) * 4
areaLayout.addWidget(QSplitter())
for i in range(int(byteLineEdit)):
hLayout = QHBoxLayout()
hLayout.addWidget(QSplitter(), 1)
hLayout.addLayout(self.dateLayout(number = (i), isAnalog = False), 3)
hLayout.addWidget(QSplitter(), 1)
hLayout.addLayout(self.dateLayout(number = (i) + 8, isAnalog = False), 3)
hLayout.addWidget(QSplitter(), 1)
areaLayout.addLayout(hLayout)
areaLayout.addWidget(QSplitter())
return areaLayout
def dateLayout(self, number, isAnalog = True):
if not isAnalog:
forceLayout = QHBoxLayout()
valueRadio = ForceRadioButton(number = number)
valueRadio.setObjectName('valueRadio')
valueRadio.setAutoExclusive(False)
valueRadio.setText('OFF')
valueRadio.toggled.connect(self.DIDOForceValues)
massesageLabel = QLabel('通道 {} '.format(str(number + 1)))
massesageLabel.setObjectName('massesageLabel')
forceLayout.addWidget(massesageLabel)
forceLayout.addWidget(valueRadio)
forceLayout.setContentsMargins(0, 0, 0, 0)
forceLayout.setSpacing(0)
self.areaLabel[number] = valueRadio
if not self.force:
valueRadio.setEnabled(False)
else:
forceLayout = QGridLayout()
forceLayout.setContentsMargins(0, 0, 0, 0)
areaMessLabel = QLabel('当前值:' )
areaMessLabel.setObjectName('areaMessLabel')
areaValueLabel = QLabel('0')
areaValueLabel.setObjectName('areaValueLabel')
forceLayout.addWidget(areaMessLabel,0,0,1,1)
forceLayout.addWidget(areaValueLabel,0,1,1,1)
#添加质量位置layout
qualityLabel = QLabel('质量位状态值:' )
qualityLabel.setObjectName('areaMessLabel')
qualityValueLabel = QLabel('0')
qualityValueLabel.setObjectName('areaValueLabel')
forceLayout.addWidget(qualityLabel,1,0,1,1)
forceLayout.addWidget(qualityValueLabel,1,1,1,1)
qualityValueLabel.setFixedHeight(40)
if self.force:
areaLineEdit = SoftKeyBoardEdit('0')
areaLineEdit.setObjectName('areaLineEdit')
areaLineEdit.setFixedSize(80, 45)
qualityLineEdit = SoftKeyBoardEdit('80')
qualityLineEdit.setObjectName('areaLineEdit')
qualityLineEdit.setFixedSize(80, 45)
forceBtn = ForceButton(number = number, valueLabel=areaValueLabel, valueEdit=areaLineEdit, qualityValueLabel=qualityValueLabel, \
qualityLineEdit=qualityLineEdit, btnName = '强制')
forceBtn.clicked.connect(self.AIAOForceValues)
qualityBtn = ForceButton(number = number, valueLabel=areaValueLabel, valueEdit=areaLineEdit, qualityValueLabel=qualityValueLabel, \
qualityLineEdit=qualityLineEdit, btnName = '故障')
qualityBtn.clicked.connect(lambda: self.AIAOForceValues(qualityValue = '0'))
# forceBtn.setFixedSize(50, 27)
forceLayout.addWidget(areaLineEdit,0,2,1,1)
forceLayout.addWidget(forceBtn,0,3,1,1)
forceLayout.addWidget(qualityLineEdit,1,2,1,1)
forceLayout.addWidget(qualityBtn,1,3,1,1)
else:
self.areaLabel[number] = areaValueLabel
self.qualityLabel[number] = qualityValueLabel
self.areaLineEditValue.append(0)
self.qualityEditValueList.append(0)
# if self.deviceName[-2:] + self.dataType in ['从站DI','主站DO']:
# areaMessLabel.setObjectName('wirteDIDOareaMessLabel')
# areaValueLabel.setObjectName('wirteDIDOareaValueLabel')
# areaLineEdit.setObjectName('wirteDIDOareaLineEdit')
# areaLineEdit.setFixedSize(30, 27)
# areaLineEdit.setAlignment(Qt.AlignHCenter)
# forceBtn.setObjectName('wirteDIDOforceBtn')
# if self.deviceName[-2:] + self.dataType in ['主站DI','从站DO']:
# areaMessLabel.setObjectName('readDIDOareaMessLabel')
# areaValueLabel.setObjectName('readDIDOareaValueLabel')
# forceLayout.setSpacing(10)
return forceLayout
def wirteAreaLineEditValue(self,dataTypeAndModel, number, value, qualityValue = None, valueLabel = None, \
qualityValueLabel = None):
if self.areaWidget.okBtnValue:
QMessageBox.warning(self, '提示', '请先保存通道信息')
return
if dataTypeAndModel in ['主站AO','从站AI']:
pattern = re.compile(r'^[+-]?(\d+(\.\d*)?|\.\d+)$')
match = pattern.match(value)
hexPattern = re.compile(r'^(0x)?[0-9A-Fa-f]{1,2}$')
match2 = hexPattern.match(qualityValue)
if not match :
QMessageBox.warning(self, '提示', '请输入数字。')
return None, None
if not match2:
QMessageBox.warning(self, '提示', '请输入0-FF')
return None, None
else:
hexValue = int(match2.group(0), 16)
# 检查值是否小于等于 255
if hexValue > 255:
QMessageBox.warning(self, '提示', '请输入0-FF')
return None, None
else:
valueLabel.setText(str(float(value)))
qualityValueLabel.setText(str(qualityValue))
self.areaLineEditValue[number] = float(value)
# print(self.areaLineEditValue,number, qualityValue )
self.qualityEditValueList[number] = qualityValue
return self.areaLineEditValue , self.qualityEditValueList #返回值和质量位值
#判断输入值是否为0和1
elif dataTypeAndModel in ['主站DO','从站DI']:
self.areaLineEditValue[number] = value
return self.areaLineEditValue
def readValues(self, curIndex):
# print(curIndex)
if not self.force:
# 优先通过ProtocolManage读取这样可以获取RPC同步的值
if self.valueName and self.protocolManage:
try:
value = self.protocolManage.readVariableValue(self.valueName)
if value is not None:
# 处理从ProtocolManage获取的值
if isinstance(value, dict) and 'value' in value:
actualValue = value['value']
qualityValue = value.get('quality', '0x00')
else:
actualValue = value
qualityValue = '0x00'
# 更新UI显示
if self.dataType in ['AI', 'AO']:
# 模拟量显示
if 0 in self.areaLabel:
self.areaLabel[0].setText(str(actualValue))
if 0 in self.qualityLabel:
self.qualityLabel[0].setText(str(qualityValue))
else:
# 离散量显示
for index, label in self.areaLabel.items():
if isinstance(actualValue, list) and index < len(actualValue):
bitValue = actualValue[index]
if bitValue == 1:
label.setText('ON')
label.setChecked(True)
else:
label.setText('OFF')
label.setChecked(False)
else:
label.setText('OFF')
label.setChecked(False)
return
except Exception as e:
print(f"通过ProtocolManage读取变量 {self.valueName} 失败: {e}")
# 回退到直接从设备读取
device = self.devicesManange.getDevice(self.deviceName)
values, qualityValueList = device.getAreaValues(curIndex)
# print(qualityValueList)
# print(self.deviceName, curIndex, values)
if len(values) > len(self.areaLabel):
return
for index, value in enumerate(values):
# print(self.dataType, self.force)
if self.dataType in ['DI', 'DO'] and not self.force:
if value == 1:
value = 'ON'
self.areaLabel[index].setChecked(True)
else:
value = 'OFF'
self.areaLabel[index].setChecked(False)
self.areaLabel[index].setText(value)
continue
self.areaLabel[index].setText(str(value))
for index, value in enumerate(qualityValueList):
self.qualityLabel[index].setText(str(value))
# print(self.areaLabel[index],values)
def AIAOForceValues(self, qualityValue = None):
sender = self.sender()
number = sender.number
valueLabel = sender.valueLabel
qualityValueLabel = sender.qualityValueLabel
value = sender.valueEdit.text()
if qualityValue == '0':
qualityValue = '0'
else:
qualityValue = sender.qualityLineEdit.text()
# print(qualityValue)
dataTypeAndModel = self.deviceName[-2:] + self.dataType
curIndex = self.areaWidget.areaTabWidget.currentIndex()
valueList, qualityValueList = self.wirteAreaLineEditValue(dataTypeAndModel=dataTypeAndModel, number=number, value=value, qualityValue=qualityValue, \
valueLabel=valueLabel, qualityValueLabel=qualityValueLabel )
# print(valueList, qualityValueList,222)
if valueList is None:
return
else:
# 通过ProtocolManage写入以便触发RPC同步
if self.valueName and self.protocolManage:
# 构造写入值(包含质量值)
writeValue = {
'value': float(value),
'quality': qualityValue
}
success = self.protocolManage.writeVariableValue(self.valueName, writeValue)
if not success:
# 如果ProtocolManage写入失败回退到直接写入
self.devicesManange.writeAreas(deviceName = self.deviceName, areaIndex = curIndex, values = valueList, qualityValueList = qualityValueList)
else:
# 如果没有变量名或ProtocolManage不可用使用直接写入
self.devicesManange.writeAreas(deviceName = self.deviceName, areaIndex = curIndex, values = valueList, qualityValueList = qualityValueList)
def DIDOForceValues(self):
sender = self.sender()
number = sender.number
value = 1 if sender.isChecked() else 0
dataTypeAndModel = self.deviceName[-2:] + self.dataType
curIndex = self.areaWidget.areaTabWidget.currentIndex()
valueList = self.wirteAreaLineEditValue(dataTypeAndModel=dataTypeAndModel, number=number, value=value)
if valueList is None:
return
else:
# 通过ProtocolManage写入以便触发RPC同步
if self.valueName and self.protocolManage:
success = self.protocolManage.writeVariableValue(self.valueName, value)
if not success:
# 如果ProtocolManage写入失败回退到直接写入
self.devicesManange.writeAreas(deviceName = self.deviceName, areaIndex = curIndex, values = valueList)
else:
# 如果没有变量名或ProtocolManage不可用使用直接写入
self.devicesManange.writeAreas(deviceName = self.deviceName, areaIndex = curIndex, values = valueList)
if sender.isChecked():
sender.setText('ON')
else:
sender.setText('OFF')