0718更新 修复Modbus相关

main
zcwBit 3 months ago
parent 02f42ab766
commit 165659ea10

@ -713,13 +713,13 @@ QCheckBox#userBox::indicator{
QCheckBox#userBox::indicator:checked{
image: url(:/static/checkoff.png);
image: url(./Static/checkoff.png);
}
QCheckBox#userBox::indicator:enabled:unchecked{
image: url(:/static/checkon.png);
image: url(./Static/checkon.png);
}
@ -816,7 +816,7 @@ QComboBox#timeBox::drop-down{
QComboBox#setBox::drop-down, QComboBox#ProTypeBox::drop-down,QComboBox#TcRtdTypeBox::drop-down, QComboBox#ModbusTypeBox::drop-down, QComboBox#timeBox::drop-down{
image: url(:/static/down.png);
image: url(./Static/down.png);
}

@ -28,7 +28,7 @@ class LoginWidget(QWidget):
self.resize(306, 451)
self.picLabel = QLabel()
self.picLabel.setPixmap(QPixmap(':/static/userPic.png'))
self.picLabel.setPixmap(QPixmap('./Static/userPic.png'))
self.picLabel.setScaledContents(True)
self.userEdit = QLineEdit()

@ -45,7 +45,7 @@ class MainWindow(QMainWindow):
super(MainWindow, self).__init__()
InitParameterDB()
self.setupUi()
# self.setStyleSheet(CommonHelper.readQss('static/main.qss'))
# self.setStyleSheet(CommonHelper.readQss('Static/main.qss'))
self.setWindowFlags(Qt.FramelessWindowHint|Qt.WindowSystemMenuHint)
self.SHADOW_WIDTH = 0 #边框距离
@ -130,7 +130,7 @@ class MainWindow(QMainWindow):
self.varManageTabWidget.addTab(self.rpcVarTableWidget, '远程通讯')
#添加导入变量按钮
self.importVarButton = QPushButton(QIcon(':/static/import.png'), '导入变量')
self.importVarButton = QPushButton(QIcon('./Static/import.png'), '导入变量')
self.importVarButton.setObjectName('importBtn')
self.importVarButton.setIconSize(QSize(22, 22))
self.importVarButton.setFlat(True)
@ -421,7 +421,7 @@ class MainWindow(QMainWindow):
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle(QtWidgets.QStyleFactory.create('Fusion'))
app.setStyleSheet(CommonHelper.readQss('static/main.qss'))
app.setStyleSheet(CommonHelper.readQss('Static/main.qss'))
# print(QtWidgets.QStyleFactory.keys())
ex = MainWindow()
ex.show()

@ -77,23 +77,23 @@ class MainLeft(QWidget):
self.protocolMag.setText("通讯配置")
self.procedureMag.setText("规程管理")
self.createProject.setIcon(QIcon(':/static/newH.png'))
# self.openProject.setIcon(QIcon(':/static/open.png'))
self.varMag.setIcon(QIcon(':/static/varMag.png'))
self.trendMag.setIcon(QIcon(':/static/trend.png'))
self.userMag.setIcon(QIcon(':/static/userMag.png'))
self.protocolMag.setIcon(QIcon(':/static/setting.png'))
self.procedureMag.setIcon(QIcon(':/static/procedure.png'))
self.createProject.setIcon(QIcon('./Static/newH.png'))
# self.openProject.setIcon(QIcon('./Static/open.png'))
self.varMag.setIcon(QIcon('./Static/varMag.png'))
self.trendMag.setIcon(QIcon('./Static/trend.png'))
self.userMag.setIcon(QIcon('./Static/userMag.png'))
self.protocolMag.setIcon(QIcon('./Static/setting.png'))
self.procedureMag.setIcon(QIcon('./Static/procedure.png'))
for btn in [self.createProject, self.varMag, self.trendMag, self.userMag, self.protocolMag, self.procedureMag]:
self.setBtn(btn)
# self.openProject.clicked.connect(lambda:self.openProject.setIcon(QIcon(':/static/openH.png')))
self.createProject.clicked.connect(lambda:self.createProject.setIcon(QIcon(':/static/newH.png')))
self.varMag.clicked.connect(lambda:self.varMag.setIcon(QIcon(':/static/varMagH.png')))
self.trendMag.clicked.connect(lambda:self.trendMag.setIcon(QIcon(':/static/trendH.png')))
self.userMag.clicked.connect(lambda:self.userMag.setIcon(QIcon(':/static/userMagH.png')))
self.protocolMag.clicked.connect(lambda:self.protocolMag.setIcon(QIcon(':/static/settingH.png')))
# self.openProject.clicked.connect(lambda:self.openProject.setIcon(QIcon('./Static/openH.png')))
self.createProject.clicked.connect(lambda:self.createProject.setIcon(QIcon('./Static/newH.png')))
self.varMag.clicked.connect(lambda:self.varMag.setIcon(QIcon('./Static/varMagH.png')))
self.trendMag.clicked.connect(lambda:self.trendMag.setIcon(QIcon('./Static/trendH.png')))
self.userMag.clicked.connect(lambda:self.userMag.setIcon(QIcon('./Static/userMagH.png')))
self.protocolMag.clicked.connect(lambda:self.protocolMag.setIcon(QIcon('./Static/settingH.png')))
self.createProject.setChecked(True)
self.createProject.setDown(True)
@ -114,45 +114,45 @@ class MainLeft(QWidget):
def eventFilter(self, object, event):
if object == self.createProject:
if event.type() == QtCore.QEvent.HoverEnter:
self.createProject.setIcon(QIcon(':/static/newH.png'))
self.createProject.setIcon(QIcon('./Static/newH.png'))
return True
if event.type() == QtCore.QEvent.HoverLeave and not self.createProject.isChecked():
self.createProject.setIcon(QIcon(':/static/new.png'))
self.createProject.setIcon(QIcon('./Static/new.png'))
return True
# if object == self.openProject:
# if event.type() == QtCore.QEvent.HoverEnter:
# self.openProject.setIcon(QIcon(':/static/openH.png'))
# self.openProject.setIcon(QIcon('./Static/openH.png'))
# return True
# if event.type() == QtCore.QEvent.HoverLeave and not self.openProject.isChecked():
# self.openProject.setIcon(QIcon(':/static/open.png'))
# self.openProject.setIcon(QIcon('./Static/open.png'))
# return True
if object == self.varMag:
if event.type() == QtCore.QEvent.HoverEnter:
self.varMag.setIcon(QIcon(':/static/varMagH.png'))
self.varMag.setIcon(QIcon('./Static/varMagH.png'))
return True
if event.type() == QtCore.QEvent.HoverLeave and not self.varMag.isChecked():
self.varMag.setIcon(QIcon(':/static/varMag.png'))
self.varMag.setIcon(QIcon('./Static/varMag.png'))
return True
if object == self.trendMag:
if event.type() == QtCore.QEvent.HoverEnter:
self.trendMag.setIcon(QIcon(':/static/trendH.png'))
self.trendMag.setIcon(QIcon('./Static/trendH.png'))
return True
if event.type() == QtCore.QEvent.HoverLeave and not self.trendMag.isChecked():
self.trendMag.setIcon(QIcon(':/static/trend.png'))
self.trendMag.setIcon(QIcon('./Static/trend.png'))
return True
if object == self.userMag:
if event.type() == QtCore.QEvent.HoverEnter:
self.userMag.setIcon(QIcon(':/static/userMagH.png'))
self.userMag.setIcon(QIcon('./Static/userMagH.png'))
return True
if event.type() == QtCore.QEvent.HoverLeave and not self.userMag.isChecked():
self.userMag.setIcon(QIcon(':/static/userMag.png'))
self.userMag.setIcon(QIcon('./Static/userMag.png'))
return True
if object == self.protocolMag:
if event.type() == QtCore.QEvent.HoverEnter:
self.protocolMag.setIcon(QIcon(':/static/settingH.png'))
self.protocolMag.setIcon(QIcon('./Static/settingH.png'))
return True
if event.type() == QtCore.QEvent.HoverLeave and not self.protocolMag.isChecked():
self.protocolMag.setIcon(QIcon(':/static/setting.png'))
self.protocolMag.setIcon(QIcon('./Static/setting.png'))
return True
return False
@ -164,9 +164,9 @@ class MainLeft(QWidget):
self.userMag.setDown(False)
self.protocolMag.setDown(False)
self.createProject.setIcon(QIcon(':/static/new.png'))
# self.openProject.setIcon(QIcon(':/static/open.png'))
self.varMag.setIcon(QIcon(':/static/varMag.png'))
self.trendMag.setIcon(QIcon(':/static/trend.png'))
self.userMag.setIcon(QIcon(':/static/userMag.png'))
self.protocolMag.setIcon(QIcon(':/static/setting.png'))
self.createProject.setIcon(QIcon('./Static/new.png'))
# self.openProject.setIcon(QIcon('./Static/open.png'))
self.varMag.setIcon(QIcon('./Static/varMag.png'))
self.trendMag.setIcon(QIcon('./Static/trend.png'))
self.userMag.setIcon(QIcon('./Static/userMag.png'))
self.protocolMag.setIcon(QIcon('./Static/setting.png'))

