From b5f451cf9c242081e7f48a44e24fb50831b4a595 Mon Sep 17 00:00:00 2001 From: "DESKTOP-3D7M4SA\\Hicent" <452669850@qq.com> Date: Tue, 16 Dec 2025 22:53:49 +0800 Subject: [PATCH] =?UTF-8?q?1217=E9=AA=8C=E6=94=B6=E6=BC=94=E7=A4=BA?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UI/ProcedureManager/StepExecutor.py | 5 +- UI/ProfibusWidgets/ProfibusWindow.py | 38 +- UI/ProfibusWidgets/RightAreaWidget.py | 68 +--- UI/VarManages/VarTable.py | 2 +- model/ProjectModel/DeviceManage.py | 2 +- model/ProjectModel/VarManage.py | 5 +- protocol/ModBus/ModbusManager.py | 45 ++- protocol/ModBus/rtumaster_example.py | 34 +- protocol/ModBus/rtuslave_example.py | 46 ++- protocol/ModBus/tcpmaster_example.py | 42 ++- protocol/ModBus/tcpslave_example.py | 20 +- protocol/ProtocolManage.py | 483 ++++++-------------------- 12 files changed, 248 insertions(+), 542 deletions(-) diff --git a/UI/ProcedureManager/StepExecutor.py b/UI/ProcedureManager/StepExecutor.py index 2ae5958..b1ef0b4 100644 --- a/UI/ProcedureManager/StepExecutor.py +++ b/UI/ProcedureManager/StepExecutor.py @@ -911,7 +911,10 @@ class StepExecutor(QWidget): varName = varName.strip() try: # 转换为浮点数,支持各种数值格式 - numericValue = float(varValue) + if '.' in str(varValue): + numericValue = float(varValue) + else: + numericValue: float = int(varValue) # print(f" 变量: {varName} = {numericValue}") # 处理超时设置 diff --git a/UI/ProfibusWidgets/ProfibusWindow.py b/UI/ProfibusWidgets/ProfibusWindow.py index 2b79b56..59aa4de 100644 --- a/UI/ProfibusWidgets/ProfibusWindow.py +++ b/UI/ProfibusWidgets/ProfibusWindow.py @@ -74,19 +74,8 @@ class ProfibusWidgets(QWidget): super().__init__() InitParameterDB() self.setObjectName("MainWindow") - self.protocolManage = Globals.getValue('protocolManage') - self.usingSharedProfibus = False - self.devicesManange = None - if self.protocolManage and self.protocolManage.hasProfibusSupport(): - sharedManager = self.protocolManage.getSharedProfibusManager() - if sharedManager: - self.devicesManange = sharedManager - self.usingSharedProfibus = True - if self.devicesManange is None: - print('没有找到共享的Profibus') - self.devicesManange = DevicesManange() + self.devicesManange = DevicesManange() # self.batteryManange = BatteryManange() - self.dpv1Master = DPV1Master('192.168.4.38', 502) self.blockParameterManageWidget = BlockParameterManageWidget() self.process = None @@ -239,10 +228,9 @@ class ProfibusWidgets(QWidget): self.refreshProgressBar() - self._connectProfibusBackend() + self.devicesManange.connect() self.setWindowFlags(Qt.FramelessWindowHint) - # self.resize(800, 600) # self.showMaximized() @@ -253,20 +241,16 @@ class ProfibusWidgets(QWidget): self.startProtocolBtn.setText('停止通讯') self.startProtocolBtn.setIcon(QIcon('./Static/pause.png')) self.startProtocolBtn.setIconSize(QSize(22, 22)) - self._connectProfibusBackend() self.protocolTimer.start(500) else: - self.startProtocolBtn.setText('开始通讯') self.startProtocolBtn.setIcon(QIcon('./Static/start.png')) self.protocolTimer.stop() def readValues(self): - if not self._updateProfibusAreasForUI(): - return + self.devicesManange.readAreas() dockWidgets = self.findChildren(QDockWidget) #找到四个dockWidget窗口 - for dockWidget in dockWidgets: if dockWidget.widget().currentWidget().objectName() == 'initWidget': # print(dockWidget.widget().currentWidget().objectName()) @@ -296,24 +280,8 @@ class ProfibusWidgets(QWidget): # except Exception as e: # print(e) - def _connectProfibusBackend(self): - if self.usingSharedProfibus and self.protocolManage: - sharedManager = self.protocolManage.getSharedProfibusManager() - if sharedManager: - self.devicesManange = sharedManager - self.protocolManage.connectProfibus() - else: - self.devicesManange.connect() - - def _updateProfibusAreasForUI(self): - if self.usingSharedProfibus and self.protocolManage: - self.protocolManage.updateProfibusAreas(force=True) - return True - self.devicesManange.readAreas() - return True def refreshProgressBar(self): - # self.temp = temp / 10 if temp > -3276.8 else float('nan') # 假设温度值需要除以10得到实际℃数 # self.current = current # mA # self.volt = volt # mV diff --git a/UI/ProfibusWidgets/RightAreaWidget.py b/UI/ProfibusWidgets/RightAreaWidget.py index b22fe04..f309105 100644 --- a/UI/ProfibusWidgets/RightAreaWidget.py +++ b/UI/ProfibusWidgets/RightAreaWidget.py @@ -4,7 +4,6 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton, QGridLay 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, \ @@ -32,7 +31,6 @@ class RightAreaWidgets(QWidget): self.qualityLabel = {} self.areaWidget = areaWidget self.devicesManange = self.areaWidget.devicesManange - self.protocolManage = Globals.getValue('protocolManage') self.order = order self.byteLineEdit = byteLineEdit self.dataType = dataType @@ -207,45 +205,6 @@ class RightAreaWidgets(QWidget): 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) @@ -266,7 +225,7 @@ class RightAreaWidgets(QWidget): self.areaLabel[index].setText(str(value)) for index, value in enumerate(qualityValueList): self.qualityLabel[index].setText(str(value)) - # print(self.areaLabel[index],values) + # print(self.areaLabel[index],values) @@ -289,20 +248,7 @@ class RightAreaWidgets(QWidget): 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) + self.devicesManange.writeAreas(deviceName = self.deviceName, areaIndex = curIndex, values = valueList, qualityValueList = qualityValueList) def DIDOForceValues(self): @@ -315,15 +261,7 @@ class RightAreaWidgets(QWidget): 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) + self.devicesManange.writeAreas(deviceName = self.deviceName, areaIndex = curIndex, values = valueList) if sender.isChecked(): sender.setText('ON') else: diff --git a/UI/VarManages/VarTable.py b/UI/VarManages/VarTable.py index 9efd083..5b2ccb0 100644 --- a/UI/VarManages/VarTable.py +++ b/UI/VarManages/VarTable.py @@ -139,7 +139,7 @@ class VarTableView(QTableView): self.verticalHeader().hide() def setupColumnWidths(self): - self.setCustomColumnWidths([0.9, 0.9, 0.9, 1, 1, 1.4, 1, 1, 1, 1, 0.9, 1.3]) + self.setCustomColumnWidths([0.9, 0.9, 0.9, 1.4, 1, 1.3, 0.9, 0.9, 0.9, 0.9, 0.9, 1.4]) def setCustomColumnWidths(self, ratios): # 计算总比例 diff --git a/model/ProjectModel/DeviceManage.py b/model/ProjectModel/DeviceManage.py index e8aed2a..65b3ed3 100644 --- a/model/ProjectModel/DeviceManage.py +++ b/model/ProjectModel/DeviceManage.py @@ -309,7 +309,7 @@ class DevicesManange(): # print(bytes) # print(bytes) values = struct.unpack('!' + 'H' * int(len(bytes) / 2), bytes) - modbusM.writeMultipleRegisters(slaveId = 1, startAddress = 0, outputValues = values) + modbusM.writeMultipleRegisters(slaveId = 1, startAddress = 0, outputValues = values, order = 'int') # print(struct.unpack('>f', struct.pack('!HH', *values[:2]))) def readAreas(self): diff --git a/model/ProjectModel/VarManage.py b/model/ProjectModel/VarManage.py index e1f108b..42ef747 100644 --- a/model/ProjectModel/VarManage.py +++ b/model/ProjectModel/VarManage.py @@ -888,7 +888,10 @@ class GlobalVarManager(object): modelLists = ['ModbusTcpMasterTable', 'ModbusTcpSlaveTable', 'ModbusRtuMasterTable', 'ModbusRtuSlaveTable', 'HartTable', 'TcRtdTable', 'AnalogTable', 'HartSimulateTable', 'userTable'] for l in modelLists: - Globals.getValue(l).model.initTable() + tableObj = Globals.getValue(l) + # 检查对象是否存在且具有model属性 + if tableObj and hasattr(tableObj, 'model'): + tableObj.model.initTable() if errorConList: return '\r\n'.join(errorConList) diff --git a/protocol/ModBus/ModbusManager.py b/protocol/ModBus/ModbusManager.py index 9df76a8..5cf552a 100644 --- a/protocol/ModBus/ModbusManager.py +++ b/protocol/ModBus/ModbusManager.py @@ -348,6 +348,40 @@ class ModbusManager: print(f"读取RTU从站变量失败: {str(e)}") return None + def readModbusTcpMasterValue(self, info): + """读取TCP主站变量值""" + try: + if self.modbusTcpMaster is None: + return None + + slaveId = int(info['slaveID']) + address = int(info['address']) + varType = int(info['varType']) + order = info['order'] + + return self._readModbusValue(self.modbusTcpMaster, slaveId, address, varType, order) + + except Exception as e: + print(f"读取TCP主站变量失败: {str(e)}") + return None + + def readModbusRtuMasterValue(self, info): + """读取RTU主站变量值""" + try: + if self.modbusRtuMaster is None: + return None + + slaveId = int(info['slaveID']) + address = int(info['address']) + varType = int(info['varType']) + order = info['order'] + + return self._readModbusValue(self.modbusRtuMaster, slaveId, address, varType, order) + + except Exception as e: + print(f"读取RTU主站变量失败: {str(e)}") + return None + # ==================== 私有方法 ==================== def _getTcpSettings(self, tcpType): @@ -479,7 +513,7 @@ class ModbusManager: if value != 'error' and self.variableValueCache is not None and self.cacheLock is not None: with self.cacheLock: self.variableValueCache[varName] = value - print(varName, value) + # print(varName, value) except Exception as e: print(f"读取TCP主站变量失败 {varName}: {str(e)}") @@ -509,15 +543,18 @@ class ModbusManager: def _readModbusValue(self, master, slaveId, address, varType, order): """通用Modbus值读取方法""" try: - # varType: 1=线圈, 2=离散输入, 3=输入寄存器, 4=保持寄存器 + # varType: 0=线圈, 1=离散输入, 3=输入寄存器, 4=保持寄存器 + # 对于寄存器类型,需要读取2个寄存器来获取完整的浮点数 + registerCount = 2 if varType in [3, 4] and order != 'int' else 1 + if varType == 0: # 线圈 return master.readCoils(slaveId, address, 1) elif varType == 1: # 离散输入 return master.readInputCoils(slaveId, address, 1) elif varType == 3: # 输入寄存器 - return master.readInputRegisters(slaveId, address, 1, order) + return master.readInputRegisters(slaveId, address, registerCount, order) elif varType == 4: # 保持寄存器 - return master.readHoldingRegisters(slaveId, address, 1, order) + return master.readHoldingRegisters(slaveId, address, registerCount, order) else: return 'error' except Exception as e: diff --git a/protocol/ModBus/rtumaster_example.py b/protocol/ModBus/rtumaster_example.py index 21eac4b..d3d6775 100644 --- a/protocol/ModBus/rtumaster_example.py +++ b/protocol/ModBus/rtumaster_example.py @@ -35,13 +35,16 @@ class RTUMaster(): def writeSingleRegister(self, slaveId, address, outputValue, order='ABCD'): try: - if '.' not in str(outputValue): + if '.' not in str(outputValue) and order == 'int': # 整数值,使用单寄存器写入 outputValue = int(outputValue) self.master.execute(slaveId, cst.WRITE_SINGLE_REGISTER, starting_address=address, output_value=outputValue) else: # 浮点数值,需要使用多寄存器写入(因为浮点数占用2个寄存器) - outputValue = float(outputValue) + if '.' not in str(outputValue): + outputValue = int(outputValue) + else: + outputValue = float(outputValue) valueByte = None # 初始化变量 if order == 'ABCD': # 大端模式 @@ -54,14 +57,12 @@ class RTUMaster(): valueByte = floatToCDAB(outputValue) else: # 默认使用 ABCD 字节序 - # print(f"Unknown byte order '{order}', using default ABCD") valueByte = floatToABCD(outputValue) if valueByte is not None: # 浮点数必须使用 WRITE_MULTIPLE_REGISTERS,因为需要写入2个寄存器 self.master.execute(slaveId, cst.WRITE_MULTIPLE_REGISTERS, starting_address=address, output_value=valueByte) else: - # print(f"Failed to convert float value {outputValue} with order {order}") return 'error' except Exception as e: print(f'writeSingleRegister error: {e}') @@ -80,15 +81,19 @@ class RTUMaster(): try: processedValues = [] for value in outputValues: - if '.' not in str(value): - # 整数值 - processedValues.append(int(value)) + if '.' not in str(value) and order == 'int': + # 整数值,使用单寄存器写入 + value = int(value) + processedValues.append(value) else: # 浮点值 - 根据字节序转换为寄存器对 - floatValue = float(value) - if order == 'ABCD': # 大端模式 + if '.' not in str(value): + floatValue = int(value) + else: + floatValue = float(value) + if order == 'ABCD': valueByte = floatToABCD(floatValue) - elif order == 'DCBA': # 小端模式 + elif order == 'DCBA': valueByte = floatToDCBA(floatValue) elif order == 'BADC': valueByte = floatToBADC(floatValue) @@ -124,8 +129,11 @@ class RTUMaster(): try: if order == 'int': valueByte = self.master.execute(slaveId, cst.READ_HOLDING_REGISTERS, startAddress, varNums)[0] + valueByte = int(valueByte) else: - value = self.master.execute(slaveId, cst.READ_HOLDING_REGISTERS, startAddress, 2) + # 对于浮点数,总是读取2个寄存器 + readCount = 2 if order != 'int' else varNums + value = self.master.execute(slaveId, cst.READ_HOLDING_REGISTERS, startAddress, readCount) if order == 'ABCD': # 大端模式 valueByte = ABCDToFloat(value) elif order == 'DCBA': # 小端模式 @@ -143,7 +151,9 @@ class RTUMaster(): if order == 'int': valueByte = self.master.execute(slaveId, cst.READ_INPUT_REGISTERS, startAddress, varNums)[0] else: - value = self.master.execute(slaveId, cst.READ_INPUT_REGISTERS, startAddress, 2) + # 对于浮点数,总是读取2个寄存器 + readCount = 2 if order != 'int' else varNums + value = self.master.execute(slaveId, cst.READ_INPUT_REGISTERS, startAddress, readCount) if order == 'ABCD': # 大端模式 valueByte = ABCDToFloat(value) elif order == 'DCBA': # 小端模式 diff --git a/protocol/ModBus/rtuslave_example.py b/protocol/ModBus/rtuslave_example.py index bbbc78b..cec1c89 100644 --- a/protocol/ModBus/rtuslave_example.py +++ b/protocol/ModBus/rtuslave_example.py @@ -48,26 +48,34 @@ class RTUSlave(): def setValue(self, slaveId, name, address, value, order = 'ABCD'): - - slave = self.server.get_slave(slaveId) - if '.' in str(value): - floatValue = float(value) - if order == 'ABCD': # 大端模式 - valueByte = floatToABCD(floatValue) - elif order == 'DCBA': # 小端模式 - valueByte = floatToDCBA(floatValue) - elif order == 'BADC': - valueByte = floatToBADC(floatValue) - elif order == 'CDAB': - valueByte = floatToCDAB(floatValue) + try: + slave = self.server.get_slave(slaveId) + + if '.' not in str(value) and order == 'int': + # 整数值处理 + intValue = int(value) + slave.set_values(name, address, intValue) else: - valueByte = floatToABCD(floatValue) - slave.set_values(name, address, valueByte) - - else: - # print(value) - - slave.set_values(name, address, int(value)) + # 浮点数处理(或者order != 'int'时的浮点数转换) + if '.' not in str(value): + floatValue = int(value) + else: + floatValue = float(value) + + if order == 'ABCD': # 大端模式 + valueByte = floatToABCD(floatValue) + elif order == 'DCBA': # 小端模式 + valueByte = floatToDCBA(floatValue) + elif order == 'BADC': + valueByte = floatToBADC(floatValue) + elif order == 'CDAB': + valueByte = floatToCDAB(floatValue) + else: + valueByte = floatToABCD(floatValue) + slave.set_values(name, address, valueByte) + except Exception as e: + print(f"RTU Slave setValue error: {e}") + return 'error' def readValue(self, slaveId, name, address, order = 'int'): diff --git a/protocol/ModBus/tcpmaster_example.py b/protocol/ModBus/tcpmaster_example.py index 45548cb..15dff82 100644 --- a/protocol/ModBus/tcpmaster_example.py +++ b/protocol/ModBus/tcpmaster_example.py @@ -18,13 +18,16 @@ class TcpMaster(): def writeSingleRegister(self, slaveId, address, outputValue, order='ABCD'): try: - if '.' not in str(outputValue): + if '.' not in str(outputValue) and order == 'int': # 整数值,使用单寄存器写入 outputValue = int(outputValue) self.master.execute(slaveId, cst.WRITE_SINGLE_REGISTER, starting_address=address, output_value=outputValue) else: # 浮点数值,需要使用多寄存器写入(因为浮点数占用2个寄存器) - outputValue = float(outputValue) + if '.' not in str(outputValue): + outputValue = int(outputValue) + else: + outputValue = float(outputValue) if order == 'ABCD': # 大端模式 valueByte = floatToABCD(outputValue) elif order == 'DCBA': # 小端模式 @@ -47,19 +50,26 @@ class TcpMaster(): """写多个寄存器,支持不同数据类型和字节序""" try: processedValues = [] + # print(outputValues) for value in outputValues: - if '.' not in str(value): - processedValues.append(int(value)) + if '.' not in str(value) and order == 'int': + # 整数值,使用单寄存器写入 + value = int(value) + # self.master.execute(slaveId, cst.WRITE_SINGLE_REGISTER, starting_address=startAddress, output_value=value) + processedValues.append(value) else: - floatValue = float(value) - if order == 'ABCD': - valueByte = floatToABCD(floatValue) - elif order == 'DCBA': - valueByte = floatToDCBA(floatValue) - elif order == 'BADC': - valueByte = floatToBADC(floatValue) - elif order == 'CDAB': - valueByte = floatToCDAB(floatValue) + if '.' not in str(value): + floatValue = int(value) + else: + floatValue = float(value) + if order == 'ABCD': + valueByte = floatToABCD(floatValue) + elif order == 'DCBA': + valueByte = floatToDCBA(floatValue) + elif order == 'BADC': + valueByte = floatToBADC(floatValue) + elif order == 'CDAB': + valueByte = floatToCDAB(floatValue) processedValues.extend(valueByte) self.master.execute(slaveId, cst.WRITE_MULTIPLE_REGISTERS, starting_address=startAddress, output_value=processedValues) @@ -96,6 +106,7 @@ class TcpMaster(): try: if order == 'int': valueByte = self.master.execute(slaveId, cst.READ_HOLDING_REGISTERS, startAddress, varNums)[0] + valueByte = int(valueByte) else: value = self.master.execute(slaveId, cst.READ_HOLDING_REGISTERS, startAddress, varNums) if order == 'ABCD': @@ -116,8 +127,11 @@ class TcpMaster(): try: if order == 'int': valueByte = self.master.execute(slaveId, cst.READ_INPUT_REGISTERS, startAddress, varNums)[0] + valueByte = int(valueByte) else: - value = self.master.execute(slaveId, cst.READ_INPUT_REGISTERS, startAddress, 2) + # 对于浮点数,总是读取2个寄存器 + readCount = 2 if order != 'int' else varNums + value = self.master.execute(slaveId, cst.READ_INPUT_REGISTERS, startAddress, readCount) if order == 'ABCD': valueByte = ABCDToFloat(value) elif order == 'DCBA': diff --git a/protocol/ModBus/tcpslave_example.py b/protocol/ModBus/tcpslave_example.py index 6e101be..7407ac4 100644 --- a/protocol/ModBus/tcpslave_example.py +++ b/protocol/ModBus/tcpslave_example.py @@ -53,10 +53,18 @@ class TCPSlave(): def setValue(self, slaveId, name, address, value, order='ABCD'): try: slave = self.server.get_slave(slaveId) - # print(value) - if '.' in str(value): - # 浮点数处理 - floatValue = float(value) + + if '.' not in str(value) and order == 'int': + # 整数值处理 + intValue = int(value) + slave.set_values(name, address, intValue) + else: + # 浮点数处理(或者order != 'int'时的浮点数转换) + if '.' not in str(value): + floatValue = int(value) + else: + floatValue = float(value) + if order == 'ABCD': # 大端模式 valueByte = floatToABCD(floatValue) elif order == 'DCBA': # 小端模式 @@ -68,10 +76,6 @@ class TCPSlave(): else: valueByte = floatToABCD(floatValue) slave.set_values(name, address, valueByte) - else: - # 整数处理 - intValue = int(value) - slave.set_values(name, address, intValue) return True except Exception as e: diff --git a/protocol/ProtocolManage.py b/protocol/ProtocolManage.py index 0d73fc6..afdfd2a 100644 --- a/protocol/ProtocolManage.py +++ b/protocol/ProtocolManage.py @@ -11,6 +11,7 @@ from protocol.TCP.TemToMv import temToMv from protocol.RPC.RpcClient import RpcClient from protocol.RPC.RpcServer import RpcServer from protocol.ModBus.ModbusManager import ModbusManager +# from protocol.ProfibusManager import ProfibusManager from utils import Globals import threading import time @@ -42,21 +43,16 @@ class ProtocolManage(object): self.varInfoCache = {} # 保持驼峰命名 self.historyDBManage = Globals.getValue('historyDBManage') self.variableValueCache = {} # {varName: value} - self.profibusManager = None - self.profibusDeviceMeta = {} - self.profibusEnabled = GlobalConfigManager.isModuleEnabled('profibusModule') - self._profibusConnected = False - self._profibusLastUpdate = 0 - self.profibusLock = threading.Lock() - - if self.profibusEnabled: - # print('yeyeye') - self._initializeProfibusSupport() + self.cacheLock = threading.Lock() # Modbus 管理器 self.modbusManager = ModbusManager() - - # self.modbusManager.setVariableCache(self.variableValueCache, None, self.varInfoCache) + # 设置 Modbus 管理器的缓存锁 + self.modbusManager.setVariableCache(self.variableValueCache, self.cacheLock, self.varInfoCache) + + # PROFIBUS管理器 (已删除,准备重新构建) + # self.profibusManager = DevicesManange() + # self.profibusEnabled = False # HART模拟RTU从站管理器 self.hartRtuSlaveManager = None @@ -69,9 +65,6 @@ class ProtocolManage(object): self.hartRtuSlaveManager = None self.refreshVarCache() - self.cacheLock = threading.Lock() - # 设置 Modbus 管理器的缓存锁 - self.modbusManager.setVariableCache(self.variableValueCache, self.cacheLock, self.varInfoCache) self.readThreadStop = threading.Event() self.readThread = threading.Thread(target=self._backgroundReadAllVariables, daemon=True) @@ -99,10 +92,11 @@ class ProtocolManage(object): 'modelType': modelClass.__name__, 'variableData': varData } + except Exception as e: print(f"刷新缓存时出错: {modelClass.__name__}: {e}") - if self.profibusEnabled and self.profibusManager: - self._registerProfibusVariables() + # self.getAllProfibusDevices() + # PROFIBUS变量注册 (已删除,准备重新构建) @@ -127,10 +121,7 @@ class ProtocolManage(object): } self.varInfoCache[variableName] = result # 写入缓存 return result - if self.profibusEnabled and self.profibusManager: - profibusResult = self._lookupProfibusVariable(variableName) - if profibusResult: - return profibusResult + # PROFIBUS变量查找 (已删除,准备重新构建) return None @@ -254,12 +245,10 @@ class ProtocolManage(object): trigger = FPGATrigger if trigger else trigger self.tcpVarManager.writeValue(varType, channel, value, trigger=trigger, model=model, timeoutMS=timeoutMS) - # PROFIBUS变量处理 + # PROFIBUS变量处理 (已删除,准备重新构建) elif modelType == 'ProfibusVar': - success, normalizedValue = self._writeProfibusVariable(info, value) - if not success: - return False - value = normalizedValue + # PROFIBUS变量写入功能 (已删除,准备重新构建) + return False # HART模拟变量处理 @@ -307,8 +296,7 @@ class ProtocolManage(object): while not self.readThreadStop.is_set(): try: allVarNames = list(self.getAllVariableNames()) - if self.profibusEnabled and self.profibusManager: - self._updateProfibusAreas(force=True) + # PROFIBUS区域更新 (已删除,准备重新构建) for varName in allVarNames: if self.readThreadStop.is_set(): @@ -328,351 +316,7 @@ class ProtocolManage(object): print(f"后台读取线程异常: {e}") time.sleep(5) # 异常时等待更长时间 - # ==================== PROFIBUS 变量管理 ==================== - def _initializeProfibusSupport(self): - try: - self.profibusManager = DevicesManange() - self._loadProfibusConfiguration() - self.profibusManager.recalculateAddress() - self._registerProfibusVariables() - except Exception as e: - print(f"初始化PROFIBUS管理器失败: {e}") - self.profibusManager = None - self.profibusEnabled = False - - def _loadProfibusConfiguration(self): - self.profibusDeviceMeta = {} - allDevices = DevicesManange.getAllDevice() - if not allDevices or isinstance(allDevices, str): - return - for deviceRow in allDevices: - if not deviceRow: - continue - try: - deviceName = deviceRow[0] - except (IndexError, TypeError): - continue - proType = deviceRow[1] if len(deviceRow) > 1 else None - masterSlaveModel = deviceRow[2] if len(deviceRow) > 2 else None - areaJson = deviceRow[3] if len(deviceRow) > 3 else None - pvUpper = deviceRow[4] if len(deviceRow) > 4 else None - pvLower = deviceRow[5] if len(deviceRow) > 5 else None - pvUnit = deviceRow[6] if len(deviceRow) > 6 else None - self.profibusDeviceMeta[deviceName] = { - 'pvUpperLimit': pvUpper, - 'pvLowerLimit': pvLower, - 'pvUnit': pvUnit - } - try: - self.profibusManager.addDevice( - proType=proType, - masterSlaveModel=masterSlaveModel, - deviceName=deviceName - ) - except Exception as e: - print(f"初始化设备 {deviceName} 失败: {e}") - continue - self._addProfibusAreas(deviceName, areaJson) - - def _addProfibusAreas(self, deviceName, areaJson): - if not areaJson: - return - try: - areas = json.loads(areaJson) if isinstance(areaJson, str) else areaJson - except Exception as e: - print(f"解析设备 {deviceName} 的区域配置失败: {e}") - return - device = self.profibusManager.getDevice(deviceName) - if not device or not areas: - return - for areaConfig in areas: - if not isinstance(areaConfig, dict): - continue - dataType = areaConfig.get('type') - valueName = areaConfig.get('valueName') - if not dataType or not valueName: - continue - order = areaConfig.get('order', 'ABCD') - bytesCount = areaConfig.get('bytes', 0) - try: - bytesCount = int(bytesCount) - except (TypeError, ValueError): - bytesCount = 0 - try: - device.addArea( - type=dataType, - nums=1, - bytes=bytesCount, - order=order, - valueName=valueName - ) - except Exception as e: - print(f"添加设备 {deviceName} 的区域 {valueName} 失败: {e}") - continue - - def _registerProfibusVariables(self): - if not self.profibusEnabled or not self.profibusManager: - return - for areaInfo in self._iterProfibusAreas(): - varName = areaInfo.get('valueName') - if not varName: - continue - self.varInfoCache[varName] = { - 'modelType': 'ProfibusVar', - 'variableData': dict(areaInfo) - } - - def _iterProfibusAreas(self): - if not self.profibusManager: - return - deviceGroups = [ - self.profibusManager.dpMasterDevices, - self.profibusManager.dpSlaveDevices, - self.profibusManager.paMasterDevices, - self.profibusManager.paSlaveDevices - ] - for devicesDict in deviceGroups: - for deviceName, device in devicesDict.items(): - deviceMeta = self.profibusDeviceMeta.get(deviceName, {}) - for areaIndex, area in enumerate(device.areas): - yield { - 'deviceName': deviceName, - 'areaIndex': areaIndex, - 'areaType': area.type, - 'bytes': getattr(area, 'bytes', 0), - 'order': getattr(area, 'order', 'ABCD'), - 'valueName': getattr(area, 'valueName', None), - 'proType': device.type, - 'masterSlaveModel': device.masterOrSlave, - 'min': deviceMeta.get('pvLowerLimit'), - 'max': deviceMeta.get('pvUpperLimit'), - 'unit': deviceMeta.get('pvUnit'), - 'varType': area.type - } - - def _lookupProfibusVariable(self, variableName): - if not self.profibusEnabled or not self.profibusManager: - return None - for areaInfo in self._iterProfibusAreas() or []: - if areaInfo.get('valueName') == variableName: - result = { - 'modelType': 'ProfibusVar', - 'variableData': dict(areaInfo) - } - self.varInfoCache[variableName] = result - return result - return None - - def _ensureProfibusConnected(self): - - if not self.profibusManager: - return False - if self._profibusConnected: - return True - try: - print(f"正在连接Profibus...") - self.profibusManager.connect() - self._profibusConnected = True - print(f"Profibus连接成功") - except Exception as e: - print(f"连接PROFIBUS失败: {e}") - self._profibusConnected = False - return False - return True - - def _updateProfibusAreas(self, force=False): - if not self.profibusManager: - return - now = time.time() - if not force and (now - self._profibusLastUpdate) < 0.5: - return - if not self._ensureProfibusConnected(): - print(f"Profibus连接失败,跳过区域更新") - return - with self.profibusLock: - try: - print(f"正在读取Profibus区域数据...") - self.profibusManager.readAreas() - self._profibusLastUpdate = now - print(f"Profibus区域数据读取完成") - except Exception as e: - print(f"读取PROFIBUS区域失败: {e}") - - def _writeProfibusVariable(self, info, rawValue): - if not self.profibusManager: - print(f"Profibus管理器未初始化") - return False, None - if not self._ensureProfibusConnected(): - print(f"Profibus连接失败") - return False, None - device = self.profibusManager.getDevice(info['deviceName']) - if not device: - print(f"找不到设备: {info['deviceName']}") - return False, None - areaIndex = info['areaIndex'] - if areaIndex >= len(device.areas): - print(f"区域索引超出范围: {areaIndex} >= {len(device.areas)}") - return False, None - area = device.areas[areaIndex] - print(f"写入设备 {info['deviceName']} 区域 {areaIndex} 类型 {area.type} 值 {rawValue}") - - if area.type in ['AI', 'AO']: - analogValue, qualityList = self._formatAnalogValue(rawValue) - if analogValue is None: - print(f"模拟量值格式化失败") - return False, None - valuesToWrite = [analogValue] - normalizedValue = analogValue - else: - valuesToWrite = self._formatDiscreteValues(area, rawValue) - if valuesToWrite is None: - print(f"离散量值格式化失败") - return False, None - qualityList = None - normalizedValue = valuesToWrite[:] - - with self.profibusLock: - try: - print(f"调用writeAreas写入数据: {valuesToWrite}") - if qualityList is not None: - self.profibusManager.writeAreas( - deviceName=info['deviceName'], - areaIndex=areaIndex, - values=valuesToWrite, - qualityValueList=qualityList - ) - else: - self.profibusManager.writeAreas( - deviceName=info['deviceName'], - areaIndex=areaIndex, - values=valuesToWrite - ) - print(f"writeAreas调用成功,更新本地缓存") - if area.type in ['AI', 'AO']: - area.currentValue = [normalizedValue] - if qualityList: - area.qualityValueList = qualityList - else: - area.currentValue = normalizedValue[:] - except Exception as e: - print(f"写入PROFIBUS变量 {info['valueName']} 失败: {e}") - return False, None - with self.cacheLock: - self.variableValueCache[info['valueName']] = normalizedValue - return True, normalizedValue - - def _formatAnalogValue(self, rawValue): - qualityValue = None - targetValue = rawValue - if isinstance(rawValue, dict): - targetValue = rawValue.get('value') - qualityValue = rawValue.get('quality') or rawValue.get('qualityValue') - try: - analogValue = float(targetValue) - except (TypeError, ValueError): - return None, None - qualityList = None - if qualityValue is not None: - normalizedQuality = self._normalizeQualityValue(qualityValue) - if normalizedQuality is None: - return None, None - qualityList = [normalizedQuality] - return analogValue, qualityList - - def _normalizeQualityValue(self, qualityValue): - try: - if isinstance(qualityValue, str): - qualityValue = qualityValue.strip() - if qualityValue.lower().startswith('0x'): - qualityInt = int(qualityValue, 16) - else: - qualityInt = int(qualityValue) - else: - qualityInt = int(qualityValue) - if qualityInt < 0 or qualityInt > 255: - return None - return f"0x{qualityInt:02X}" - except (TypeError, ValueError): - return None - - def _formatDiscreteValues(self, area, rawValue): - bitLength = (area.bytes or 0) * 8 - if bitLength <= 0: - bitLength = 16 - if isinstance(getattr(area, 'currentValue', None), list) and area.currentValue: - baseValues = list(area.currentValue) - elif isinstance(getattr(area, 'forceValue', None), list) and area.forceValue: - baseValues = list(area.forceValue) - else: - baseValues = [0] * bitLength - if len(baseValues) < bitLength: - baseValues += [0] * (bitLength - len(baseValues)) - else: - baseValues = baseValues[:bitLength] - if isinstance(rawValue, dict) and 'index' in rawValue: - try: - index = int(rawValue['index']) - except (TypeError, ValueError): - return None - if index < 0 or index >= bitLength: - return None - baseValues[index] = 1 if rawValue.get('value') in [1, True, '1', 'on', 'ON'] else 0 - return baseValues - if isinstance(rawValue, (list, tuple)): - normalized = [1 if item in [1, True, '1', 'on', 'ON'] else 0 for item in rawValue] - if len(normalized) < bitLength: - normalized += [0] * (bitLength - len(normalized)) - return normalized[:bitLength] - baseValues[0] = 1 if rawValue in [1, True, '1', 'on', 'ON'] else 0 - return baseValues - - def _readProfibusVariable(self, info): - if not self.profibusManager: - print(f"Profibus管理器未初始化") - return None - self._updateProfibusAreas() - device = self.profibusManager.getDevice(info['deviceName']) - if not device: - print(f"找不到设备: {info['deviceName']}") - return None - areaIndex = info['areaIndex'] - if areaIndex >= len(device.areas): - print(f"区域索引超出范围: {areaIndex} >= {len(device.areas)}") - return None - area = device.areas[areaIndex] - print(f"读取设备 {info['deviceName']} 区域 {areaIndex} 类型 {area.type} 当前值: {getattr(area, 'currentValue', None)}") - - if area.type in ['AI', 'AO']: - if isinstance(area.currentValue, list) and area.currentValue: - try: - return float(area.currentValue[0]) - except (TypeError, ValueError): - return area.currentValue[0] - return None - if isinstance(area.currentValue, list) and area.currentValue: - bitLength = (area.bytes or 0) * 8 - if bitLength <= 0: - bitLength = len(area.currentValue) - return area.currentValue[:bitLength] - return None - - # ==================== 对外共享的 PROFIBUS 接口 ==================== - def hasProfibusSupport(self) -> bool: - return self.profibusEnabled and self.profibusManager is not None - - def getSharedProfibusManager(self): - return self.profibusManager - - def connectProfibus(self) -> bool: - if not self.hasProfibusSupport(): - return False - return self._ensureProfibusConnected() - - def updateProfibusAreas(self, force: bool = False) -> bool: - if not self.hasProfibusSupport(): - return False - self._updateProfibusAreas(force=force) - return True + # ==================== 对外共享的 PROFIBUS 接口 (已删除,准备重新构建) ==================== def getAllVariableNames(self): @@ -714,12 +358,13 @@ class ProtocolManage(object): info = varInfo['variableData'] try: # 拆分为独立的协议条件判断 - # if modelType == 'ModbusTcpMasterVar': - # value = self.modbusManager.readModbusTcpMasterValue(info) - if modelType == 'ModbusTcpSlaveVar': + if modelType == 'ModbusTcpMasterVar': + value = self.modbusManager.readModbusTcpMasterValue(info) + # print(value) + elif modelType == 'ModbusTcpSlaveVar': value = self.modbusManager.readModbusTcpSlaveValue(info) - # elif modelType == 'ModbusRtuMasterVar': - # value = self.modbusManager.readModbusRtuMasterValue(info) + elif modelType == 'ModbusRtuMasterVar': + value = self.modbusManager.readModbusRtuMasterValue(info) elif modelType == 'ModbusRtuSlaveVar': value = self.modbusManager.readModbusRtuSlaveValue(info) elif modelType == 'HartVar': @@ -754,7 +399,13 @@ class ProtocolManage(object): if varType in ['AI', 'AO']: value = self.getRealAI(value, info['max'], info['min']) elif modelType == 'ProfibusVar': - value = self._readProfibusVariable(info) + # PROFIBUS变量读取功能 (已删除,准备重新构建) + # value = None + # print(info) + # device = self.profibusManager.getDevice(info['deviceName']) + # values, qualityValueList = device.getAreaValues(info['id']) + # print(values, qualityValueList, info['valueName']) + pass elif modelType == 'HartSimulateVar': if not self.hartRtuSlaveManager: @@ -803,8 +454,10 @@ class ProtocolManage(object): def readVariableValue(self, variableName): with self.cacheLock: - + # print(self.variableValueCache) + # print(variableName,111) if variableName in self.variableValueCache: + # print(variableName) return self.variableValueCache[variableName] return self._readVariableValueOriginal(variableName) @@ -827,6 +480,8 @@ class ProtocolManage(object): if hasattr(self, 'readThreadStop') and hasattr(self, 'readThread'): self.readThreadStop.set() self.readThread.join(timeout=1) + + # 关闭PROFIBUS管理器 (已删除,准备重新构建) def getRealAO(self, value, highValue, lowValue): if highValue: @@ -947,4 +602,70 @@ class ProtocolManage(object): """读取HART变量值""" if not self.hartRtuSlaveManager: return None - return self.hartRtuSlaveManager.readVariable(variableName) \ No newline at end of file + return self.hartRtuSlaveManager.readVariable(variableName) + + # ==================== PROFIBUS设备管理方法 ==================== + + def getAllProfibusDevices(self): + """获取所有PROFIBUS设备和区域信息,只返回变量名不为空的AREA""" + try: + # 使用DeviceManage的getAllDevice方法获取所有设备信息 + devices = DevicesManange.getAllDevice() + if not devices: + return [] + + profibusDevices = [] + for device in devices: + deviceName, proType, masterSlaveModel, areaJson, pvLowerLimit, pvUpperLimit, pvUnit = device + + # 只处理PROFIBUS相关的设备(DP或PA类型) + if proType in ['DP', 'PA']: + deviceInfo = { + 'deviceName': deviceName, + 'proType': proType, + 'masterSlaveModel': masterSlaveModel, + 'pvLowerLimit': pvLowerLimit, + 'pvUpperLimit': pvUpperLimit, + 'pvUnit': pvUnit, + 'areas': [] + } + + # 解析区域信息,只添加变量名不为空的AREA + if areaJson and areaJson != '[]': + try: + areas = json.loads(areaJson) + for area in areas: + valueName = area.get('valueName', '') + # 只有当变量名不为空时才添加该AREA + if valueName and valueName.strip() != '': + areaInfo = { + 'deviceName': deviceName, + 'id': area.get('id', 0), + 'type': area.get('type', ''), + 'order': area.get('order', 'ABCD'), + 'bytes': area.get('bytes', 4), + 'valueName': valueName, + 'nums': area.get('nums', 1), + 'proType': proType, + 'masterSlaveModel': masterSlaveModel, + } + # deviceInfo['areas'].append(areaInfo) + self.varInfoCache[valueName] = { + 'modelType': 'ProfibusVar', + 'variableData': areaInfo + } + # print(f"缓存变量: {valueName}", areaInfo) + except json.JSONDecodeError: + # 如果JSON解析失败,跳过该设备 + continue + + # 只有当设备有变量名不为空的AREA时才添加到结果中 + # if deviceInfo['areas']: + # profibusDevices.append(deviceInfo) + + # return profibusDevices + + except Exception as e: + print(f"获取PROFIBUS设备信息失败: {str(e)}") + return [] +