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