@ -24,7 +24,7 @@ class MainTop(QtWidgets.QWidget):
self.searchEdit = QtWidgets.QLineEdit()
action = QtWidgets.QAction(self)
action.setIcon(QIcon(':/static/search.png'))
action.setIcon(QIcon('./Static/search.png'))
self.searchEdit.addAction(action, QtWidgets.QLineEdit.LeadingPosition)
self.searchEdit.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
self.searchEdit.setObjectName('searchEdit')
@ -35,16 +35,16 @@ class MainTop(QtWidgets.QWidget):
self.searchEdit.textChanged.connect(self.searchEditTextChanged)
# print(Globals.getValue('SearchWidget'))
self.minBtn = QtWidgets.QPushButton(QIcon(':/static/min.png'), '' ,self)
self.minBtn = QtWidgets.QPushButton(QIcon('./Static/min.png'), '' ,self)
self.minBtn.setObjectName("minBtn")
self.maxBtn = QtWidgets.QPushButton(QIcon(':/static/normal.png'), '' ,self)
self.maxBtn = QtWidgets.QPushButton(QIcon('./Static/normal.png'), '' ,self)
self.maxBtn.setObjectName("maxBtn")
self.closeBtn = QtWidgets.QPushButton(QIcon(':/static/close.png'), '' ,self)
self.closeBtn = QtWidgets.QPushButton(QIcon('./Static/close.png'), '' ,self)
self.closeBtn.setObjectName("closeBtn")
self.iconLabol.setPixmap(QPixmap(':/static/zhjt.png').scaled(50,50))
self.iconLabol.setPixmap(QPixmap('./Static/zhjt.png').scaled(50,50))
self.titleLabel.setText("信号发生装置")
self.closeBtn.clicked.connect(self.MainWindow.close)
@ -95,14 +95,14 @@ class MainTop(QtWidgets.QWidget):
def showMax(self):
if self.MainWindow.isMaximized():
self.MainWindow.showNormal()
self.maxBtn.setIcon(QIcon(':/static/max.png'))
self.maxBtn.setIcon(QIcon('./Static/max.png'))
self.MainWindow.verticalLayout.setStretch(0, 1)
self.MainWindow.verticalLayout.setStretch(1, 15)
else:
self.MainWindow.showMaximized()
self.MainWindow.verticalLayout.setStretch(0, 1)
self.MainWindow.verticalLayout.setStretch(1, 18)
self.maxBtn.setIcon(QIcon(':/static/normal.png'))
self.maxBtn.setIcon(QIcon('./Static/normal.png'))
def mouseDoubleClickEvent(self, e): # 双击
self.showMax()

@ -36,7 +36,7 @@ class AreaTabWidget(QTabWidget):
self.tabBar().setObjectName('areaTabBar')
self.addAreaButton = QPushButton("添加通道 ")
self.addAreaButton.setObjectName('addareabutton')
self.addAreaButton.setIcon(QIcon(':/static/add.png'))
self.addAreaButton.setIcon(QIcon('./Static/add.png'))
self.addAreaButton.setFlat(True)
self.addAreaButton.clicked.connect(self.addAreaTab)
self.setCornerWidget(self.addAreaButton)
@ -75,7 +75,7 @@ class AreaTabWidget(QTabWidget):
layout = QHBoxLayout()
addButton = QPushButton('添加通道')
addButton.setObjectName('initAreaAddButton')
icon = QIcon(':/static/add.png')
icon = QIcon('./Static/add.png')
iconSize = QSize(50,50)
addButton.setIcon(icon)
addButton.setIconSize(iconSize)
@ -196,7 +196,7 @@ class AreaWidget(QWidget):
self.okBtnValue = True
self.delAreaBtn = QPushButton('删除')
self.delAreaBtn.setIcon(QIcon(':/static/delete.png'))
self.delAreaBtn.setIcon(QIcon('./Static/delete.png'))
self.delAreaBtn.setObjectName('delAreaBtn')
self.delAreaBtn.clicked.connect(self.removeAreaTab)

@ -102,7 +102,7 @@ class ProfibusWidgets(QWidget):
self.startProtocolBtn = QPushButton()
self.startProtocolBtn.setObjectName("profibusStartProtocolBtn")
# self.startProtocolBtn.setIcon(QIcon(':/static/startProtocol.png'))
# self.startProtocolBtn.setIcon(QIcon('./Static/startProtocol.png'))
self.startProtocolBtn.setText('开始通讯')
self.startProtocolBtn.setIcon(QIcon('Static/start_green.png'))
self.startProtocolBtn.setIconSize(QSize(23, 23))
@ -149,9 +149,9 @@ class ProfibusWidgets(QWidget):
# 创建按钮
# self.minimizeButton = QPushButton(QIcon(':/static/min.png'), "")
# self.minimizeButton = QPushButton(QIcon('./Static/min.png'), "")
# self.minimizeButton.setObjectName('minButton')
# self.closeButton = QPushButton(QIcon(':/static/close.png'), "")
# self.closeButton = QPushButton(QIcon('./Static/close.png'), "")
# self.closeButton.setObjectName('closeButton')
# # 按钮点击事件连接
@ -162,7 +162,7 @@ class ProfibusWidgets(QWidget):
# hLayout.addWidget(self.closeButton)
iconLabel = QLabel()
pix = QPixmap('static/Hicent.png')
pix = QPixmap('Static/Hicent.png')
scaledPixmap = pix.scaled(168, 28, Qt.KeepAspectRatio)
iconLabel.setPixmap(scaledPixmap)
iconLabel.setScaledContents(True)
@ -222,7 +222,7 @@ class ProfibusWidgets(QWidget):
self.setLayout(self.mainLayout)
# self.setCentralWidget(self.stackWidget)
self.setWindowIcon(QIcon(':/static/Hicent.jpg'))
self.setWindowIcon(QIcon('./Static/Hicent.jpg'))
self.setWindowTitle("PROFIBUS总线测试工具")
@ -239,13 +239,13 @@ class ProfibusWidgets(QWidget):
if self.startProtocolBtn.isChecked():
self.startProtocolBtn.setText('停止通讯')
self.startProtocolBtn.setIcon(QIcon(':/static/pause.png'))
self.startProtocolBtn.setIcon(QIcon('./Static/pause.png'))
self.startProtocolBtn.setIconSize(QSize(22, 22))
self.protocolTimer.start(500)
else:
self.startProtocolBtn.setText('开始通讯')
self.startProtocolBtn.setIcon(QIcon(':/static/start.png'))
self.startProtocolBtn.setIcon(QIcon('./Static/start.png'))
self.protocolTimer.stop()
def readValues(self):
@ -315,7 +315,7 @@ class ProfibusWidgets(QWidget):
self.process = subprocess.Popen("D:\\EnTalk PROFIBUS Manager\\DP.exe",startupinfo=startupInfo)
QTimer.singleShot(500, lambda:self.showLowerWidget(self.process))
# self.showFullScreen()
# self.switchBtn.setIcon(QIcon(':/static/varMagH.png'))
# self.switchBtn.setIcon(QIcon('./Static/varMagH.png'))
def switchDeviceValueManageWidget(self):
self.stackWidget.setCurrentIndex(0)

@ -13,17 +13,17 @@ class ProjectWidgets(QtWidgets.QWidget):
self.setupUi()
def setupUi(self):
self.createBtn = QPushButton(QIcon(':/static/add.png'), '新建工程')
self.createBtn = QPushButton(QIcon('./Static/add.png'), '新建工程')
self.createBtn.setObjectName('createBtn')
self.createBtn.setIconSize(QSize(22, 22))
self.createBtn.clicked.connect(self.createProject)
self.importBtn = QPushButton(QIcon(':/static/import.png'), '导入工程')
self.importBtn = QPushButton(QIcon('./Static/import.png'), '导入工程')
self.importBtn.setObjectName('importBtn')
self.importBtn.setIconSize(QSize(22, 22))
self.importBtn.clicked.connect(self.importProject)
self.exportBtn = QPushButton(QIcon(':/static/export.png'), '导出工程')
self.exportBtn = QPushButton(QIcon('./Static/export.png'), '导出工程')
self.exportBtn.setObjectName('exportBtn')
self.exportBtn.setIconSize(QSize(22, 22))
self.exportBtn.clicked.connect(self.exportPorject)

@ -97,7 +97,7 @@ class RegisterWidget(QWidget):
self.setWindowTitle("Form")
pix = QtGui.QPixmap(':/:/static/logo.png')
pix = QtGui.QPixmap(':/Static/logo.png')
self.label.setPixmap(pix)
self.label.setScaledContents(True)
self.label.setMaximumSize(QSize(110,40))
@ -145,7 +145,7 @@ class RegisterWidget(QWidget):
'提示',
"注册成功",
QMessageBox.Yes)
with open('static/license.lic', 'w') as f:
with open('Static/license.lic', 'w') as f:
f.write(passwd)
self.showMainWindow()
self.close()

@ -16,16 +16,16 @@ class UserWidgets(QtWidgets.QWidget):
super(UserWidgets, self).__init__(parent)
self.setAttribute(Qt.WA_StyledBackground, True)
self.createBtn = QPushButton(QIcon(':/static/add.png'), '添加用户')
self.createBtn = QPushButton(QIcon('./Static/add.png'), '添加用户')
self.createBtn.setObjectName('forceBtn')
self.createBtn.setIconSize(QSize(22, 22))
self.createBtn.clicked.connect(self.createUser)
# self.importBtn = QPushButton(QIcon(':/static/import.png'), '导入变量')
# self.importBtn = QPushButton(QIcon('./Static/import.png'), '导入变量')
# self.importBtn.setObjectName('importBtn')
# self.importBtn.setIconSize(QSize(22, 22))
self.delBtn = QPushButton(QIcon(':/static/delete.png'), '批量删除')
self.delBtn = QPushButton(QIcon('./Static/delete.png'), '批量删除')
self.delBtn.setObjectName('delBtn')
self.delBtn.setIconSize(QSize(22, 22))
self.delBtn.clicked.connect(self.deleteUser)

