|
|
|
|
from utils.DBModels.ProtocolModel import (
|
|
|
|
|
ModbusTcpMasterVar, ModbusTcpSlaveVar, ModbusRtuMasterVar, ModbusRtuSlaveVar,
|
|
|
|
|
HartVar, TcRtdVar, AnalogVar, HartSimulateVar
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
from protocol.TCP.TCPVarManage import *
|
|
|
|
|
from protocol.TCP.TemToMv import temToMv
|
|
|
|
|
from protocol.RPC.RpcClient import RpcClient
|
|
|
|
|
from protocol.RPC.RpcServer import RpcServer
|
|
|
|
|
from utils import Globals
|
|
|
|
|
import threading
|
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
class ProtocolManage(object):
|
|
|
|
|
"""通讯变量查找类,用于根据变量名在数据库模型中检索变量信息"""
|
|
|
|
|
|
|
|
|
|
# 支持的模型类列表
|
|
|
|
|
MODEL_CLASSES = [
|
|
|
|
|
ModbusTcpMasterVar, ModbusTcpSlaveVar,
|
|
|
|
|
ModbusRtuMasterVar, ModbusRtuSlaveVar,
|
|
|
|
|
HartVar, TcRtdVar, AnalogVar, HartSimulateVar
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
# self.tcpVarManager = TCPVarManager('192.168.1.50', 5055)
|
|
|
|
|
self.tcpVarManager = TCPVarManager('127.0.0.1', 8000)
|
|
|
|
|
self.writeTC = [0] * 8
|
|
|
|
|
self.writeRTD = [0] * 8
|
|
|
|
|
self.RpcClient = None
|
|
|
|
|
self.RpcServer = None
|
|
|
|
|
self.varInfoCache = {} # 保持驼峰命名
|
|
|
|
|
self.historyDBManage = Globals.getValue('historyDBManage')
|
|
|
|
|
self.variableValueCache = {} # {varName: value}
|
|
|
|
|
self.refreshVarCache()
|
|
|
|
|
self.cacheLock = threading.Lock()
|
|
|
|
|
self.readThreadStop = threading.Event()
|
|
|
|
|
self.readThread = threading.Thread(target=self._backgroundReadAllVariables, daemon=True)
|
|
|
|
|
self.readThread.start()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def clearVarCache(self):
|
|
|
|
|
"""清空变量信息缓存"""
|
|
|
|
|
self.varInfoCache.clear()
|
|
|
|
|
|
|
|
|
|
def refreshVarCache(self):
|
|
|
|
|
"""重新加载所有变量信息到缓存(可选实现)"""
|
|
|
|
|
self.varInfoCache.clear()
|
|
|
|
|
for modelClass in self.MODEL_CLASSES:
|
|
|
|
|
try:
|
|
|
|
|
for varInstance in modelClass.select():
|
|
|
|
|
varName = getattr(varInstance, 'varName', None)
|
|
|
|
|
if varName:
|
|
|
|
|
varData = {}
|
|
|
|
|
for field in varInstance._meta.sorted_fields:
|
|
|
|
|
fieldName = field.name
|
|
|
|
|
varData[fieldName] = getattr(varInstance, fieldName)
|
|
|
|
|
self.varInfoCache[varName] = {
|
|
|
|
|
'modelType': modelClass.__name__,
|
|
|
|
|
'variableData': varData
|
|
|
|
|
}
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"刷新缓存时出错: {modelClass.__name__}: {e}")
|
|
|
|
|
|
|
|
|
|
def lookupVariable(self, variableName):
|
|
|
|
|
"""
|
|
|
|
|
根据变量名检索变量信息(优先查缓存)
|
|
|
|
|
:param variableName: 要查询的变量名
|
|
|
|
|
:return: 包含变量信息和模型类型的字典,如果未找到返回None
|
|
|
|
|
"""
|
|
|
|
|
if variableName in self.varInfoCache:
|
|
|
|
|
# print(111)
|
|
|
|
|
return self.varInfoCache[variableName]
|
|
|
|
|
for modelClass in self.MODEL_CLASSES:
|
|
|
|
|
varInstance = modelClass.getByName(variableName)
|
|
|
|
|
if varInstance:
|
|
|
|
|
varData = {}
|
|
|
|
|
for field in varInstance._meta.sorted_fields:
|
|
|
|
|
fieldName = field.name
|
|
|
|
|
varData[fieldName] = getattr(varInstance, fieldName)
|
|
|
|
|
result = {
|
|
|
|
|
'modelType': modelClass.__name__,
|
|
|
|
|
'variableData': varData
|
|
|
|
|
}
|
|
|
|
|
self.varInfoCache[variableName] = result # 写入缓存
|
|
|
|
|
return result
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def setClentMode(self, clentName, rabbitmqHost='localhost'):
|
|
|
|
|
if self.RpcClient:
|
|
|
|
|
self.RpcClient.close()
|
|
|
|
|
self.RpcClient = RpcClient(clentName, rabbitmqHost, self)
|
|
|
|
|
# 使用非阻塞方式启动RPC客户端
|
|
|
|
|
self.RpcClient.startNonBlocking()
|
|
|
|
|
|
|
|
|
|
def closeClent(self):
|
|
|
|
|
if self.RpcClient:
|
|
|
|
|
self.RpcClient.close()
|
|
|
|
|
self.RpcClient = None
|
|
|
|
|
|
|
|
|
|
def setServerMode(self, rabbitmqHost='localhost'):
|
|
|
|
|
if self.RpcServer:
|
|
|
|
|
return
|
|
|
|
|
self.RpcServer = RpcServer(rabbitmqHost)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def addClient(self, clientName):
|
|
|
|
|
if self.RpcServer:
|
|
|
|
|
self.RpcServer.addClient(clientName = clientName)
|
|
|
|
|
else:
|
|
|
|
|
return
|
|
|
|
|
# print(11111111111)
|
|
|
|
|
# time.sleep(3)
|
|
|
|
|
# print(self.RpcServer.broadcastRead())
|
|
|
|
|
# self.RpcServer.broadcastRead()
|
|
|
|
|
|
|
|
|
|
def closeServer(self):
|
|
|
|
|
if self.RpcServer:
|
|
|
|
|
self.RpcServer.close()
|
|
|
|
|
self.RpcServer = None
|
|
|
|
|
|
|
|
|
|
# @classmethod
|
|
|
|
|
def writeVariableValue(self, variableName, value, trigger = None, timeoutMS = 2000):
|
|
|
|
|
"""
|
|
|
|
|
根据变量名写入变量值,根据变量类型进行不同处理(不保存到数据库)
|
|
|
|
|
|
|
|
|
|
:param variableName: 变量名
|
|
|
|
|
:param value: 要写入的值
|
|
|
|
|
:return: 写入成功返回True,否则返回False
|
|
|
|
|
"""
|
|
|
|
|
varInfo = self.lookupVariable(variableName)
|
|
|
|
|
if not varInfo:
|
|
|
|
|
if self.RpcServer:
|
|
|
|
|
existsVar, clientNames = self.RpcServer.existsVar(variableName)
|
|
|
|
|
if existsVar:
|
|
|
|
|
value = self.RpcServer.writeVar(variableName, value)
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
modelType = varInfo['modelType']
|
|
|
|
|
info = varInfo['variableData']
|
|
|
|
|
|
|
|
|
|
# print(info)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# 拆分为四个独立的Modbus协议条件判断
|
|
|
|
|
if modelType == 'ModbusTcpMasterVar':
|
|
|
|
|
# 仅设置值,不保存到数据库
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
elif modelType == 'ModbusTcpSlaveVar':
|
|
|
|
|
# 仅设置值,不保存到数据库
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
elif modelType == 'ModbusRtuMasterVar':
|
|
|
|
|
# 仅设置值,不保存到数据库
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
elif modelType == 'ModbusRtuSlaveVar':
|
|
|
|
|
# 仅设置值,不保存到数据库
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
# HART协议变量处理
|
|
|
|
|
elif modelType == 'HartVar':
|
|
|
|
|
# 仅设置值,不保存到数据库
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
# 温度/RTD变量处理
|
|
|
|
|
elif modelType == 'TcRtdVar':
|
|
|
|
|
channel = int(info['channelNumber']) - 1
|
|
|
|
|
varType = info['varType']
|
|
|
|
|
compensationVar = float(info['compensationVar'])
|
|
|
|
|
varModel = info['varModel']
|
|
|
|
|
model = self.getModelType(varModel) if self.getModelType(varModel) else localModel
|
|
|
|
|
# print(value + compensationVar)
|
|
|
|
|
if model == localModel:
|
|
|
|
|
if varType == 'PT100':
|
|
|
|
|
self.writeRTD[channel] = value
|
|
|
|
|
else:
|
|
|
|
|
self.writeTC[channel] = value
|
|
|
|
|
if varType in ['R', 'S', 'B', 'J', 'T', 'E', 'K', 'N', 'C', 'A', 'PT100'] and model != SimModel:
|
|
|
|
|
value = temToMv(varType, value + compensationVar) # 直接补偿温度 补偿mv调整到括号外
|
|
|
|
|
if trigger and varType in ['R', 'S', 'B', 'J', 'T', 'E', 'K', 'N', 'C', 'A']:
|
|
|
|
|
trigger = TCTrigger
|
|
|
|
|
if trigger and varType in ['PT100']:
|
|
|
|
|
trigger = RTDTrigger
|
|
|
|
|
self.tcpVarManager.writeValue(varType, channel, value, trigger=trigger, model=model, timeoutMS=timeoutMS)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 模拟量变量处理
|
|
|
|
|
elif modelType == 'AnalogVar':
|
|
|
|
|
channel = int(info['channelNumber']) - 1
|
|
|
|
|
varType = info['varType']
|
|
|
|
|
varModel = info['varModel']
|
|
|
|
|
model = self.getModelType(varModel) if self.getModelType(varModel) else localModel
|
|
|
|
|
if info['varType'] in ['AI','AO']:
|
|
|
|
|
value = self.getRealAO(value, info['max'], info['min'])
|
|
|
|
|
trigger = FPGATrigger if trigger else trigger
|
|
|
|
|
self.tcpVarManager.writeValue(varType, channel, value, trigger=trigger, model=model, timeoutMS=timeoutMS)
|
|
|
|
|
|
|
|
|
|
# print(1)
|
|
|
|
|
# HART模拟变量处理
|
|
|
|
|
elif modelType == 'HartSimulateVar':
|
|
|
|
|
# 仅设置值,不保存到数据库
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if self.RpcClient:
|
|
|
|
|
self.RpcClient.setVarContent(variableName, value, info['min'], info['max'], info['varType'])
|
|
|
|
|
return True
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"写入变量值失败: {str(e)}")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def _backgroundReadAllVariables(self, interval=0.5):
|
|
|
|
|
while not self.readThreadStop.is_set():
|
|
|
|
|
allVarNames = list(self.getAllVariableNames())
|
|
|
|
|
for varName in allVarNames:
|
|
|
|
|
value = self._readVariableValueOriginal(varName)
|
|
|
|
|
with self.cacheLock:
|
|
|
|
|
self.variableValueCache[varName] = value
|
|
|
|
|
time.sleep(interval)
|
|
|
|
|
|
|
|
|
|
def getAllVariableNames(self):
|
|
|
|
|
# 直接从缓存获取所有变量名,降低与数据库模型的耦合
|
|
|
|
|
return list(self.varInfoCache.keys())
|
|
|
|
|
|
|
|
|
|
def _readVariableValueOriginal(self, variableName):
|
|
|
|
|
# 完全保留原有读取逻辑
|
|
|
|
|
varInfo = self.lookupVariable(variableName)
|
|
|
|
|
value = None
|
|
|
|
|
if not varInfo:
|
|
|
|
|
if self.RpcServer:
|
|
|
|
|
existsVar, clientNames = self.RpcServer.existsVar(variableName)
|
|
|
|
|
if existsVar:
|
|
|
|
|
value = float(self.RpcServer.getVarValue(clientNames[0], variableName)['value'])
|
|
|
|
|
# return value
|
|
|
|
|
else:
|
|
|
|
|
return None
|
|
|
|
|
return None
|
|
|
|
|
modelType = varInfo['modelType']
|
|
|
|
|
info = varInfo['variableData']
|
|
|
|
|
try:
|
|
|
|
|
# 拆分为独立的协议条件判断
|
|
|
|
|
if modelType == 'ModbusTcpMasterVar':
|
|
|
|
|
pass
|
|
|
|
|
elif modelType == 'ModbusTcpSlaveVar':
|
|
|
|
|
pass
|
|
|
|
|
elif modelType == 'ModbusRtuMasterVar':
|
|
|
|
|
pass
|
|
|
|
|
elif modelType == 'ModbusRtuSlaveVar':
|
|
|
|
|
pass
|
|
|
|
|
elif modelType == 'HartVar':
|
|
|
|
|
pass
|
|
|
|
|
elif modelType == 'TcRtdVar':
|
|
|
|
|
channel = int(info['channelNumber']) - 1
|
|
|
|
|
varType = info['varType']
|
|
|
|
|
varModel = info['varModel']
|
|
|
|
|
model = self.getModelType(varModel)
|
|
|
|
|
if model == SimModel:
|
|
|
|
|
if varType == 'PT100':
|
|
|
|
|
value = self.tcpVarManager.simRTDData[channel]
|
|
|
|
|
elif varType in ['R', 'S', 'B', 'J', 'T', 'E', 'K', 'N', 'C', 'A']:
|
|
|
|
|
value = self.tcpVarManager.simTCData[channel]
|
|
|
|
|
# if self.RpcClient:
|
|
|
|
|
# self.RpcClient.setVarContent(variableName, value, info['min'], info['max'], info['varType'])
|
|
|
|
|
# return value
|
|
|
|
|
else:
|
|
|
|
|
if varType == 'PT100':
|
|
|
|
|
value = self.writeRTD[channel]
|
|
|
|
|
elif varType in ['R', 'S', 'B', 'J', 'T', 'E', 'K', 'N', 'C', 'A']:
|
|
|
|
|
value = self.writeTC[channel]
|
|
|
|
|
# if self.RpcClient:
|
|
|
|
|
# self.RpcClient.setVarContent(variableName, value, info['min'], info['max'], info['varType'])
|
|
|
|
|
# return value
|
|
|
|
|
elif modelType == 'AnalogVar':
|
|
|
|
|
channel = int(info['channelNumber']) - 1
|
|
|
|
|
varType = info['varType']
|
|
|
|
|
varModel = info['varModel']
|
|
|
|
|
model = self.getModelType(varModel)
|
|
|
|
|
value = self.tcpVarManager.readValue(varType, channel, model=model)
|
|
|
|
|
if varType in ['AI','AO']:
|
|
|
|
|
value = self.getRealAI(value, info['max'], info['min'])
|
|
|
|
|
|
|
|
|
|
# return value
|
|
|
|
|
elif modelType == 'HartSimulateVar':
|
|
|
|
|
pass
|
|
|
|
|
if value is not None:
|
|
|
|
|
if self.RpcClient:
|
|
|
|
|
self.RpcClient.setVarContent(variableName, value, info['min'], info['max'], info['varType'])
|
|
|
|
|
self.historyDBManage.writeVarValue(variableName, value)
|
|
|
|
|
# print('sucess')
|
|
|
|
|
return value
|
|
|
|
|
else:
|
|
|
|
|
return None
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"读取变量值失败: {str(e)}")
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def readVariableValue(self, variableName):
|
|
|
|
|
# 优先从缓存读取,未命中则走原有逻辑
|
|
|
|
|
with self.cacheLock:
|
|
|
|
|
if variableName in self.variableValueCache:
|
|
|
|
|
return self.variableValueCache[variableName]
|
|
|
|
|
return self._readVariableValueOriginal(variableName)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# def sendTrigger(self, variableName, value, timeoutMS):
|
|
|
|
|
# self.writeVariableValue(variableName, value, trigger=True, timeoutMS = timeoutMS)
|
|
|
|
|
|
|
|
|
|
def recvDeltaT(self):
|
|
|
|
|
return self.tcpVarManager.recvDeltaT()
|
|
|
|
|
|
|
|
|
|
def shutdown(self):
|
|
|
|
|
self.tcpVarManager.shutdown()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def getRealAO(self, value,highValue, lowValue):
|
|
|
|
|
if highValue:
|
|
|
|
|
lowValue = float(lowValue)
|
|
|
|
|
highValue = float(highValue)
|
|
|
|
|
return (16 * (value - lowValue) + 4 * (highValue-lowValue))/(1000 * (highValue - lowValue))
|
|
|
|
|
else:
|
|
|
|
|
return value/1000
|
|
|
|
|
|
|
|
|
|
def getRealAI(self, mA, highValue, lowValue):
|
|
|
|
|
"""
|
|
|
|
|
将毫安值转换为实际工程值(getRealAO的反向计算)
|
|
|
|
|
|
|
|
|
|
:param mA: 毫安值
|
|
|
|
|
:param highValue: 工程值上限
|
|
|
|
|
:param lowValue: 工程值下限
|
|
|
|
|
:return: 实际工程值
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
if highValue:
|
|
|
|
|
lowValue = float(lowValue)
|
|
|
|
|
highValue = float(highValue)
|
|
|
|
|
# 反向计算: value = (1000 * mA * (highValue - lowValue) - 4*(highValue - lowValue)) / 16 + lowValue
|
|
|
|
|
return (1000 * mA * (highValue - lowValue) - 4 * (highValue - lowValue)) / 16.0 + lowValue
|
|
|
|
|
else:
|
|
|
|
|
return mA * 1000
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"工程值转换失败: {str(e)}")
|
|
|
|
|
return 0.0 # 默认返回0避免中断流程
|
|
|
|
|
|
|
|
|
|
def getModelType(self, varModel):
|
|
|
|
|
if varModel == '本地值':
|
|
|
|
|
return localModel
|
|
|
|
|
elif varModel == '远程值':
|
|
|
|
|
return NetModel
|
|
|
|
|
elif varModel == '模拟值':
|
|
|
|
|
return SimModel
|
|
|
|
|
|
|
|
|
|
def disconnectClient(self, clientName):
|
|
|
|
|
if self.RpcServer:
|
|
|
|
|
self.RpcServer.removeClient(clientName)
|
|
|
|
|
|
|
|
|
|
|