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.

327 lines
17 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.

from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QGroupBox,
QLabel, QLineEdit, QPushButton, QComboBox,
QTabWidget, QMessageBox, QGridLayout, QDoubleSpinBox,
QSpinBox, QFormLayout, QCheckBox)
from PyQt5.QtCore import Qt
class HartCalibrationWidget(QWidget):
def __init__(self, parent=None):
super(HartCalibrationWidget, self).__init__(parent)
self.hartComm = None
self.initUI()
def initUI(self):
# 创建主布局
mainLayout = QVBoxLayout()
# --- 1. 标准校准区域 ---
calibGroup = QGroupBox("标准校准操作")
calibLayout = QVBoxLayout(calibGroup)
infoLabel1 = QLabel("标准校准操作将校准设备的测量值。请确保在执行校准前已正确连接设备。")
infoLabel1.setWordWrap(True)
calibLayout.addWidget(infoLabel1)
buttonLayout = QGridLayout()
self.calibrate4mAButton = QPushButton("4mA校准 (Command 37)")
self.calibrate20mAButton = QPushButton("20mA校准 (Command 36)")
self.calibrateZeroPointButton = QPushButton("零点校准 (Command 43)")
buttonLayout.addWidget(self.calibrate4mAButton, 0, 0)
buttonLayout.addWidget(self.calibrate20mAButton, 0, 1)
buttonLayout.addWidget(self.calibrateZeroPointButton, 1, 0, 1, 2)
calibLayout.addLayout(buttonLayout)
warningLabel1 = QLabel("警告:校准操作将修改设备的校准参数,请确保您知道您在做什么!")
warningLabel1.setStyleSheet("color: red;")
warningLabel1.setWordWrap(True)
calibLayout.addWidget(warningLabel1)
mainLayout.addWidget(calibGroup)
# --- 2. 环路电流微调区域 ---
trimGroup = QGroupBox("环路电流微调")
trimLayout = QVBoxLayout(trimGroup)
infoLabel2 = QLabel("环路电流微调用于精确调整4mA和20mA输出。请先进入固定电流模式使设备输出固定电流再使用高精度电流表测量实际输出电流然后输入测量值进行微调。")
infoLabel2.setWordWrap(True)
trimLayout.addWidget(infoLabel2)
trim4mAGroup = QGroupBox("4mA微调 (Command 45)")
trim4mALayout = QFormLayout(trim4mAGroup)
self.trim4mASpinBox = QDoubleSpinBox()
self.trim4mASpinBox.setRange(3.0, 5.0)
self.trim4mASpinBox.setSingleStep(0.001)
self.trim4mASpinBox.setDecimals(3)
self.trim4mASpinBox.setValue(4.0)
self.trim4mAButton = QPushButton("执行4mA微调")
trim4mALayout.addRow(QLabel("测量的电流值(mA):"), self.trim4mASpinBox)
trim4mALayout.addRow("", self.trim4mAButton)
trim20mAGroup = QGroupBox("20mA微调 (Command 46)")
trim20mALayout = QFormLayout(trim20mAGroup)
self.trim20mASpinBox = QDoubleSpinBox()
self.trim20mASpinBox.setRange(19.0, 21.0)
self.trim20mASpinBox.setSingleStep(0.001)
self.trim20mASpinBox.setDecimals(3)
self.trim20mASpinBox.setValue(20.0)
self.trim20mAButton = QPushButton("执行20mA微调")
trim20mALayout.addRow(QLabel("测量的电流值(mA):"), self.trim20mASpinBox)
trim20mALayout.addRow("", self.trim20mAButton)
trimLayout.addWidget(trim4mAGroup)
trimLayout.addWidget(trim20mAGroup)
warningLabel2 = QLabel("警告:微调操作将修改设备的校准参数,请确保使用高精度电流表测量!")
warningLabel2.setStyleSheet("color: red;")
warningLabel2.setWordWrap(True)
trimLayout.addWidget(warningLabel2)
mainLayout.addWidget(trimGroup)
# --- 3. 固定电流输出区域 ---
fixedCurrentGroup = QGroupBox("固定电流输出 (Command 40)")
fixedCurrentLayout = QVBoxLayout(fixedCurrentGroup)
infoLabel3 = QLabel("固定电流输出模式用于测试和校准目的。在此模式下,设备将输出固定电流值,不受测量值变化的影响。")
infoLabel3.setWordWrap(True)
fixedCurrentLayout.addWidget(infoLabel3)
self.enableFixedCurrentCheckBox = QCheckBox("启用固定电流输出")
fixedCurrentLayout.addWidget(self.enableFixedCurrentCheckBox)
fixedCurrentFormLayout = QFormLayout()
self.fixedCurrentSpinBox = QDoubleSpinBox()
self.fixedCurrentSpinBox.setRange(3.8, 21.0)
self.fixedCurrentSpinBox.setSingleStep(0.1)
self.fixedCurrentSpinBox.setDecimals(2)
self.fixedCurrentSpinBox.setValue(4.0)
self.fixedCurrentSpinBox.setEnabled(False)
fixedCurrentFormLayout.addRow(QLabel("固定电流值(mA):"), self.fixedCurrentSpinBox)
fixedCurrentLayout.addLayout(fixedCurrentFormLayout)
self.applyFixedCurrentButton = QPushButton("应用设置")
fixedCurrentLayout.addWidget(self.applyFixedCurrentButton)
warningLabel3 = QLabel("警告:启用固定电流输出模式将使设备不再响应测量值变化!请在完成测试后务必退出固定电流模式。")
warningLabel3.setStyleSheet("color: red;")
warningLabel3.setWordWrap(True)
fixedCurrentLayout.addWidget(warningLabel3)
mainLayout.addWidget(fixedCurrentGroup)
mainLayout.addStretch(1)
self.setLayout(mainLayout)
# --- 连接所有信号和槽 ---
self.calibrate4mAButton.clicked.connect(self.onCalibrate4mA)
self.calibrate20mAButton.clicked.connect(self.onCalibrate20mA)
self.calibrateZeroPointButton.clicked.connect(self.onCalibrateZeroPoint)
self.trim4mAButton.clicked.connect(self.onTrimLoopCurrent4mA)
self.trim20mAButton.clicked.connect(self.onTrimLoopCurrent20mA)
self.enableFixedCurrentCheckBox.toggled.connect(self.fixedCurrentSpinBox.setEnabled)
self.applyFixedCurrentButton.clicked.connect(self.onSetFixedCurrentOutput)
def setHartComm(self, hartComm):
"""设置HART通信对象"""
self.hartComm = hartComm
def onCalibrate4mA(self):
"""4mA校准 command 37"""
if not self.hartComm or not self.hartComm.isConnected():
QMessageBox.warning(self, "警告", "设备未连接,请先连接设备")
return
reply = QMessageBox.question(self, "确认", "确定要执行4mA校准吗此操作将修改设备校准参数。",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply != QMessageBox.Yes:
return
try:
raw_response = self.hartComm.calibrate4mA()
response_dict = raw_response[0] if isinstance(raw_response, list) and raw_response else raw_response
if isinstance(response_dict, dict) and response_dict.get("status") == "success":
details = self.formatResponseDetails(response_dict)
QMessageBox.information(self, "成功", f"4mA校准成功!\n\n{details}")
elif isinstance(response_dict, dict):
error_msg = response_dict.get("error", "未知错误")
QMessageBox.critical(self, "错误", f"4mA校准失败: {error_msg}")
else:
QMessageBox.critical(self, "错误", "4mA校准失败: 无效的响应格式")
except Exception as e:
QMessageBox.critical(self, "异常", f"4mA校准时发生异常: {str(e)}")
def onCalibrate20mA(self):
"""20mA校准 command 36"""
if not self.hartComm or not self.hartComm.isConnected():
QMessageBox.warning(self, "警告", "设备未连接,请先连接设备")
return
reply = QMessageBox.question(self, "确认", "确定要执行20mA校准吗此操作将修改设备校准参数。",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply != QMessageBox.Yes:
return
try:
raw_response = self.hartComm.calibrate20mA()
response_dict = raw_response[0] if isinstance(raw_response, list) and raw_response else raw_response
if isinstance(response_dict, dict) and response_dict.get("status") == "success":
details = self.formatResponseDetails(response_dict)
QMessageBox.information(self, "成功", f"20mA校准成功!\n\n{details}")
elif isinstance(response_dict, dict):
error_msg = response_dict.get("error", "未知错误")
QMessageBox.critical(self, "错误", f"20mA校准失败: {error_msg}")
else:
QMessageBox.critical(self, "错误", "20mA校准失败: 无效的响应格式")
except Exception as e:
QMessageBox.critical(self, "异常", f"20mA校准时发生异常: {str(e)}")
def onCalibrateZeroPoint(self):
"""零点校准 command 43"""
if not self.hartComm or not self.hartComm.isConnected():
QMessageBox.warning(self, "警告", "设备未连接,请先连接设备")
return
reply = QMessageBox.question(self, "确认", "确定要执行零点校准吗?此操作将修改设备校准参数。",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply != QMessageBox.Yes:
return
try:
raw_response = self.hartComm.calibrateZeroPoint()
response_dict = raw_response[0] if isinstance(raw_response, list) and raw_response else raw_response
if isinstance(response_dict, dict) and response_dict.get("status") == "success":
details = self.formatResponseDetails(response_dict)
QMessageBox.information(self, "成功", f"零点校准成功!\n\n{details}")
elif isinstance(response_dict, dict):
error_msg = response_dict.get("error", "未知错误")
QMessageBox.critical(self, "错误", f"零点校准失败: {error_msg}")
else:
QMessageBox.critical(self, "错误", "零点校准失败: 无效的响应格式")
except Exception as e:
QMessageBox.critical(self, "异常", f"零点校准时发生异常: {str(e)}")
def onTrimLoopCurrent4mA(self):
"""微调环路电流4mA command 45"""
if not self.hartComm or not self.hartComm.isConnected():
QMessageBox.warning(self, "警告", "设备未连接,请先连接设备")
return
measured_current = self.trim4mASpinBox.value()
reply = QMessageBox.question(self, "确认", f"确定要使用测量值 {measured_current} mA 执行4mA微调吗此操作将修改设备校准参数。",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply != QMessageBox.Yes:
return
try:
raw_response = self.hartComm.trimLoopCurrent4mA(measured_current)
response_dict = raw_response[0] if isinstance(raw_response, list) and raw_response else raw_response
if isinstance(response_dict, dict) and response_dict.get("status") == "success":
details = self.formatResponseDetails(response_dict)
QMessageBox.information(self, "成功", f"4mA环路电流微调成功!\n测量值: {measured_current} mA\n\n{details}")
elif isinstance(response_dict, dict):
error_msg = response_dict.get("error", "未知错误")
QMessageBox.critical(self, "错误", f"4mA环路电流微调失败: {error_msg}")
else:
QMessageBox.critical(self, "错误", "4mA环路电流微调失败: 无效的响应格式")
except Exception as e:
QMessageBox.critical(self, "异常", f"4mA环路电流微调时发生异常: {str(e)}")
def onTrimLoopCurrent20mA(self):
"""微调环路电流20mA command 46"""
if not self.hartComm or not self.hartComm.isConnected():
QMessageBox.warning(self, "警告", "设备未连接,请先连接设备")
return
measured_current = self.trim20mASpinBox.value()
reply = QMessageBox.question(self, "确认", f"确定要使用测量值 {measured_current} mA 执行20mA微调吗此操作将修改设备校准参数。",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply != QMessageBox.Yes:
return
try:
raw_response = self.hartComm.trimLoopCurrent20mA(measured_current)
response_dict = raw_response[0] if isinstance(raw_response, list) and raw_response else raw_response
if isinstance(response_dict, dict) and response_dict.get("status") == "success":
details = self.formatResponseDetails(response_dict)
QMessageBox.information(self, "成功", f"20mA环路电流微调成功!\n测量值: {measured_current} mA\n\n{details}")
elif isinstance(response_dict, dict):
error_msg = response_dict.get("error", "未知错误")
QMessageBox.critical(self, "错误", f"20mA环路电流微调失败: {error_msg}")
else:
QMessageBox.critical(self, "错误", "20mA环路电流微调失败: 无效的响应格式")
except Exception as e:
QMessageBox.critical(self, "异常", f"20mA环路电流微调时发生异常: {str(e)}")
def onSetFixedCurrentOutput(self):
"""设置固定电流输出/退出固定模式 command 40"""
if not self.hartComm or not self.hartComm.isConnected():
QMessageBox.warning(self, "警告", "设备未连接,请先连接设备")
return
enable = self.enableFixedCurrentCheckBox.isChecked()
current_value = self.fixedCurrentSpinBox.value() if enable else 0.0
if enable:
message = f"确定要启用固定电流输出模式,输出电流值为 {current_value} mA 吗?\n\n警告:启用此模式后,设备将不再响应测量值变化!"
else:
message = "确定要退出固定电流输出模式吗?"
reply = QMessageBox.question(self, "确认", message, QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply != QMessageBox.Yes:
return
try:
raw_response = self.hartComm.setFixedCurrentOutput(enable, current_value)
response_dict = raw_response[0] if isinstance(raw_response, list) and raw_response else raw_response
if isinstance(response_dict, dict) and response_dict.get("status") == "success":
details = self.formatResponseDetails(response_dict)
if enable:
QMessageBox.information(self, "成功", f"已启用固定电流输出模式!\n电流值: {current_value} mA\n\n{details}")
else:
QMessageBox.information(self, "成功", f"已退出固定电流输出模式!\n\n{details}")
elif isinstance(response_dict, dict):
error_msg = response_dict.get("error", "未知错误")
QMessageBox.critical(self, "错误", f"设置固定电流输出失败: {error_msg}")
else:
QMessageBox.critical(self, "错误", "设置固定电流输出失败: 无效的响应格式")
except Exception as e:
QMessageBox.critical(self, "异常", f"设置固定电流输出时发生异常: {str(e)}")
def formatResponseDetails(self, response):
"""格式化响应详细信息"""
details = ""
# 添加消息对象的详细信息
msg = response.get("msg", {})
if msg:
details += "消息详情:\n"
for key, value in msg.items():
# 处理二进制数据,转换为可读形式
if isinstance(value, bytes):
try:
# 尝试解码为ASCII字符串移除不可打印字符
printable_chars = "".join(chr(c) for c in value if 32 <= c <= 126)
if printable_chars:
value_str = f"{printable_chars} (HEX: {value.hex()})"
else:
value_str = f"HEX: {value.hex()}"
except:
value_str = f"HEX: {value.hex()}"
else:
value_str = str(value)
details += f" {key}: {value_str}\n"
# 添加原始数据的详细信息
raw_data = response.get("raw_data")
if raw_data:
details += "\n原始数据:\n"
details += f" HEX: {raw_data.hex()}"
return details