@ -1,116 +1,113 @@
from PyQt5.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt, QTimer)
from PyQt5.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PyQt5.QtWidgets import (QApplication, QGridLayout, QHBoxLayout, QLabel,
QPushButton, QSizePolicy, QSpacerItem, QTextEdit,
QWidget)
from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QTextEdit, QHBoxLayout, QVBoxLayout, QGridLayout, QSpacerItem, QSizePolicy
from PyQt5.QtCore import Qt, QTimer, QCoreApplication
from PyQt5.QtGui import QIcon
from utils import Globals
from protocol.Celery.MBTCPMaster import app
from Static import static
class MessageWidget(QWidget):
def __init__(self, parent=None):
super(MessageWidget, self).__init__(parent)
self.setObjectName(u"self")
self.setupUI()
self.setupConnections()
def setupUI(self):
"""设置UI界面"""
self.setObjectName("MessageWidget")
self.resize(1037, 648)
self.decima = 16
self.recvLabel = QLabel(self)
self.setWindowTitle('报文查看')
# self.setWindowIcon(QIcon('./Static/file.png'))
# 创建控件
self.recvLabel = QLabel("接收到报文")
self.recvLabel.setObjectName("mesLabel")
self.recvLabel.setAlignment(Qt.AlignCenter)
self.sendLabel = QLabel(self)
self.sendLabel = QLabel("发送的报文")
self.sendLabel.setObjectName("mesLabel")
self.sendLabel.setAlignment(Qt.AlignCenter)
self.clearButton = QPushButton(self)
self.clearButton = QPushButton("清空报文")
self.clearButton.setObjectName("mesButton")
self.reButton = QPushButton(self)
self.reButton.setObjectName("mesButton")
self.decimaButton = QPushButton(self)
self.decimaButton.setObjectName("mesButton")
self.recvEdit = QTextEdit(self)
self.refreshButton = QPushButton("停止刷新")
self.refreshButton.setObjectName("mesButton")
self.recvEdit = QTextEdit()
self.recvEdit.setObjectName("mesEdit")
self.sendEdit = QTextEdit(self)
self.sendEdit = QTextEdit()
self.sendEdit.setObjectName("mesEdit")
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.horizontalLayout.addWidget(self.clearButton)
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout.addItem(self.horizontalSpacer)
self.horizontalLayout.addWidget(self.reButton)
self.horizontalLayout.addWidget(self.decimaButton)
self.gridLayout = QGridLayout(self)
self.gridLayout.setObjectName("gridLayout")
self.gridLayout.addWidget(self.recvLabel, 1, 0, 1, 1)
self.gridLayout.addWidget(self.sendLabel, 1, 1, 1, 1)
self.gridLayout.addWidget(self.recvEdit, 2, 0, 1, 1)
self.gridLayout.addWidget(self.sendEdit, 2, 1, 1, 1)
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 2)
self.setWindowTitle('报文查看')
self.setWindowIcon(QIcon('./:/static/file.png'))
self.recvLabel.setText(QCoreApplication.translate("Form", u"\u63a5\u6536\u5230\u62a5\u6587", None))
self.sendLabel.setText(QCoreApplication.translate("Form", u"\u53d1\u9001\u7684\u62a5\u6587", None))
self.clearButton.setText("清空报文")
self.reButton.setText('停止刷新')
self.decimaButton.setText('切换进制')
# 布局设置
self.setupLayout()
# 定时器设置
self.timer = QTimer(self)
# 将定时器超时信号与槽函数showTime()连接
self.timer.timeout.connect(self.addText)
self.timer.start(1000) # 启动timer
self.reButton.clicked.connect(self.stopRe)
self.decimaButton.clicked.connect(self.changeDecima)
self.clearButton.clicked.connect(self.clearText)
def clearText(self):
self.timer.timeout.connect(self.updateMessages)
self.timer.start(1000) # 每秒更新一次
def setupLayout(self):
"""设置布局"""
# 按钮布局
buttonLayout = QHBoxLayout()
buttonLayout.addWidget(self.clearButton)
buttonSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
buttonLayout.addItem(buttonSpacer)
buttonLayout.addWidget(self.refreshButton)
# 主布局
mainLayout = QGridLayout(self)
mainLayout.addLayout(buttonLayout, 0, 0, 1, 2)
mainLayout.addWidget(self.recvLabel, 1, 0, 1, 1)
mainLayout.addWidget(self.sendLabel, 1, 1, 1, 1)
mainLayout.addWidget(self.recvEdit, 2, 0, 1, 1)
mainLayout.addWidget(self.sendEdit, 2, 1, 1, 1)
def setupConnections(self):
"""设置信号连接"""
self.clearButton.clicked.connect(self.clearMessages)
self.refreshButton.clicked.connect(self.toggleRefresh)
def updateMessages(self):
"""更新报文显示"""
try:
protocolManage = Globals.getValue('protocolManage')
if not protocolManage:
return
# 获取 Modbus 报文
messages = protocolManage.getModbusMessages()
# 清空并更新接收报文
self.recvEdit.clear()
for msg in messages['receive']:
self.recvEdit.append(msg)
# 清空并更新发送报文
self.sendEdit.clear()
for msg in messages['send']:
self.sendEdit.append(msg)
except Exception as e:
pass
def clearMessages(self):
"""清空报文"""
self.recvEdit.clear()
self.sendEdit.clear()
def changeDecima(self):
if self.decima == 16:
self.decima = 10
elif self.decima == 10:
self.decima = 16
def stopRe(self):
try:
protocolManage = Globals.getValue('protocolManage')
if protocolManage:
protocolManage.clearModbusMessages()
except Exception as e:
pass
def toggleRefresh(self):
"""切换刷新状态"""
if self.timer.isActive():
self.timer.stop()
self.reButton.setText('开始刷新')
self.refreshButton.setText('开始刷新')
else:
self.timer.start()
self.reButton.setText('停止刷新')
def addText(self):
try:
self.recvEdit.clear()
self.sendEdit.clear()
if self.decima == 16:
for x in app.backend.client.lrange("16R" , 0 , -1):
text = str(x)[2:-1]
self.recvEdit.append(text)
for x in app.backend.client.lrange("16S" , 0 , -1):
text = str(x)[2:-1]
self.sendEdit.append(text)
elif self.decima == 10:
for x in app.backend.client.lrange("10R" , 0 , -1):
text = str(x)[2:-1]
self.recvEdit.append(text)
for x in app.backend.client.lrange("10S" , 0 , -1):
text = str(x)[2:-1]
self.sendEdit.append(text)
except:
pass
self.timer.start(1000)
self.refreshButton.setText('停止刷新')

@ -12,14 +12,7 @@ from PyQt5.QtWidgets import QItemDelegate, QHBoxLayout, QWidget, QMessageBox, QC
from sympy import N
from protocol.Celery.MBTCPMaster import app as MBTCPMApp
from protocol.Celery.MBRTUMaster import app as MBRTUMApp
from protocol.Celery.MBRTUSlave import app as MBRTUSApp
from protocol.Celery.MBTCPSlave import app as MBTCPSApp
# from protocol.Celery.MBTCPMaster.MBTCPMTask import setValue as setMTcpValue
# from protocol.Celery.MBRTUMaster.MBRTUMTask import setValue as setMRTUValue
from celery.result import AsyncResult
# 移除 Celery 相关导入,现在使用 ProtocolManage 和 ModbusManager
from ..TrendManage.ActualTrendWidget import ActualTrend
from model.ProjectModel.VarManage import *
@ -129,16 +122,13 @@ class VarTableModel(QAbstractTableModel):
if QModelIndex.column() == 2:
varName = self.datas[QModelIndex.row()][3]
if varName != '':
# print(uid)
try:
uid = MBTCPMApp.backend.get('ModBus').decode('utf-8')
res = AsyncResult(uid) # 参数为task id
if res.result:
# print(res.result, res.date_done)
result = res.result[varName]
if result or result in [0, '0']:
protocolManage = Globals.getValue('protocolManage')
if protocolManage:
result = protocolManage.readVariableValue(varName)
if result is not None:
self.datas[QModelIndex.row()][QModelIndex.column()] = result
except:
except Exception as e:
pass
return QVariant(self.datas[QModelIndex.row()][QModelIndex.column()])
@ -350,24 +340,24 @@ class VarButtonDelegate(QItemDelegate):
"超出量程范围",
QMessageBox.Yes)
return
# 0 : MODBUSTCP 主站模式
# 1 : MODBUSTCP 从站模式
# 2 : MODBUSRTU 主站模式
# 3 : MODBUSRTU 从站模式
proType = Globals.getValue('currentProType')
forceVars = Globals.getValue('forceVars')
forceVars.add(name)
Globals.setValue('forceVars', forceVars)
# print(Globals.getValue('forceVars'))
if proType == '0':
MBTCPMApp.send_task('protocol.Celery.MBTCPMaster.MBTCPMTask.setValue',args=[name, varType, slaveID, address, value, order])
if proType == '1':
MBTCPSApp.send_task('protocol.Celery.MBTCPSlave.MBTCPSTask.setValue',args=[name, varType, slaveID, address, value])
elif proType == '2':
MBRTUMApp.send_task('protocol.Celery.MBRTUMaster.MBRTUMTask.setValue',args=[name, varType, slaveID, address, value, order])
elif proType == '3':
MBRTUSApp.send_task('protocol.Celery.MBRTUSlave.MBRTUSTask.setValue',args=[name, varType, slaveID, address, value])
# 使用新的 ProtocolManage 进行变量写入
protocolManage = Globals.getValue('protocolManage')
if protocolManage:
try:
result = protocolManage.writeVariableValue(name, value)
if result:
forceVars = Globals.getValue('forceVars')
if forceVars is None:
forceVars = set()
forceVars.add(name)
Globals.setValue('forceVars', forceVars)
else:
QMessageBox.warning(self.parent(), '错误', f'变量 {name} 写入失败', QMessageBox.Yes)
except Exception as e:
QMessageBox.warning(self.parent(), '错误', f'写入变量时发生错误: {str(e)}', QMessageBox.Yes)
else:
QMessageBox.warning(self.parent(), '错误', '协议管理器未初始化', QMessageBox.Yes)
def edit_action(self):
sender = self.sender()

@ -10,10 +10,7 @@ from UI.VarManages.MessageWidget import MessageWidget
from model.ProjectModel.ProjectManage import ProjectManage
from model.ProjectModel.VarManage import ModbusVarManage
from utils import Globals
from protocol.Celery.MBTCPMaster import app as MBTCPMApp
from protocol.Celery.MBRTUMaster import app as MBRTUMApp
from protocol.Celery.MBRTUSlave import app as MBRTUSApp
from protocol.Celery.MBTCPSlave import app as MBTCPSApp
# 移除 Celery 相关导入,现在使用 ProtocolManage 和 ModbusManager
from protocol.TCP.TemToMv import temToMv
from protocol.TCP.Analog import getRealAO
import re
@ -28,37 +25,37 @@ class VarWidgets(QtWidgets.QWidget):
def setupUI(self):
self.setAttribute(Qt.WA_StyledBackground, True)
self.createBtn = QPushButton(QIcon(':/static/add.png'), '新建变量')
self.createBtn = QPushButton(QIcon(':/Static/add.png'), '新建变量')
self.createBtn.setObjectName('createBtn')
self.createBtn.setIconSize(QSize(22, 22))
self.createBtn.clicked.connect(self.createVar)
self.forceBtn = QPushButton(QIcon(':/static/start.png'), '批量强制')
self.forceBtn = QPushButton(QIcon(':/Static/start.png'), '批量强制')
self.forceBtn.setObjectName('forceBtn')
self.forceBtn.setIconSize(QSize(22, 22))
self.forceBtn.clicked.connect(self.forceVar)
self.clearBtn = QPushButton(QIcon(':/static/clear.png'), '清除颜色')
self.clearBtn = QPushButton(QIcon(':/Static/clear.png'), '清除颜色')
self.clearBtn.setObjectName('clearBtn')
self.clearBtn.setIconSize(QSize(22, 22))
self.clearBtn.clicked.connect(self.clearColour)
# self.importBtn = QPushButton(QIcon(':/static/import.png'), '导入变量')
# self.importBtn = QPushButton(QIcon(':/Static/import.png'), '导入变量')
# self.importBtn.setObjectName('importBtn')
# self.importBtn.setIconSize(QSize(22, 22))
# self.importBtn.clicked.connect(self.importVar)
# self.exportBtn = QPushButton(QIcon(':/static/export.png'), '导出变量')
# self.exportBtn = QPushButton(QIcon(':/Static/export.png'), '导出变量')
# self.exportBtn.setObjectName('exportBtn')
# self.exportBtn.setIconSize(QSize(22, 22))
# self.exportBtn.clicked.connect(self.exportVar)
self.messageBtn = QPushButton(QIcon(':/static/message.png'), '查看报文')
self.messageBtn = QPushButton(QIcon(':/Static/message.png'), '查看报文')
self.messageBtn.setObjectName('messageBtn')
self.messageBtn.setIconSize(QSize(22, 22))
self.messageBtn.clicked.connect(self.showMessage)
self.startProtocolBtn = QPushButton(QIcon(':/static/startProtocol.png'), '开始通讯')
self.startProtocolBtn = QPushButton(QIcon(':/Static/startProtocol.png'), '开始通讯')
self.startProtocolBtn.setObjectName('startProtocolBtn')
self.startProtocolBtn.setIconSize(QSize(22, 22))
self.startProtocolBtn.clicked.connect(self.startProtocol)
@ -210,51 +207,63 @@ class VarWidgets(QtWidgets.QWidget):
self.varView.model.append_data(['', '', '', '', '', '', '', '', '', '', '','本地值','int'])
def forceVar(self):
check = [i for i,x in enumerate(self.varView.model.checkList) if x == 'Checked']
# check.sort(reverse=True)
check = [i for i, x in enumerate(self.varView.model.checkList) if x == 'Checked']
if not check:
QMessageBox.information(self, '提示', '请先勾选要强制的变量', QMessageBox.Yes)
return
protocolManage = Globals.getValue('protocolManage')
if not protocolManage:
QMessageBox.warning(self, '错误', '协议管理器未初始化', QMessageBox.Yes)
return
forceVars = Globals.getValue('forceVars')
if forceVars is None:
forceVars = set()
for i in check:
varMes = self.varView.model.datas[i]
value, name, des, varType, slaveID, address, min, max, order = str(varMes[1]), str(varMes[3]), str(varMes[4]), str(varMes[5]), str(varMes[6]), str(varMes[7]), str(varMes[8]), str(varMes[9]), str(varMes[10]), str(varMes[11])
value, name, des, varType, slaveID, address, min, max, order = str(varMes[1]), str(varMes[3]), str(varMes[4]), str(varMes[5]), str(varMes[6]), str(varMes[7]), str(varMes[8]), str(varMes[9]), str(varMes[10])
pattern = re.compile(r'[^0-9\.-]+')
if not value or re.findall(pattern, str(value)):
reply = QMessageBox.question(self.parent(),
'警告',
"请输入强制值或数字",
QMessageBox.Yes)
QMessageBox.warning(self, '警告', "请输入强制值或数字", QMessageBox.Yes)
return
if min and max:
if float(value) < float(min) or float(value) > float(max):
reply = QMessageBox.question(self.parent(),
'警告',
"超出量程范围",
QMessageBox.Yes)
return
try:
if float(value) < float(min) or float(value) > float(max):
QMessageBox.warning(self, '警告', "超出量程范围", QMessageBox.Yes)
return
except Exception:
QMessageBox.warning(self, '警告', "量程范围格式错误", QMessageBox.Yes)
return
elif min and not max:
if float(value) < float(min):
reply = QMessageBox.question(self.parent(),
'警告',
"超出量程范围",
QMessageBox.Yes)
return
try:
if float(value) < float(min):
QMessageBox.warning(self, '警告', "超出量程范围", QMessageBox.Yes)
return
except Exception:
QMessageBox.warning(self, '警告', "量程范围格式错误", QMessageBox.Yes)
return
elif max and not min:
if float(value) > float(max):
reply = QMessageBox.question(self.parent(),
'警告',
"超出量程范围",
QMessageBox.Yes)
return
proType = Globals.getValue('currentProType')
forceVars = Globals.getValue('forceVars')
forceVars.add(name)
Globals.setValue('forceVars', forceVars)
if proType == '0':
MBTCPMApp.send_task('protocol.Celery.MBTCPMaster.MBTCPMTask.setValue',args=[name, varType, slaveID, address, value, order])
if proType == '1':
MBTCPSApp.send_task('protocol.Celery.MBTCPSlave.MBTCPSTask.setValue',args=[name, varType, slaveID, address, value])
elif proType == '2':
MBRTUMApp.send_task('protocol.Celery.MBRTUMaster.MBRTUMTask.setValue',args=[name, varType, slaveID, address, value, order])
elif proType == '3':
MBRTUSApp.send_task('protocol.Celery.MBRTUSlave.MBRTUSTask.setValue',args=[name, varType, slaveID, address, value])
try:
if float(value) > float(max):
QMessageBox.warning(self, '警告', "超出量程范围", QMessageBox.Yes)
return
except Exception:
QMessageBox.warning(self, '警告', "量程范围格式错误", QMessageBox.Yes)
return
# 使用新的 ProtocolManage 进行变量写入
try:
result = protocolManage.writeVariableValue(name, value)
if result:
forceVars.add(name)
else:
QMessageBox.information(self, '提示', f'变量 {name} 写入失败', QMessageBox.Yes)
except Exception as e:
QMessageBox.warning(self, '错误', f'写入变量 {name} 时发生错误: {str(e)}', QMessageBox.Yes)
Globals.setValue('forceVars', forceVars)
def importVar(self):
@ -277,21 +286,59 @@ class VarWidgets(QtWidgets.QWidget):
self.messageWidget.show()
def startProtocol(self):
protocolManage = Globals.getValue('protocolManage')
if not protocolManage:
QMessageBox.warning(self, '错误', '协议管理器未初始化', QMessageBox.Yes)
return
if not self._isPopenOpen:
ProjectManage.startProtocol()
self._isPopenOpen = True
self.startProtocolBtn.setText('停止通讯')
self.startProtocolBtn.setIcon(QIcon(':/static/pause.png'))
# 根据 modbusType 启动对应的 Modbus 通讯
print(self.modbusType)
try:
success = False
if self.modbusType == 'ModbusTcpMaster': # TCP Master
success = protocolManage.startModbusTcpMaster()
elif self.modbusType == 'ModbusTcpSlave': # TCP Slave
success = protocolManage.startModbusTcpSlave()
elif self.modbusType == 'ModbusRtuMaster': # RTU Master
success = protocolManage.startModbusRtuMaster()
elif self.modbusType == 'ModbusRtuSlave': # RTU Slave
success = protocolManage.startModbusRtuSlave()
if success:
self._isPopenOpen = True
self.startProtocolBtn.setText('停止通讯')
self.startProtocolBtn.setIcon(QIcon(':/Static/pause.png'))
else:
QMessageBox.warning(self, '错误', 'Modbus 通讯启动失败', QMessageBox.Yes)
except Exception as e:
QMessageBox.warning(self, '错误', f'启动通讯时发生错误: {str(e)}', QMessageBox.Yes)
else:
ProjectManage.closePopen()
self._isPopenOpen = False
self.startProtocolBtn.setText('开始通讯')
self.startProtocolBtn.setIcon(QIcon(':/static/startProtocol.png'))
# 停止对应的 Modbus 通讯
try:
success = False
if self.modbusType == 'ModbusTcpMaster': # TCP Master
success = protocolManage.stopModbusTcpMaster()
elif self.modbusType == 'ModbusTcpSlave': # TCP Slave
success = protocolManage.stopModbusTcpSlave()
elif self.modbusType == 'ModbusRtuMaster': # RTU Master
success = protocolManage.stopModbusRtuMaster()
elif self.modbusType == 'ModbusRtuSlave': # RTU Slave
success = protocolManage.stopModbusRtuSlave()
if success:
self._isPopenOpen = False
self.startProtocolBtn.setText('开始通讯')
self.startProtocolBtn.setIcon(QIcon(':/Static/startProtocol.png'))
else:
QMessageBox.warning(self, '错误', 'Modbus 通讯停止失败', QMessageBox.Yes)
except Exception as e:
QMessageBox.warning(self, '错误', f'停止通讯时发生错误: {str(e)}', QMessageBox.Yes)
def initIcon(self):
self._isPopenOpen = False
self.startProtocolBtn.setText('开始通讯')
self.startProtocolBtn.setIcon(QIcon(':/static/startProtocol.png'))
self.startProtocolBtn.setIcon(QIcon(':/Static/startProtocol.png'))
class HartWidgets(VarWidgets):
@ -415,7 +462,7 @@ class TcRtdWidgets(VarWidgets):
except Exception:
QMessageBox.warning(self, '警告', "量程范围格式错误", QMessageBox.Yes)
return
res = Globals.getValue('protocolManage').writeVariableValue(varName, float(value))
res = Globals.getValue('protocolManage').writeVariableValue(varName, value)
if res:
forceVars.add(varName)
else:

@ -4,16 +4,21 @@ from utils import Globals
from model.ClientModel.Client import Client
from UI.RegisterWidgets.RegisterWidget import RegisterWidget
from model.ClientModel.RegisterManage import Register
# import Static.staticQrc_rc # 导入资源文件
import sys
import logging
# 设置 modbus_tk 日志级别为 ERROR避免过多的调试信息和格式化错误
logging.getLogger('modbus_tk').setLevel(logging.ERROR)
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle(QStyleFactory.create('Fusion'))
app.setStyleSheet(CommonHelper.readQss('static/Main.qss')
+ CommonHelper.readQss('static/profibus.qss')
+ CommonHelper.readQss('static/Area.qss'))
app.setStyleSheet(CommonHelper.readQss('Static/Main.qss')
+ CommonHelper.readQss('Static/profibus.qss')
+ CommonHelper.readQss('Static/Area.qss'))
reg = Register()
if not reg.checkLicense():
regWidget = RegisterWidget()

@ -49,6 +49,9 @@ class Client(object):
popenBeat = Globals.getValue('beatPopen')
histroyMan = Globals.getValue('historyDBManage')
histroyMan.close()
protocolManage = Globals.getValue('protocolManage')
if protocolManage:
protocolManage.shutdown()
if popen:
popen.kill()
if popenBeat:

@ -3,7 +3,7 @@ import json
from utils.DBModels.DeviceModels import DeviceDB
import numpy as np
from protocol.ModBus.ByteOrder import *
from protocol.ModBus.TCPMaster import *
from protocol.ModBus.tcpmaster_example import TcpMaster
import struct
import time
#从站 "AI" "DI"可强制

@ -1,7 +1,7 @@
import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_tcp, hooks
from modbus_tk import modbus_tcp
import logging
import struct
import threading
@ -35,8 +35,7 @@ class DPV1Master():
self.master.set_timeout(5.0)
except Exception as e:
self.master = None
# hooks.install_hook("modbus_tcp.TcpMaster.after_recv", afterRecv)
# hooks.install_hook("modbus_tcp.TcpMaster.after_send", afterSend)
def writeMultipleRegister(self, slaveId, address, outputValue):

@ -0,0 +1,703 @@
from utils.DBModels.ProtocolModel import TCPSetting, RTUSetting
from .tcpmaster_example import TcpMaster
from .rtumaster_example import RTUMaster
from .tcpslave_example import TCPSlave
from .rtuslave_example import RTUSlave
from modbus_tk import hooks
import threading
import time
class ModbusManager:
"""Modbus 通讯管理器,负责管理所有 Modbus TCP/RTU 主站和从站"""
def __init__(self):
# Modbus 通讯实例
self.modbusTcpMaster = None
self.modbusRtuMaster = None
self.modbusTcpSlave = None
self.modbusRtuSlave = None
# 线程管理
self.modbusReadThreads = {} # 存储各个Modbus读取线程
self.modbusStopEvents = {} # 存储各个Modbus停止事件
self.modbusLocks = {} # 存储各个Modbus的锁
# 变量缓存回调
self.variableValueCache = None
self.cacheLock = None
self.varInfoCache = None
# 报文记录
self.messageHistory = {
'send': [], # 发送的报文
'receive': [] # 接收的报文
}
self.maxMessageCount = 100 # 最大保存报文数量
self.messageLock = threading.Lock()
# 设置报文捕获 hooks
self._setupHooks()
def setVariableCache(self, variableValueCache, cacheLock, varInfoCache):
"""设置变量缓存引用"""
self.variableValueCache = variableValueCache
self.cacheLock = cacheLock
self.varInfoCache = varInfoCache
# ==================== 启动/停止方法 ====================
def startModbusTcpMaster(self):
"""启动 Modbus TCP 主站"""
try:
if self.modbusTcpMaster is not None:
return True
# 从数据库获取TCP设置
tcpSettings = self._getTcpSettings('master')
if not tcpSettings:
return False
# 创建TCP主站实例
# print(tcpSettings['host'], tcpSettings['port'])
self.modbusTcpMaster = TcpMaster(
host=tcpSettings['host'],
port=tcpSettings['port']
)
# 启动读取线程
self._startModbusReadThread('TCP_MASTER', tcpSettings['frequency'])
return True
except Exception as e:
print(f"启动 Modbus TCP 主站失败: {str(e)}")
return False
def stopModbusTcpMaster(self):
"""停止 Modbus TCP 主站"""
try:
if self.modbusTcpMaster is None:
return True
# 停止读取线程
self._stopModbusReadThread('TCP_MASTER')
# 清理主站实例
self.modbusTcpMaster = None
return True
except Exception as e:
return False
def startModbusRtuMaster(self):
"""启动 Modbus RTU 主站"""
try:
if self.modbusRtuMaster is not None:
return True
# 从数据库获取RTU设置
rtuSettings = self._getRtuSettings('master')
if not rtuSettings:
return False
# 创建RTU主站实例
self.modbusRtuMaster = RTUMaster(
port=rtuSettings['port'],
baudrate=rtuSettings['baudrate'],
bytesize=rtuSettings['byteSize'],
parity=rtuSettings['parity'][0], # 取第一个字符
stopbits=rtuSettings['stopbits']
)
# 启动读取线程
self._startModbusReadThread('RTU_MASTER', rtuSettings['frequency'])
return True
except Exception as e:
return False
def stopModbusRtuMaster(self):
"""停止 Modbus RTU 主站"""
try:
if self.modbusRtuMaster is None:
return True
# 停止读取线程
self._stopModbusReadThread('RTU_MASTER')
# 清理主站实例
self.modbusRtuMaster = None
return True
except Exception as e:
return False
def startModbusTcpSlave(self):
"""启动 Modbus TCP 从站"""
try:
if self.modbusTcpSlave is not None:
return True
# 从数据库获取TCP设置
tcpSettings = self._getTcpSettings('slave')
if not tcpSettings:
return False
# 创建TCP从站实例
self.modbusTcpSlave = TCPSlave(
address=tcpSettings['host'],
port=tcpSettings['port']
)
# 添加默认从站ID
self.modbusTcpSlave.addSlave(1)
return True
except Exception as e:
return False
def stopModbusTcpSlave(self):
"""停止 Modbus TCP 从站"""
try:
if self.modbusTcpSlave is None:
return True
# 停止从站服务器
if hasattr(self.modbusTcpSlave, 'server'):
self.modbusTcpSlave.server.stop()
self.modbusTcpSlave = None
return True
except Exception as e:
return False
def startModbusRtuSlave(self):
"""启动 Modbus RTU 从站"""
try:
if self.modbusRtuSlave is not None:
return True
# 从数据库获取RTU设置
rtuSettings = self._getRtuSettings('slave')
if not rtuSettings:
return False
# 创建RTU从站实例
self.modbusRtuSlave = RTUSlave(
port=rtuSettings['port'],
baudrate=rtuSettings['baudrate'],
bytesize=rtuSettings['byteSize'],
parity=rtuSettings['parity'][0], # 取第一个字符
stopbits=rtuSettings['stopbits']
)
# 启动从站服务器
self.modbusRtuSlave.start()
# 添加默认从站ID
self.modbusRtuSlave.addSlave(1)
return True
except Exception as e:
return False
def stopModbusRtuSlave(self):
"""停止 Modbus RTU 从站"""
try:
if self.modbusRtuSlave is None:
return True
# 停止从站服务器
if hasattr(self.modbusRtuSlave, 'server'):
self.modbusRtuSlave.server.stop()
self.modbusRtuSlave = None
return True
except Exception as e:
return False
def stopAllModbus(self):
"""停止所有 Modbus 通讯"""
results = []
results.append(self.stopModbusTcpMaster())
results.append(self.stopModbusRtuMaster())
results.append(self.stopModbusTcpSlave())
results.append(self.stopModbusRtuSlave())
return all(results)
def getModbusStatus(self):
"""获取所有 Modbus 通讯状态"""
return {
'tcpMaster': self.modbusTcpMaster is not None,
'rtuMaster': self.modbusRtuMaster is not None,
'tcpSlave': self.modbusTcpSlave is not None,
'rtuSlave': self.modbusRtuSlave is not None
}
# ==================== 读写方法 ====================
def writeModbusTcpMasterValue(self, info, value):
"""写入TCP主站变量值"""
try:
if self.modbusTcpMaster is None:
return False
slaveId = int(info['slaveID'])
address = int(info['address'])
varType = int(info['varType'])
order = info['order']
return self._writeModbusValue(self.modbusTcpMaster, slaveId, address, varType, value, order)
except Exception as e:
print(f"写入TCP主站变量失败: {str(e)}")
return False
def writeModbusRtuMasterValue(self, info, value):
"""写入RTU主站变量值"""
try:
if self.modbusRtuMaster is None:
return False
slaveId = int(info['slaveID'])
address = int(info['address'])
varType = int(info['varType'])
order = info['order']
return self._writeModbusValue(self.modbusRtuMaster, slaveId, address, varType, value, order)
except Exception as e:
print(f"写入RTU主站变量失败: {str(e)}")
return False
def writeModbusTcpSlaveValue(self, info, value):
"""写入TCP从站变量值"""
try:
if self.modbusTcpSlave is None:
print("Modbus TCP 从站未启动")
return False
slaveId = int(info['slaveID'])
address = int(info['address'])
varType = int(info['varType'])
order = info['order']
return self._writeModbusSlaveValue(self.modbusTcpSlave, slaveId, address, varType, value, order)
except Exception as e:
print(f"写入TCP从站变量失败: {str(e)}")
return False
def writeModbusRtuSlaveValue(self, info, value):
"""写入RTU从站变量值"""
try:
if self.modbusRtuSlave is None:
print("Modbus RTU 从站未启动")
return False
slaveId = int(info['slaveID'])
address = int(info['address'])
varType = int(info['varType'])
order = info['order']
return self._writeModbusSlaveValue(self.modbusRtuSlave, slaveId, address, varType, value, order)
except Exception as e:
print(f"写入RTU从站变量失败: {str(e)}")
return False
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 readModbusTcpSlaveValue(self, info):
"""读取TCP从站变量值"""
try:
if self.modbusTcpSlave is None:
return None
slaveId = int(info['slaveID'])
address = int(info['address'])
varType = int(info['varType'])
order = info['order']
return self._readModbusSlaveValue(self.modbusTcpSlave, slaveId, address, varType, order)
except Exception as e:
print(f"读取TCP从站变量失败: {str(e)}")
return None
def readModbusRtuSlaveValue(self, info):
"""读取RTU从站变量值"""
try:
if self.modbusRtuSlave is None:
return None
slaveId = int(info['slaveID'])
address = int(info['address'])
varType = int(info['varType'])
order = info['order']
return self._readModbusSlaveValue(self.modbusRtuSlave, slaveId, address, varType, order)
except Exception as e:
print(f"读取RTU从站变量失败: {str(e)}")
return None
# ==================== 私有方法 ====================
def _getTcpSettings(self, tcpType):
"""从数据库获取TCP设置"""
try:
setting = TCPSetting.select().where(TCPSetting.tcpType == tcpType).first()
if setting:
return {
'host': setting.host,
'port': setting.port,
'frequency': float(setting.frequency),
'offset': setting.offset
}
else:
# 如果没有设置,创建默认设置
newSetting = TCPSetting()
newSetting.initSetting(tcpType)
return {
'host': newSetting.host,
'port': newSetting.port,
'frequency': float(newSetting.frequency),
'offset': newSetting.offset
}
except Exception as e:
print(f"获取TCP设置失败: {str(e)}")
return None
def _getRtuSettings(self, tcpType):
"""从数据库获取RTU设置"""
try:
setting = RTUSetting.select().where(RTUSetting.tcpType == tcpType).first()
if setting:
return {
'port': setting.port,
'byteSize': setting.byteSize,
'baudrate': setting.baudrate,
'stopbits': setting.stopbits,
'parity': setting.parity,
'frequency': float(setting.frequency),
'offset': setting.offset
}
else:
# 如果没有设置,创建默认设置
newSetting = RTUSetting()
newSetting.initSetting(tcpType)
return {
'port': newSetting.port,
'byteSize': newSetting.byteSize,
'baudrate': newSetting.baudrate,
'stopbits': newSetting.stopbits,
'parity': newSetting.parity,
'frequency': float(newSetting.frequency),
'offset': newSetting.offset
}
except Exception as e:
print(f"获取RTU设置失败: {str(e)}")
return None
def _startModbusReadThread(self, protocolType, frequency):
"""启动Modbus读取线程"""
if protocolType in self.modbusReadThreads:
return
stopEvent = threading.Event()
lock = threading.Lock()
self.modbusStopEvents[protocolType] = stopEvent
self.modbusLocks[protocolType] = lock
readThread = threading.Thread(
target=self._modbusReadWorker,
args=(protocolType, frequency, stopEvent, lock),
daemon=True
)
self.modbusReadThreads[protocolType] = readThread
readThread.start()
def _stopModbusReadThread(self, protocolType):
"""停止Modbus读取线程"""
if protocolType in self.modbusStopEvents:
self.modbusStopEvents[protocolType].set()
if protocolType in self.modbusReadThreads:
self.modbusReadThreads[protocolType].join(timeout=2)
del self.modbusReadThreads[protocolType]
if protocolType in self.modbusStopEvents:
del self.modbusStopEvents[protocolType]
if protocolType in self.modbusLocks:
del self.modbusLocks[protocolType]
def _modbusReadWorker(self, protocolType, frequency, stopEvent, lock):
"""Modbus读取工作线程"""
interval = 1.0 / frequency if frequency > 0 else 1.0
while not stopEvent.is_set():
try:
with lock:
self._readModbusVariables(protocolType)
except Exception as e:
print(f"Modbus读取线程错误 ({protocolType}): {str(e)}")
time.sleep(interval)
def _readModbusVariables(self, protocolType):
"""读取指定协议类型的所有Modbus变量"""
if protocolType == 'TCP_MASTER':
self._readTcpMasterVariables()
elif protocolType == 'RTU_MASTER':
self._readRtuMasterVariables()
def _readTcpMasterVariables(self):
"""读取TCP主站变量"""
if self.modbusTcpMaster is None or self.varInfoCache is None:
return
for varName, varInfo in self.varInfoCache.items():
if varInfo['modelType'] == 'ModbusTcpMasterVar':
try:
info = varInfo['variableData']
slaveId = int(info['slaveID'])
address = int(info['address'])
varType = int(info['varType'])
order = info['order']
value = self._readModbusValue(self.modbusTcpMaster, slaveId, address, varType, order)
if value != 'error' and self.variableValueCache is not None and self.cacheLock is not None:
with self.cacheLock:
self.variableValueCache[varName] = value
except Exception as e:
print(f"读取TCP主站变量失败 {varName}: {str(e)}")
def _readRtuMasterVariables(self):
"""读取RTU主站变量"""
if self.modbusRtuMaster is None or self.varInfoCache is None:
return
for varName, varInfo in self.varInfoCache.items():
if varInfo['modelType'] == 'ModbusRtuMasterVar':
try:
info = varInfo['variableData']
slaveId = int(info['slaveID'])
address = int(info['address'])
varType = int(info['varType'])
order = info['order']
value = self._readModbusValue(self.modbusRtuMaster, slaveId, address, varType, order)
if value != 'error' and self.variableValueCache is not None and self.cacheLock is not None:
with self.cacheLock:
self.variableValueCache[varName] = value
except Exception as e:
print(f"读取RTU主站变量失败 {varName}: {str(e)}")
def _readModbusValue(self, master, slaveId, address, varType, order):
"""通用Modbus值读取方法"""
try:
# varType: 1=线圈, 2=离散输入, 3=输入寄存器, 4=保持寄存器
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)
elif varType == 4: # 保持寄存器
return master.readHoldingRegisters(slaveId, address, 1, order)
else:
return 'error'
except Exception as e:
print(f"读取Modbus值失败: {str(e)}")
return 'error'
def _writeModbusValue(self, master, slaveId, address, varType, value, order):
"""通用Modbus主站值写入方法"""
try:
# varType: 0=线圈, 1=离散输入, 3=输入寄存器, 4=保持寄存器
if varType == 0: # 线圈
result = master.writeSingleCoil(slaveId, address, value)
return result != 'error'
elif varType == 4: # 保持寄存器
result = master.writeSingleRegister(slaveId, address, value, order)
return result != 'error'
else:
print(f"不支持写入的变量类型: {varType}")
return False
except Exception as e:
print(f"写入Modbus主站值失败: {str(e)}")
return False
def _writeModbusSlaveValue(self, slave, slaveId, address, varType, value, order):
"""通用Modbus从站值写入方法"""
try:
# 根据变量类型确定存储区名称
blockName = self._getModbusBlockName(varType, address)
if not blockName:
return False
# 转换地址为存储区内部地
slave.setValue(slaveId, blockName, address, value, order)
return True
except Exception as e:
print(f"写入Modbus从站值失败: {str(e)}")
return False
def _readModbusSlaveValue(self, slave, slaveId, address, varType, order):
"""通用Modbus从站值读取方法"""
try:
# 根据变量类型确定存储区名称
blockName = self._getModbusBlockName(varType, address)
if not blockName:
return None
return slave.readValue(slaveId, blockName, address, order)
except Exception as e:
print(f"读取Modbus从站值失败: {str(e)}")
return None
def _getModbusBlockName(self, varType, address):
"""根据变量类型和地址获取Modbus存储区名称"""
# varType: 0=线圈, 1=离散输入, 3=输入寄存器, 4=保持寄存器
if varType == 0: # 线圈 (0-9999)
return '0'
elif varType == 1: # 离散输入 (10000-19999)
return '1'
elif varType == 3: # 输入寄存器 (30000-39999)
return '3'
elif varType == 4: # 保持寄存器 (40000-49999)
return '4'
else:
print(f"未知的变量类型: {varType}")
return None
# ==================== 报文记录方法 ====================
def _setupHooks(self):
"""设置 modbus_tk hooks 来捕获报文"""
try:
def captureRequest(args):
"""捕获请求报文数据"""
try:
if args and len(args) > 0:
# args[-1] 通常包含报文数据
data = args[-1]
if isinstance(data, (list, tuple)):
hexData = ' '.join([f'{b:02X}' for b in data])
elif isinstance(data, bytes):
hexData = ' '.join([f'{b:02X}' for b in data])
else:
hexData = str(data)
self._addMessage('receive', f"接收请求: {hexData}")
except Exception as e:
pass
def captureResponse(args):
"""捕获响应报文数据"""
try:
if args and len(args) > 0:
# args[-1] 通常包含报文数据
data = args[-1]
if isinstance(data, (list, tuple)):
hexData = ' '.join([f'{b:02X}' for b in data])
elif isinstance(data, bytes):
hexData = ' '.join([f'{b:02X}' for b in data])
else:
hexData = str(data)
self._addMessage('send', f"发送响应: {hexData}")
except Exception as e:
pass
# 使用正确的 hook 名称
hooks.install_hook('modbus.Server.before_handle_request', captureRequest)
hooks.install_hook('modbus.Server.after_handle_request', captureResponse)
except Exception as e:
print(f"设置 hooks 失败: {e}")
# 如果 hooks 设置失败,不影响正常通讯功能
pass
def _addMessage(self, messageType, content):
"""添加报文记录"""
try:
with self.messageLock:
timestamp = time.strftime('%H:%M:%S')
message = f"[{timestamp}] {content}"
if messageType == 'send':
self.messageHistory['send'].append(message)
if len(self.messageHistory['send']) > self.maxMessageCount:
self.messageHistory['send'].pop(0)
elif messageType == 'receive':
self.messageHistory['receive'].append(message)
if len(self.messageHistory['receive']) > self.maxMessageCount:
self.messageHistory['receive'].pop(0)
except Exception as e:
pass
def getMessages(self):
"""获取报文信息"""
try:
with self.messageLock:
return {
'send': self.messageHistory['send'].copy(),
'receive': self.messageHistory['receive'].copy()
}
except Exception as e:
return {'send': [], 'receive': []}
def clearMessages(self):
"""清空报文记录"""
try:
with self.messageLock:
self.messageHistory['send'].clear()
self.messageHistory['receive'].clear()
except Exception as e:
pass

@ -3,7 +3,7 @@ import serial
import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu, hooks
from modbus_tk import modbus_rtu
import sys
from .ByteOrder import *
@ -31,33 +31,93 @@ class RTUMaster():
except Exception as e:
pass
hooks.install_hook("modbus_rtu.RtuMaster.after_recv", afterRecv)
hooks.install_hook("modbus_rtu.RtuMaster.before_send", afterSend)
def writeSingleRegister(self, slaveId, address, outputValue, order = 'ABCD'):
def writeSingleRegister(self, slaveId, address, outputValue, order='ABCD'):
try:
if '.' not in str(outputValue):
# 整数值,使用单寄存器写入
outputValue = int(outputValue)
# print(outputValue)
self.master.execute(slaveId, cst.WRITE_SINGLE_REGISTER, starting_address = address, output_value = outputValue)
self.master.execute(slaveId, cst.WRITE_SINGLE_REGISTER, starting_address=address, output_value=outputValue)
else:
# 浮点数值需要使用多寄存器写入因为浮点数占用2个寄存器
outputValue = float(outputValue)
if order == 'ABCD': # 大端模式
valueByte = None # 初始化变量
if order == 'ABCD': # 大端模式
valueByte = floatToABCD(outputValue)
elif order == 'DCBA': # 小端模式
elif order == 'DCBA': # 小端模式
valueByte = floatToDCBA(outputValue)
elif order == 'BADC':
valueByte = floatToBADC(outputValue)
elif order == 'CDAB':
valueByte = floatToCDAB(outputValue)
self.master.execute(slaveId, cst.WRITE_MULTIPLE_REGISTERS, starting_address = address, output_value=valueByte)
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('error')
print(f'writeSingleRegister error: {e}')
return 'error'
def writeSingleCoil(self, slaveId, address, outputValue):
if outputValue in [0, 1]:
self.master.execute(slaveId, cst.WRITE_SINGLE_COIL, address, output_value = outputValue)
try:
outputValue = int(outputValue)
if outputValue in [0, 1]:
self.master.execute(slaveId, cst.WRITE_SINGLE_COIL, address, output_value=outputValue)
except Exception as e:
return 'error'
def writeMultipleRegisters(self, slaveId, startAddress, outputValues, order='ABCD'):
"""写多个寄存器,支持不同数据类型和字节序"""
try:
processedValues = []
for value in outputValues:
if '.' not in str(value):
# 整数值
processedValues.append(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)
except Exception as e:
return 'error'
def writeMultipleCoils(self, slaveId, startAddress, outputValues):
"""写多个线圈支持布尔值列表或0/1整数列表"""
try:
processedValues = []
for value in outputValues:
if isinstance(value, bool):
processedValues.append(1 if value else 0)
else:
intValue = int(value)
if intValue in [0, 1]:
processedValues.append(intValue)
else:
# 如果值不是0或1转换为布尔值
processedValues.append(1 if intValue else 0)
self.master.execute(slaveId, cst.WRITE_MULTIPLE_COILS, starting_address=startAddress, output_value=processedValues)
except Exception as e:
return 'error'
def readHoldingRegisters(self, slaveId, startAddress, varNums, order = 'ABCD'):
@ -96,9 +156,10 @@ class RTUMaster():
except Exception as e:
return 'error'
def readCoils(self, slaveId, startAddress, varNums, order = 'ABCD'):
def readCoils(self, slaveId, startAddress, varNums, order='ABCD'):
try:
value = self.master.execute(slaveId, cst.READ_COILS, startAddress, varNums)
# 如果只读取一个线圈,返回单个值;否则返回列表
return value[0]
except Exception as e:
return 'error'
@ -106,6 +167,7 @@ class RTUMaster():
def readInputCoils(self, slaveId, startAddress, varNums):
try:
value = self.master.execute(slaveId, cst.READ_DISCRETE_INPUTS, startAddress, varNums)
# 如果只读取一个线圈,返回单个值;否则返回列表
return value[0]
except Exception as e:
return 'error'
@ -133,7 +195,7 @@ class RTUMaster():
# red = master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 9) # 这里可以修改需要读取的功能码
# print(red)
# alarm = "正常"
# return list(red), alarm
# return list(red), alarm#
# except Exception as exc:
# print(str(exc))

@ -18,8 +18,8 @@ class RTUSlave():
self.server = modbus_rtu.RtuServer(serial.Serial(port = port, baudrate = baudrate, bytesize = bytesize, parity = parity, stopbits = stopbits, xonxoff = xonxoff))
except Exception as e:
return
hooks.install_hook('modbus.Server.before_handle_request', afterRecv)
hooks.install_hook("modbus.Server.after_handle_request", afterSend)
# hooks.install_hook('modbus.Server.before_handle_request', afterRecv)
# hooks.install_hook("modbus.Server.after_handle_request", afterSend)
# self.server.set_timeout(5.0)
# self.server.set_verbose(True)
@ -59,6 +59,8 @@ class RTUSlave():
valueByte = floatToBADC(value)
elif order == 'CDAB':
valueByte = floatToCDAB(value)
else:
valueByte = floatToABCD(value)
slave.set_values(name, address, valueByte)
else:
@ -80,6 +82,8 @@ class RTUSlave():
value = BADCToFloat(value)
elif order == 'CDAB':
value = CDABToFloat(value)
else:
value = ABCDToFloat(value)
return value
except Exception as e:
print(e)

@ -1,7 +1,7 @@
import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_tcp, hooks
from modbus_tk import modbus_tcp
import logging
import struct
from .SetMessage import *
@ -9,53 +9,96 @@ from .ByteOrder import *
class TcpMaster():
def __init__(self, host = None, port = None):
def __init__(self, host=None, port=None):
try:
self.master = modbus_tcp.TcpMaster(host = host, port = port)
self.master = modbus_tcp.TcpMaster(host=host, port=port)
self.master.set_timeout(5.0)
except Exception as e:
pass
hooks.install_hook("modbus_tcp.TcpMaster.after_recv", afterRecv)
hooks.install_hook("modbus_tcp.TcpMaster.before_send", afterSend)
def writeSingleRegister(self, slaveId, address, outputValue, order = 'ABCD'):
def writeSingleRegister(self, slaveId, address, outputValue, order='ABCD'):
try:
if '.' not in str(outputValue):
# 整数值,使用单寄存器写入
outputValue = int(outputValue)
print(outputValue)
self.master.execute(slaveId, cst.WRITE_SINGLE_REGISTER, starting_address = address, output_value = outputValue)
self.master.execute(slaveId, cst.WRITE_SINGLE_REGISTER, starting_address=address, output_value=outputValue)
else:
# 浮点数值需要使用多寄存器写入因为浮点数占用2个寄存器
outputValue = float(outputValue)
if order == 'ABCD': # 大端模式
if order == 'ABCD': # 大端模式
valueByte = floatToABCD(outputValue)
elif order == 'DCBA': # 小端模式
elif order == 'DCBA': # 小端模式
valueByte = floatToDCBA(outputValue)
elif order == 'BADC':
valueByte = floatToBADC(outputValue)
elif order == 'CDAB':
valueByte = floatToCDAB(outputValue)
self.master.execute(slaveId, cst.WRITE_MULTIPLE_REGISTERS, starting_address = address, output_value=valueByte)
else:
valueByte = floatToABCD(outputValue)
# 浮点数必须使用 WRITE_MULTIPLE_REGISTERS因为需要写入2个寄存器
self.master.execute(slaveId, cst.WRITE_MULTIPLE_REGISTERS, starting_address=address, output_value=valueByte)
except Exception as e:
return 'error'
def writeMultipleRegisters(self, slaveId, startAddress, outputValues, order='ABCD'):
"""写多个寄存器,支持不同数据类型和字节序"""
try:
processedValues = []
for value in outputValues:
if '.' not in str(value):
processedValues.append(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)
except Exception as e:
return 'error'
def writeSingleCoil(self, slaveId, address, outputValue):
try:
outputValue = int(outputValue)
if outputValue in [0, 1]:
self.master.execute(slaveId, cst.WRITE_SINGLE_COIL, address, output_value = outputValue)
self.master.execute(slaveId, cst.WRITE_SINGLE_COIL, address, output_value=outputValue)
except Exception as e:
return 'error'
def readHoldingRegisters(self, slaveId, startAddress, varNums, order = 'ABCD'):
print(order)
def writeMultipleCoils(self, slaveId, startAddress, outputValues):
"""写多个线圈支持布尔值列表或0/1整数列表"""
try:
processedValues = []
for value in outputValues:
if isinstance(value, bool):
processedValues.append(1 if value else 0)
else:
intValue = int(value)
if intValue in [0, 1]:
processedValues.append(intValue)
else:
processedValues.append(1 if intValue else 0)
self.master.execute(slaveId, cst.WRITE_MULTIPLE_COILS, starting_address=startAddress, output_value=processedValues)
except Exception as e:
return 'error'
def readHoldingRegisters(self, slaveId, startAddress, varNums, order='ABCD'):
try:
if order == 'int':
valueByte = self.master.execute(slaveId, cst.READ_HOLDING_REGISTERS, startAddress, varNums)[0]
else:
value = self.master.execute(slaveId, cst.READ_HOLDING_REGISTERS, startAddress, 2)
if order == 'ABCD': # 大端模式
if order == 'ABCD':
valueByte = ABCDToFloat(value)
elif order == 'DCBA': # 小端模式
elif order == 'DCBA':
valueByte = DCBAToFloat(value)
elif order == 'BADC':
valueByte = BADCToFloat(value)
@ -65,15 +108,15 @@ class TcpMaster():
except:
return 'error'
def readInputRegisters(self, slaveId, startAddress, varNums, order = 'ABCD'):
def readInputRegisters(self, slaveId, startAddress, varNums, order='ABCD'):
try:
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)
if order == 'ABCD': # 大端模式
if order == 'ABCD':
valueByte = ABCDToFloat(value)
elif order == 'DCBA': # 小端模式
elif order == 'DCBA':
valueByte = DCBAToFloat(value)
elif order == 'BADC':
valueByte = BADCToFloat(value)
@ -83,18 +126,24 @@ class TcpMaster():
except Exception as e:
return 'error'
def readCoils(self, slaveId, startAddress, varNums, order = 'ABCD'):
def readCoils(self, slaveId, startAddress, varNums, order='ABCD'):
try:
value = self.master.execute(slaveId, cst.READ_COILS, startAddress, varNums)
return value[0]
if varNums == 1:
return value[0] if value else 0
else:
return value
except Exception as e:
return 'error'
def readInputCoils(self, slaveId, startAddress, varNums):
print(slaveId, startAddress, varNums)
try:
value = self.master.execute(slaveId, cst.READ_DISCRETE_INPUTS, startAddress, varNums)
return value[0]
except:
if varNums == 1:
return value[0] if value else 0
else:
return value
except Exception as e:
return 'error'

@ -12,13 +12,15 @@ from .SetMessage import *
class TCPSlave():
def __init__(self, address = '127.0.0.1', port = 502):
try:
self.server = modbus_tcp.TcpServer(address = address, port = port)
self.server = modbus_tcp.TcpServer(address=address, port=port)
self.server.start()
print(f"TCP Slave started on {address}:{port}")
except Exception as e:
pass
print(f"Failed to start TCP Slave on {address}:{port}: {e}")
raise e
hooks.install_hook('modbus.Server.before_handle_request', afterRecv)
hooks.install_hook("modbus.Server.after_handle_request", afterSend)
# hooks.install_hook('modbus.Server.before_handle_request', afterRecv)
# hooks.install_hook("modbus.Server.after_handle_request", afterSend)
# 创建从站
# 添加存储区
@ -29,36 +31,52 @@ class TCPSlave():
# ANALOG_INPUTS = 4
def addSlave(self, slaveId):
try:
self.server.add_slave(slaveId)
slave = self.server.get_slave(slaveId)
slave.add_block('0', cst.COILS, 0, 9999) # 从0开始创建10000个地址
slave.add_block('1', cst.DISCRETE_INPUTS, 10000,19999)
slave.add_block('3', cst.ANALOG_INPUTS, 30000, 39999)
slave.add_block('4', cst.HOLDING_REGISTERS, 40000, 49999)
# 添加存储区 - 使用正确的地址范围
slave.add_block('0', cst.COILS, 0, 9999) # 线圈 0-9999
slave.add_block('1', cst.DISCRETE_INPUTS, 10000, 19999) # 离散输入 10000-19999
slave.add_block('3', cst.ANALOG_INPUTS, 30000, 39999) # 输入寄存器 30000-39999
slave.add_block('4', cst.HOLDING_REGISTERS, 40000, 49999) # 保持寄存器 40000-49999
print(f"Added slave {slaveId} with storage blocks")
return True
except Exception as e:
pass
print(f"Failed to add slave {slaveId}: {e}")
return False
def setValue(self, slaveId, name, address, value, order = 'ABCD'):
def setValue(self, slaveId, name, address, value, order='ABCD'):
try:
slave = self.server.get_slave(slaveId)
# print(value)
if '.' in str(value):
if order == 'ABCD': # 大端模式
valueByte = floatToABCD(value)
elif order == 'DCBA': # 小端模式
valueByte = floatToDCBA(value)
# 浮点数处理
floatValue = float(value)
if order == 'ABCD': # 大端模式
valueByte = floatToABCD(floatValue)
elif order == 'DCBA': # 小端模式
valueByte = floatToDCBA(floatValue)
elif order == 'BADC':
valueByte = floatToBADC(value)
valueByte = floatToBADC(floatValue)
elif order == 'CDAB':
valueByte = floatToCDAB(value)
valueByte = floatToCDAB(floatValue)
else:
valueByte = floatToABCD(floatValue)
slave.set_values(name, address, valueByte)
else:
slave.set_values(name, address, value)
# 整数处理
intValue = int(value)
slave.set_values(name, address, intValue)
return True
except Exception as e:
pass
print(f"TCP Slave setValue error: {e}")
print(f"Error details - slaveId: {slaveId}, name: {name}, address: {address}, value: {value}")
return False
def readValue(self, slaveId, name, address, order = 'int'):
try:

@ -7,6 +7,7 @@ from protocol.TCP.TCPVarManage import *
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 utils import Globals
import threading
import time
@ -31,13 +32,20 @@ class ProtocolManage(object):
self.varInfoCache = {} # 保持驼峰命名
self.historyDBManage = Globals.getValue('historyDBManage')
self.variableValueCache = {} # {varName: value}
# Modbus 管理器
self.modbusManager = ModbusManager()
self.modbusManager.setVariableCache(self.variableValueCache, None, self.varInfoCache)
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)
self.readThread.start()
def clearVarCache(self):
"""清空变量信息缓存"""
self.varInfoCache.clear()
@ -68,7 +76,6 @@ class ProtocolManage(object):
:return: 包含变量信息和模型类型的字典如果未找到返回None
"""
if variableName in self.varInfoCache:
# print(111)
return self.varInfoCache[variableName]
for modelClass in self.MODEL_CLASSES:
varInstance = modelClass.getByName(variableName)
@ -101,25 +108,19 @@ class ProtocolManage(object):
if self.RpcServer:
return
self.RpcServer = RpcServer(rabbitmqHost)
def addClient(self, clientName):
if self.RpcServer:
self.RpcServer.addClient(clientName = clientName)
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):
def writeVariableValue(self, variableName, value, trigger=None, timeoutMS=2000):
"""
根据变量名写入变量值根据变量类型进行不同处理不保存到数据库
@ -130,40 +131,42 @@ class ProtocolManage(object):
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
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协议条件判断
# 拆分为四个独立的Modbus协议条件判断
if modelType == 'ModbusTcpMasterVar':
# 仅设置值,不保存到数据库
pass
res = self.modbusManager.writeModbusTcpMasterValue(info, value)
# print(res)
if res == 'error':
return
elif modelType == 'ModbusTcpSlaveVar':
# 仅设置值,不保存到数据库
pass
res = self.modbusManager.writeModbusTcpSlaveValue(info, value)
if res == 'error':
return
elif modelType == 'ModbusRtuMasterVar':
# 仅设置值,不保存到数据库
pass
res = self.modbusManager.writeModbusRtuMasterValue(info, value)
if res == 'error':
return
elif modelType == 'ModbusRtuSlaveVar':
# 仅设置值,不保存到数据库
pass
res = self.modbusManager.writeModbusRtuSlaveValue(info, value)
if res == 'error':
return
# HART协议变量处理
elif modelType == 'HartVar':
# 仅设置值,不保存到数据库
pass
# 温度/RTD变量处理
@ -173,21 +176,18 @@ class ProtocolManage(object):
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调整到括号外
value = temToMv(varType, value + compensationVar)
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':
@ -195,17 +195,14 @@ class ProtocolManage(object):
varType = info['varType']
varModel = info['varModel']
model = self.getModelType(varModel) if self.getModelType(varModel) else localModel
if info['varType'] in ['AI','AO']:
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'])
@ -224,12 +221,9 @@ class ProtocolManage(object):
time.sleep(interval)
def getAllVariableNames(self):
# 直接从缓存获取所有变量名,降低与数据库模型的耦合
return list(self.varInfoCache.keys())
def _readVariableValueOriginal(self, variableName):
# 完全保留原有读取逻辑
# print(12)
varInfo = self.lookupVariable(variableName)
value = None
if not varInfo:
@ -237,7 +231,6 @@ class ProtocolManage(object):
existsVar, clientNames = self.RpcServer.existsVar(variableName)
if existsVar:
value = float(self.RpcServer.getVarValue(clientNames[0], variableName)['value'])
# return value
else:
return None
return None
@ -246,13 +239,13 @@ class ProtocolManage(object):
try:
# 拆分为独立的协议条件判断
if modelType == 'ModbusTcpMasterVar':
pass
value = self.modbusManager.readModbusTcpMasterValue(info)
elif modelType == 'ModbusTcpSlaveVar':
pass
value = self.modbusManager.readModbusTcpSlaveValue(info)
elif modelType == 'ModbusRtuMasterVar':
pass
value = self.modbusManager.readModbusRtuMasterValue(info)
elif modelType == 'ModbusRtuSlaveVar':
pass
value = self.modbusManager.readModbusRtuSlaveValue(info)
elif modelType == 'HartVar':
pass
elif modelType == 'TcRtdVar':
@ -265,34 +258,25 @@ class ProtocolManage(object):
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']:
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 value is not None and value != 'error':
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
@ -301,57 +285,44 @@ class ProtocolManage(object):
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()
# 关闭所有Modbus通讯
self.modbusManager.stopAllModbus()
# 关闭后台读取线程
if hasattr(self, 'readThreadStop') and hasattr(self, 'readThread'):
self.readThreadStop.set()
self.readThread.join(timeout=1)
def getRealAO(self, value,highValue, lowValue):
def getRealAO(self, value, highValue, lowValue):
if highValue:
lowValue = float(lowValue)
highValue = float(highValue)
return (16 * (value - lowValue) + 4 * (highValue-lowValue))/(1000 * (highValue - lowValue))
return (16 * (value - lowValue) + 4 * (highValue - lowValue)) / (1000 * (highValue - lowValue))
else:
return value/1000
return value / 1000
def getRealAI(self, mA, highValue, lowValue):
"""
将毫安值转换为实际工程值getRealAO的反向计算
:param mA: 毫安值
:param highValue: 工程值上限
:param lowValue: 工程值下限
:return: 实际工程值
"""
"""将毫安值转换为实际工程值getRealAO的反向计算"""
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避免中断流程
return 0.0
def getModelType(self, varModel):
if varModel == '本地值':
return localModel
@ -364,4 +335,52 @@ class ProtocolManage(object):
if self.RpcServer:
self.RpcServer.removeClient(clientName)
# ==================== Modbus 通讯管理方法(委托给 ModbusManager ====================
def startModbusTcpMaster(self):
"""启动 Modbus TCP 主站"""
return self.modbusManager.startModbusTcpMaster()
def stopModbusTcpMaster(self):
"""停止 Modbus TCP 主站"""
return self.modbusManager.stopModbusTcpMaster()
def startModbusRtuMaster(self):
"""启动 Modbus RTU 主站"""
return self.modbusManager.startModbusRtuMaster()
def stopModbusRtuMaster(self):
"""停止 Modbus RTU 主站"""
return self.modbusManager.stopModbusRtuMaster()
def startModbusTcpSlave(self):
"""启动 Modbus TCP 从站"""
return self.modbusManager.startModbusTcpSlave()
def stopModbusTcpSlave(self):
"""停止 Modbus TCP 从站"""
return self.modbusManager.stopModbusTcpSlave()
def startModbusRtuSlave(self):
"""启动 Modbus RTU 从站"""
return self.modbusManager.startModbusRtuSlave()
def stopModbusRtuSlave(self):
"""停止 Modbus RTU 从站"""
return self.modbusManager.stopModbusRtuSlave()
def stopAllModbus(self):
"""停止所有 Modbus 通讯"""
return self.modbusManager.stopAllModbus()
def getModbusStatus(self):
"""获取所有 Modbus 通讯状态"""
return self.modbusManager.getModbusStatus()
def getModbusMessages(self):
"""获取 Modbus 报文信息"""
return self.modbusManager.getMessages()
def clearModbusMessages(self):
"""清空 Modbus 报文记录"""
self.modbusManager.clearMessages()

@ -7,9 +7,9 @@ class InitParameterDB():
self.writeUnitParameter()
def writeParameter(self) -> None:
blockNames = pd.ExcelFile('static/PA块信息表.xlsx').sheet_names
blockNames = pd.ExcelFile('Static/PA块信息表.xlsx').sheet_names
for blockName in blockNames:
parameters = pd.read_excel('static/PA块信息表.xlsx', sheet_name = str(blockName))
parameters = pd.read_excel('Static/PA块信息表.xlsx', sheet_name = str(blockName))
for index, row in parameters.iterrows():
parameter = row.values
@ -19,7 +19,7 @@ class InitParameterDB():
saveType = parameter[4], dataSize = parameter[5], accessType = parameter[6], transferType = parameter[7], description = parameter[8])
def writeUnitParameter(self):
parameters = pd.read_excel('static/UnitTable.xlsx', sheet_name = 'UnitTable')
parameters = pd.read_excel('Static/UnitTable.xlsx', sheet_name = 'UnitTable')
for index, row in parameters.iterrows():
parameter = row.values
clsblockName = UnitTable()

Loading…
Cancel
Save