diff --git a/PyNetAssistant/--PyNet.ini b/PyNetAssistant/--PyNet.ini new file mode 100644 index 0000000..5a24541 --- /dev/null +++ b/PyNetAssistant/--PyNet.ini @@ -0,0 +1,118 @@ +[UI_config] +port = 9000 +hex_send = 0 +hex_receive = 0 +add_date = 0 +cr_lf = 0 +auto_sav_log = 1 +modbus_csv = 0 + +[DisHex_config] +row00 = |||| + +[Modbus_config] +funcode = F4 +position = 5 + +[Quick_config] +log_time = 1 +button00 = | +button01 = | +button02 = | +button03 = | +button04 = | +button05 = | +button06 = | +button07 = | +button08 = | +button09 = | +button10 = | +button11 = | +button12 = | +button13 = | +button14 = | +button15 = | +button16 = | +button17 = | +button18 = | +button19 = | +button20 = | +button21 = | +button22 = | +button23 = | +button24 = | +button25 = | +button26 = | +button27 = | +button28 = | +button29 = | +button30 = | +button31 = | +button32 = | +button33 = | +button34 = | +button35 = | +button36 = | +button37 = | +button38 = | +button39 = | +button40 = | +button41 = | +button42 = | +button43 = | +button44 = | +button45 = | +button46 = | +button47 = | +button48 = | +button49 = | +button50 = | +button51 = | +button52 = | +button53 = | +button54 = | +button55 = | +button56 = | +button57 = | +button58 = | +button59 = | +button60 = | +button61 = | +button62 = | +button63 = | +button64 = | +button65 = | +button66 = | +button67 = | +button68 = | +button69 = | +button70 = | +button71 = | +button72 = | +button73 = | +button74 = | +button75 = | +button76 = | +button77 = | +button78 = | +button79 = | +button80 = | +button81 = | +button82 = | +button83 = | +button84 = | +button85 = | +button86 = | +button87 = | +button88 = | +button89 = | +button90 = | +button91 = | +button92 = | +button93 = | +button94 = | +button95 = | +button96 = | +button97 = | +button98 = | + diff --git a/PyNetAssistant/.idea/.gitignore b/PyNetAssistant/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/PyNetAssistant/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/PyNetAssistant/.idea/PyNetAssistant.iml b/PyNetAssistant/.idea/PyNetAssistant.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/PyNetAssistant/.idea/PyNetAssistant.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/PyNetAssistant/.idea/inspectionProfiles/Project_Default.xml b/PyNetAssistant/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..3dce9c6 --- /dev/null +++ b/PyNetAssistant/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/PyNetAssistant/.idea/inspectionProfiles/profiles_settings.xml b/PyNetAssistant/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/PyNetAssistant/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/PyNetAssistant/.idea/misc.xml b/PyNetAssistant/.idea/misc.xml new file mode 100644 index 0000000..a6218fe --- /dev/null +++ b/PyNetAssistant/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/PyNetAssistant/.idea/modules.xml b/PyNetAssistant/.idea/modules.xml new file mode 100644 index 0000000..17c958b --- /dev/null +++ b/PyNetAssistant/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/PyNetAssistant/.idea/vcs.xml b/PyNetAssistant/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/PyNetAssistant/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PyNetAssistant/NetDataSplit.py b/PyNetAssistant/NetDataSplit.py new file mode 100644 index 0000000..80a1a81 --- /dev/null +++ b/PyNetAssistant/NetDataSplit.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue May 28 15:40:48 2024 + +@author: WANGXIBAO +""" +# -*- coding: utf-8 -*- + + +import csv +import os +import re +import time + + +class GetDataTF(): # 读取费加罗或者自定义数据 + def __init__(self, parent=None): + super().__init__() + self.indOfReturn = 0 + self.TIME_FORMAT = "%Y-%m-%d %H:%M:%S" + self.headStr = "" + self.rowTitle = [] + self.csv_buffer = [] + + def SetConfig(self, config_in): + self.regex = re.compile(config_in[0]) # 正则表达 + self.headStr = config_in[1] + self.rowTitleStr = config_in[2] + # print(self.rowTitleStr) + self.rowTitle = self.rowTitleStr.split(',') + + def Transdata(self, data): + if data[:2] == self.headStr: + + self.data2csv = self.regex.findall(data) + + returnData = float(self.data2csv[self.indOfReturn]) + print("returnData", returnData) + return returnData + else: + return "noNum" + + def SaveCsv(self, filenameCsv, num): + # 打开一个文件用于写入,如果文件不存在则创建 + # 增加num 写入文件间隔 + if os.path.isfile(filenameCsv) == 0: + # 文件为空,需要写入表头 + with open(filenameCsv, mode='w', newline='') as file: + writer = csv.writer(file) + writer.writerow(self.rowTitle) + else: + timeCrvt = time.strftime(self.TIME_FORMAT, time.localtime()) + self.data2csv.insert(0, timeCrvt) + print(self.data2csv) + self.csv_buffer.append(self.data2csv) + if len(self.csv_buffer) >= num: + with open(filenameCsv, mode='a', newline='') as file: + # 创建一个写入器对象 + writer = csv.writer(file) + # 写入数据行 + writer.writerows(self.csv_buffer) + self.csv_buffer.clear() + + def IndOfReturn(self, ind): + self.indOfReturn = ind + +class HexData2Num(): + def __init__(self): + super().__init__() + + + diff --git a/PyNetAssistant/PyNet.exe b/PyNetAssistant/PyNet.exe index fa3a9cd..9195788 100644 Binary files a/PyNetAssistant/PyNet.exe and b/PyNetAssistant/PyNet.exe differ diff --git a/PyNetAssistant/PyNet.ini b/PyNetAssistant/PyNet.ini index 2a09b3b..8cacb7a 100644 --- a/PyNetAssistant/PyNet.ini +++ b/PyNetAssistant/PyNet.ini @@ -1,45 +1,159 @@ +[UI_config] +port = 9000 +hex_send = 0 +hex_receive = 0 +add_date = 0 +cr_lf = 2 +auto_sav_log = 2 +modbus_csv = 0 + +[Modbus_config] +funcode = F4 +position = 5 + +[DisHex_config] +row00 = 浓度|0|4|1|2 +row01 = 测试|1|3|1|2 +row02 = ||||0 +row03 = ||||0 +row04 = ||||0 +row05 = ||||0 +row06 = ||||0 +row07 = ||||0 +row08 = ||||0 +row09 = ||||0 +row10 = ||||0 +row11 = ||||0 +row12 = ||||0 +row13 = ||||0 +row14 = ||||0 +row15 = ||||0 +row16 = ||||0 +row17 = ||||0 +row18 = ||||0 +row19 = ||||0 +row20 = ||||0 +row21 = ||||0 +row22 = ||||0 +row23 = ||||0 +row24 = ||||0 +row25 = ||||0 +row26 = ||||0 +row27 = ||||0 +row28 = ||||0 +row29 = ||||0 +row30 = ||||0 +row31 = ||||0 +row32 = ||||0 +row33 = ||||0 +row34 = ||||0 +row35 = ||||0 +row36 = ||||0 +row37 = ||||0 +row38 = ||||0 +row39 = ||||0 +row40 = ||||0 +row41 = ||||0 +row42 = ||||0 +row43 = ||||0 +row44 = ||||0 +row45 = ||||0 +row46 = ||||0 +row47 = ||||0 +row48 = ||||0 +row49 = ||||0 +row50 = ||||0 +row51 = ||||0 +row52 = ||||0 +row53 = ||||0 +row54 = ||||0 +row55 = ||||0 +row56 = ||||0 +row57 = ||||0 +row58 = ||||0 +row59 = ||||0 +row60 = ||||0 +row61 = ||||0 +row62 = ||||0 +row63 = ||||0 +row64 = ||||0 +row65 = ||||0 +row66 = ||||0 +row67 = ||||0 +row68 = ||||0 +row69 = ||||0 +row70 = ||||0 +row71 = ||||0 +row72 = ||||0 +row73 = ||||0 +row74 = ||||0 +row75 = ||||0 +row76 = ||||0 +row77 = ||||0 +row78 = ||||0 +row79 = ||||0 +row80 = ||||0 +row81 = ||||0 +row82 = ||||0 +row83 = ||||0 +row84 = ||||0 +row85 = ||||0 +row86 = ||||0 +row87 = ||||0 +row88 = ||||0 +row89 = ||||0 +row90 = ||||0 +row91 = ||||0 +row92 = ||||0 +row93 = ||||0 +row94 = ||||0 +row95 = ||||0 +row96 = ||||0 +row97 = ||||0 +row98 = ||||0 + [Quick_config] -log_time = 1 -button00 = read 0|序列号 -button01 = read 1|激光温度 -button02 = read 2|K*1000 -button03 = read 3|B*1000 -button04 = read 4|电阻阻值 -button05 = read 5|电阻抽头 -button06 = read 6|输出温度 -button07 = read 7|输出激光 -button08 = read 8|输出状态 -button09 = read 9|激光温补 -button10 = read 10|噪声长度 -button11 = read 11|扫描长度 +log_time = 10 +button00 = | +button01 = | +button02 = | +button03 = read| +button04 = | +button05 = | +button06 = | +button07 = | +button08 = | +button09 = | +button10 = | +button11 = | button12 = | -button13 = read 13|气温校准 -button14 = read 14|滑动开关 -button15 = read 15|滑动标准差 -button16 = read 16|浓度温补 -button17 = read all|读取全部 +button13 = | +button14 = | +button15 = | +button16 = | +button17 = | button18 = | button19 = | -button20 = write 0,2024100103|序列号 -button21 = write 1,65000|激光温度 -button22 = write 2,1000|K*1000 -button23 = write 3,0|B*1000 -button24 = write 4,0|电阻阻值 -button25 = write 5,30|电阻抽头 -button26 = write 6,0|输出温度 -button27 = write 7,0|输出激光 -button28 = write 8,1|输出状态 -button29 = write 9,0|激光温补 -button30 = write 10,100|噪声长度 -button31 = write 11,600|扫描长度 -button32 = 22|eee -button33 = write 13,30500|气温校准 -button34 = write 14,1|滑动开关 -button35 = write 15,10|滑动标准差 -button36 = write 16,1|浓度温补 +button20 = | +button21 = | +button22 = | +button23 = | +button24 = | +button25 = | +button26 = | +button27 = | +button28 = | +button29 = | +button30 = | +button31 = | +button32 = | +button33 = | +button34 = | +button35 = | +button36 = | button37 = | button38 = | -button39 = 01 04 01 2D 00 01 A0 3F| +button39 = | button40 = | button41 = | button42 = | diff --git a/PyNetAssistant/PyNet.py b/PyNetAssistant/PyNet.py index 2be9ab4..c0e2611 100644 --- a/PyNetAssistant/PyNet.py +++ b/PyNetAssistant/PyNet.py @@ -4,70 +4,79 @@ Created on Sun Sep 29 09:01:22 2024 @author: WANGXIBAO """ -import sys,os -import re,socket - -import time,datetime - -from PyQt5 import QtWidgets -from PyQt5.QtWidgets import QMessageBox ,QFileDialog,QInputDialog -from PyQt5.QtCore import QTimer -from PyNetUi import Ui_UartAssistant +import datetime +import os +import re +import socket +import sys +import time from configparser import ConfigParser -class Pyqt5Net(QtWidgets.QWidget,Ui_UartAssistant): +from PyQt5 import QtWidgets +from PyQt5.QtCore import QTimer,Qt +from PyQt5.QtWidgets import QMessageBox, QFileDialog, QInputDialog, QTableWidgetItem + +from PyNetUi import Ui_UartAssistant + + +class Pyqt5Net(QtWidgets.QWidget, Ui_UartAssistant): # %%初始化程序 def __init__(self): - super(Pyqt5Net, self).__init__() + super(Pyqt5Net, self).__init__() self.setupUi(self) self.quick_num = 99 - self.init() #信号和槽 - self.IniPath = "PyNet.ini" + self.init() #信号和槽 + self.IniPath = "PyNet.ini" self.log_time = 10 - self.CheckCfgIniData() #更改按钮的文字 + self.funcode = "F4" + self.position = 5 + self.CheckCfgIniData() #更改按钮的文字 self.log_count = 0 - self.log_buffer = {} #定义成一个字典,键--文件名,值--对于收到的字符串列表 - - # 设置Logo和标题 + self.log_buffer = {} #定义成一个字典,键--文件名,值--对于收到的字符串列表 + + # 设置Logo和标题 #self.setWindowIcon(QIcon('favicon.ico')) self.setWindowTitle("网口调试助手") # 设置禁止拉伸窗口大小 #self.setFixedSize(self.width(), self.height()) - + # 发送数据和接收数据数目置零 self.data_num_sended = 0 self.lineEditSendNum.setText(str(self.data_num_sended)) self.data_num_received = 0 self.lineEditReceiveNum.setText(str(self.data_num_received)) - + # 串口关闭按钮使能关闭 self.pushButton_closeNet.setEnabled(False) - + # 发送框、文本框清除 self.textEditReceive.setText("") self.textEditSend.setText("") - + self.get_all_local_ips() - + # 定时器接收数据 - self.timer = QTimer() - self.timer.timeout.connect(self.data_receive) + #self.timer = QTimer() + self.timer: QTimer = QTimer() + #self.timer.timeout.connect(self.data_receive) + timeout_signal = self.timer.timeout + timeout_signal.connect(self.data_receive) + #加载快捷指令 self.widget_6.hide() #加载快捷指令的按键值 - #建立信号与槽 def init(self): self.pushButton_openNet.clicked.connect(self.open_net) self.pushButton_closeNet.clicked.connect(self.close_net) - self.pushButtonSend.clicked.connect(lambda:self.data_send(text_quick= None)) + self.pushButtonSend.clicked.connect(lambda: self.data_send(text_quick=None)) # 清除发送按钮 - self.pushButtonClearSend.clicked.connect(self.send_data_clear) + self.pushButtonClearSend.clicked.connect(self.send_data_clear) # 清除接收按钮 self.pushButtonClearReceive.clicked.connect(self.receive_data_clear) - + # 定时发送数据 self.timer_send = QTimer() self.timer_send.timeout.connect(self.data_send) @@ -82,7 +91,7 @@ class Pyqt5Net(QtWidgets.QWidget,Ui_UartAssistant): horizontalLayoutName = f"horizontalLayoutQuick_{index_str}" horizontalLayout = QtWidgets.QHBoxLayout() horizontalLayout.setObjectName(horizontalLayoutName) - + # 创建 QLineEdit 并设置动态属性 lineEditName = f"lineEditQuick_{index_str}" setattr(self, lineEditName, QtWidgets.QLineEdit(self.layoutWidget1)) @@ -94,41 +103,40 @@ class Pyqt5Net(QtWidgets.QWidget,Ui_UartAssistant): getattr(self, buttonName).setObjectName(buttonName) horizontalLayout.addWidget(getattr(self, buttonName)) self.verticalLayout_8.addLayout(horizontalLayout) - # 连接按钮点击事件到槽函数 + # 连接按钮点击事件到槽函数 button = getattr(self, buttonName) if button: button.clicked.connect(lambda checked, idx=i: self.onButtonClick(idx)) - self.double_click_timers = {} # 存储双击定时器 + # 建立表格解析并显示hex + self.tableWidget.setRowCount(self.quick_num) + for i in range(self.quick_num): # 从0到20 + item = QtWidgets.QTableWidgetItem() + item.setCheckState(Qt.Unchecked) + self.tableWidget.setItem(i, 0, item) + self.double_click_timers = {} # 存储双击定时器 + #%% 重写关闭按钮 def closeEvent(self, event): - - #关闭界面前保存快捷区域的命令和名称 - for i in range(self.quick_num): # 假设有20个按钮 - index_str = f"{i:02}" # 确保编号为两位数字形式 - lineEditName = f"lineEditQuick_{index_str}" - buttonName = f"pushButtonQuick_{index_str}" # 格式化按钮名称,确保两位数 - button_name = f"button{index_str}" - set_text = getattr(self,lineEditName).text()+ "|" + getattr(self,buttonName).text() - self.SetCfgIniData(button_name, set_text) + + self.SavConfig() self.close_net() # 调用父类的关闭事件处理函数 super().closeEvent(event) - #加载本地网络地址 def get_all_local_ips(self): ip_addresses = [] for interface in socket.getaddrinfo(socket.gethostname(), None): address = interface[4][0] if ':' not in address: # IPv6地址包含冒号 - ip_addresses.append(address) + ip_addresses.append(address) print(ip_addresses) for ip in ip_addresses: - self.comboBox_localAddr.insertItem(0,ip) + self.comboBox_localAddr.insertItem(0, ip) self.comboBox_localAddr.setCurrentIndex(0) # 打开网络连接 @@ -136,7 +144,7 @@ class Pyqt5Net(QtWidgets.QWidget,Ui_UartAssistant): IP = self.comboBox_localAddr.currentText() port = self.lineEdit_port.text() udp_addr = (IP, int(port)) - self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #创建接收空socket + self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #创建接收空socket print("绑定地址", udp_addr) try: self.udp_socket.bind(udp_addr) @@ -146,16 +154,13 @@ class Pyqt5Net(QtWidgets.QWidget,Ui_UartAssistant): except Exception as e: print(f"Error reading configuration: {e}") return None - - + #使能相关按钮 self.pushButton_closeNet.setEnabled(True) self.pushButton_openNet.setEnabled(False) - # 打开串口接收定时器,周期为1ms self.timer.start(20) - def close_net(self): if hasattr(self, 'udp_socket'): @@ -165,28 +170,30 @@ class Pyqt5Net(QtWidgets.QWidget,Ui_UartAssistant): self.pushButton_closeNet.setEnabled(False) self.pushButton_openNet.setEnabled(True) print("关闭网络连接") + #接收数据 def data_receive(self): try: recv_data = self.udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数 out_s = '' # 打印接收到的数据 - if self.checkBoxHexReceive.checkState(): - line_utf8 = recv_data[0].hex() + if self.checkBoxHexReceive.checkState(): + line_utf8 = recv_data[0].hex().upper() + out_s = ' '.join(['{:02X}'.format(b) for b in bytes.fromhex(line_utf8)]) else: - line_utf8 = recv_data[0].decode('utf-8',errors='replace') - + line_utf8 = recv_data[0].decode('utf-8', errors='replace') + print("[From %s:%d]:%s" % (recv_data[1][0], recv_data[1][1], line_utf8)) - + num = len(line_utf8) # 接收窗口中增加来源地址显示 - recv_addr = recv_data[1][0]+':'+str(recv_data[1][1]) + recv_addr = recv_data[1][0] + ':' + str(recv_data[1][1]) if not self.is_in_comboBox_channel(recv_addr): self.comboBox_channel.addItem(recv_addr) - - if recv_addr==self.comboBox_channel.currentText() or self.comboBox_channel.currentText()=="ALL": + + if recv_addr == self.comboBox_channel.currentText() or self.comboBox_channel.currentText() == "ALL": #self.textEditReceive.insertPlainText('<' + recv_addr+ '> ' ) - + if self.checkBoxAddDate.isChecked(): nowTime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f") nowTime = nowTime[:-3] @@ -195,84 +202,94 @@ class Pyqt5Net(QtWidgets.QWidget,Ui_UartAssistant): # HEX显示数据 if self.checkBoxHexReceive.checkState(): # line_utf8_bytes = line_utf8.hex() # 编码为 UTF-8 字节串 - + # for byte in line_utf8_bytes: # out_s += '{:02X} '.format(byte) # 使用大写字母 X - - out_s = ' '.join(['{:02X}'.format(b) for b in bytes.fromhex(line_utf8)]) - + + + # self.textEditReceive.insertPlainText(out_s) # self.textEditReceive.insertPlainText('\r\n') - self.add_line_to_textedit('<' + recv_addr+ '> ' + out_s) + self.add_line_to_textedit('<' + recv_addr + '> ' + out_s) + + # 解析数据 + self.Disp_hex_receive(line_utf8) + # ASCII显示数据 else: #print("解码前",datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) #self.textEditReceive.insertPlainText(line_utf8) - self.add_line_to_textedit('<' + recv_addr+ '> ' + line_utf8) + self.add_line_to_textedit('<' + recv_addr + '> ' + line_utf8) #print("解码数据",datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) # 接收换行 if self.checkBoxCRLF.isChecked(): self.textEditReceive.insertPlainText('\r\n') - - - - + # 获取到text光标 textCursor = self.textEditReceive.textCursor() # 滚动到底部 textCursor.movePosition(textCursor.End) # 设置光标到text中去 self.textEditReceive.setTextCursor(textCursor) - + # 统计接收字符的数量 self.data_num_received += num self.lineEditReceiveNum.setText(str(self.data_num_received)) # 自动保存日志 - if self.checkBoxAutoSaveLog.isChecked(): - line = line_utf8.split(',') - if len(line) ==2: - sav_name = line[0] +'_'+ datetime.datetime.now().strftime("%Y-%m-%d")+'.txt' - sav_str = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")[:23] +" " +line[1] + if self.checkBoxAutoSaveLog.isChecked(): + if self.checkBoxHexReceive.checkState(): + #根据功能码保存数据 + if line_utf8[2*self.position:2*self.position+2] == self.funcode: + sav_name = line_utf8[0:8] + '_' + datetime.datetime.now().strftime("%Y-%m-%d") + '.txt' + sav_str = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")[:23] + " " + out_s[12:] + "\r\n" + else: + sav_name = datetime.datetime.now().strftime("%Y-%m-%d") + '.log' + sav_str = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")[:23] + " " + out_s + "\r\n" + + else: - sav_name = datetime.datetime.now().strftime("%Y-%m-%d")+'.log' - if self.checkBoxHexReceive.checkState(): - sav_str = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")[:23] +" " +out_s +"\r\n" + line = line_utf8.split(',') + if len(line) == 2: + sav_name = line[0] + '_' + datetime.datetime.now().strftime("%Y-%m-%d") + '.txt' + sav_str = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")[:23] + " " + line[1] + else: - sav_str = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")[:23] +" " +line_utf8 - - - # 将日志信息添加到缓冲区 + sav_name = datetime.datetime.now().strftime("%Y-%m-%d") + '.log' + sav_str = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")[:23] + " " + line_utf8 + + # 将日志信息添加到缓冲区 if sav_name not in self.log_buffer: self.log_buffer[sav_name] = [] self.log_buffer[sav_name].append(sav_str) - + # 当缓冲区中的记录达到10条时,写入文件 if len(self.log_buffer[sav_name]) >= self.log_time: - with open(sav_name, mode='a', newline='',encoding='utf-8', errors='replace') as file: + with open(sav_name, mode='a', newline='', encoding='utf-8', errors='replace') as file: file.writelines(self.log_buffer[sav_name]) self.log_buffer[sav_name].clear() - + except socket.error as e: #print(f"Socket error: {e}") pass - def data_send(self,text_quick = None): - if text_quick== None: + + def data_send(self, text_quick=None): + if text_quick == None: input_s = self.textEditSend.toPlainText() else: input_s = text_quick - + try: - + if input_s != "": # 时间显示 if self.checkBoxAddDate.isChecked(): self.textEditReceive.insertPlainText((time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + " ") - + # HEX发送 - if self.checkBoxHexSend.isChecked(): + if self.checkBoxHexSend.isChecked(): input_s = input_s.strip() send_list = [] while input_s != '': @@ -281,57 +298,76 @@ class Pyqt5Net(QtWidgets.QWidget,Ui_UartAssistant): except ValueError: QMessageBox.critical(self, '串口异常', '请输入规范十六进制数据,以空格分开!') return None - + input_s = input_s[2:].strip() send_list.append(num) - + input_s = bytes(send_list) # ASCII发送 - else: + else: input_s = (input_s).encode('utf-8') input_s = re.sub(b'(? 1000: current_lines = current_lines[-1000:] # 只保留最新的100行 @@ -391,49 +448,113 @@ class Pyqt5Net(QtWidgets.QWidget,Ui_UartAssistant): self.textEditReceive.setPlainText('\n'.join(current_lines)) #检查是否在comboBox_channel中 - def is_in_comboBox_channel(self,addr_rece): + def is_in_comboBox_channel(self, addr_rece): for i in range(self.comboBox_channel.count()): if addr_rece == self.comboBox_channel.itemText(i): return True return False - + def channel_clear(self): self.comboBox_channel.lineEdit().clear() - for i in range(self.comboBox_channel.count()-1): + for i in range(self.comboBox_channel.count() - 1): self.comboBox_channel.removeItem(1) self.comboBox_channel.setCurrentIndex(0) - - #开关快捷指令栏 + + #开关快捷指令栏 def adjust_sidebar(self): if self.widget_6.isHidden(): self.widget_6.show() else: self.widget_6.hide() - + def onPushButtonQuickClicked(self, line_edit): text = getattr(self, line_edit).text() #print(f"Button clicked: {text}") if self.checkBox_return.isChecked(): text = text + "\r\n" self.data_send(text) - + def CheckCfgIniData(self): - if not os.path.exists(self.IniPath): + if not os.path.exists(self.IniPath): config = ConfigParser() + #UI_config + config.add_section('UI_config') + config.set('UI_config', 'port', '9000') + config.set('UI_config', 'hex_send', '0') + config.set('UI_config', 'hex_receive', '0') + config.set('UI_config', 'add_date', '0') + config.set('UI_config', 'cr_lf', '0') + config.set('UI_config', 'auto_sav_log', '2') + config.set('UI_config', 'modbus_csv', '0') + + # Modbus_config + config.add_section('Modbus_config') + config.set('Modbus_config', 'funcode', 'F4') #识别码 + config.set('Modbus_config', 'position', '5') #识别码所在位置 + + #DisHex_config + config.add_section('DisHex_config') + for i in range(self.quick_num): + idx = f'{i:02}' + rowname = f'row{idx}' + config.set('DisHex_config', rowname, '|||||0') + + + #Quick_config config.add_section('Quick_config') config.set('Quick_config', 'log_time', '10') for i in range(self.quick_num): idx = f'{i:02}' button_name = f'Button{idx}' # 格式化按钮名称,确保两位数 config.set('Quick_config', button_name, '') - with open(self.IniPath, 'w' ,encoding='utf-8') as f: + with open(self.IniPath, 'w', encoding='utf-8') as f: config.write(f) - + #读取数据 config = ConfigParser() config.read(self.IniPath, encoding='utf-8') try: - - # 创建一个空字典来存储按钮名称和对应的配置 + # UI_config + port = config.get('UI_config', 'port') + hex_send = int(config.get('UI_config', 'hex_send')) + hex_receive = int(config.get('UI_config', 'hex_receive')) + add_date = int(config.get('UI_config', 'add_date')) + cr_lf = int(config.get('UI_config', 'cr_lf')) + auto_sav_log = int(config.get('UI_config', 'auto_sav_log')) + modbus_csv = int(config.get('UI_config', 'modbus_csv')) + self.lineEdit_port.setText(port) + self.checkBoxHexSend.setChecked(hex_send) + self.checkBoxHexReceive.setChecked(hex_receive) + self.checkBoxAddDate.setChecked(add_date) + self.checkBoxCRLF.setChecked(cr_lf) + self.checkBoxAutoSaveLog.setChecked(auto_sav_log) + self.checkBoxAutoSaveCsv.setChecked(modbus_csv) + + + # Modbus_config + self.funcode = config.get('Modbus_config', 'funcode') + self.position = int(config.get('Modbus_config', 'position')) + + # DisHex_config + for i in range(self.quick_num): + idx = f'{i:02}' + rowname = f'row{idx}' + rowstr = config.get('DisHex_config', rowname) + rowstr_split = rowstr.split('|') + + for col in range(len(rowstr_split)-1): + item = QtWidgets.QTableWidgetItem() + item.setText(rowstr_split[col]) + self.tableWidget.setItem(i, col, item) + select = int(rowstr_split[col+1]) + item = self.tableWidget.item(i, 0) # 先反读回来,再设置,不然text丢失 + item.setCheckState(select) + self.tableWidget.setItem(i, 0, item) + + + + + # Quick_config + # 创建一个空字典来存储按钮名称和对应的配置 self.log_time = int(config.get('Quick_config', 'log_time')) # 循环遍历按钮编号,从0到19 for i in range(self.quick_num): @@ -444,26 +565,57 @@ class Pyqt5Net(QtWidgets.QWidget,Ui_UartAssistant): config_value_split = config_value.split('|') # 将按钮名称和配置信息存储在字典中 if len(config_value_split) == 2: - # 打印字典查看结果,并赋值 - print(button_name,config_value_split[0],config_value_split[1]) + # 打印字典查看结果,并赋值 + print(button_name, config_value_split[0], config_value_split[1]) getattr(self, f'pushButtonQuick_{idx}').setText(config_value_split[1]) getattr(self, f'lineEditQuick_{idx}').setText(config_value_split[0]) except Exception as e: print(f"Error reading configuration: {e}") - - - def SetCfgIniData(self,button_name,set_text): + + def SavConfig(self): + #关闭界面前保存快捷区域的命令和名称 config = ConfigParser() config.read(self.IniPath, encoding='utf-8') - config.set('Quick_config', button_name, set_text) - with open(self.IniPath, 'w' ,encoding='utf-8') as f: + # 保存UI_config + config.set('UI_config', 'port', str(self.lineEdit_port.text())) + config.set('UI_config', 'hex_send', str(self.checkBoxHexSend.checkState())) + config.set('UI_config', 'hex_receive', str(self.checkBoxHexReceive.checkState())) + config.set('UI_config', 'add_date', str(self.checkBoxAddDate.checkState())) + config.set('UI_config','cr_lf',str(self.checkBoxCRLF.checkState())) + config.set('UI_config', 'auto_sav_log', str(self.checkBoxAutoSaveLog.checkState())) + config.set('UI_config', 'modbus_csv', str(self.checkBoxAutoSaveCsv.checkState())) + + # 保存DisHex_config + for i in range(self.quick_num): + rowstr = [] + idx = f'{i:02}' + rowname = f'row{idx}' + for col in range(self.tableWidget.columnCount()-1): + item = self.tableWidget.item(i, col) + if item is not None: + rowstr.append(item.text()) + else: + rowstr.append('') # 如果单元格为空,则添加空字符串 + selectStr = str(self.tableWidget.item(i,0).checkState()) + row_string = '|'.join(rowstr) + f'|{selectStr}' + config.set('DisHex_config', rowname, row_string) + + # 保存快捷按钮 + for i in range(self.quick_num): # 假设有20个按钮 + index_str = f"{i:02}" # 确保编号为两位数字形式 + lineEditName = f"lineEditQuick_{index_str}" + buttonName = f"pushButtonQuick_{index_str}" # 格式化按钮名称,确保两位数 + button_name = f"button{index_str}" + set_text = getattr(self, lineEditName).text() + "|" + getattr(self, buttonName).text() + config.set('Quick_config', button_name, set_text) + + with open(self.IniPath, 'w', encoding='utf-8') as f: config.write(f) - - + def onButtonClick(self, idx): # 槽函数处理按钮点击事件 - + if idx not in self.double_click_timers: self.double_click_timers[idx] = None @@ -478,11 +630,11 @@ class Pyqt5Net(QtWidgets.QWidget,Ui_UartAssistant): if self.double_click_timers[idx]: self.double_click_timers[idx] = None lineEdit = getattr(self, f"lineEditQuick_{index_str}") - print(f"Text in lineEdit_{idx}: {lineEdit.text()}") + print(f"Text in lineEdit_{idx}: {lineEdit.text()}") text = lineEdit.text() if self.checkBox_return.isChecked(): text = text + "\r\n" - self.data_send(text) + self.data_send(text) def onButtonDoubleClick(self, idx): # 槽函数处理按钮双击事件 @@ -495,12 +647,9 @@ class Pyqt5Net(QtWidgets.QWidget,Ui_UartAssistant): button.setText(new_name) - - - #执行 if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) myshow = Pyqt5Net() myshow.show() - sys.exit(app.exec_()) \ No newline at end of file + sys.exit(app.exec_()) diff --git a/PyNetAssistant/PyNetUi.py b/PyNetAssistant/PyNetUi.py index 3f239d3..1a3b0e4 100644 --- a/PyNetAssistant/PyNetUi.py +++ b/PyNetAssistant/PyNetUi.py @@ -24,8 +24,8 @@ class Ui_UartAssistant(object): icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap("favicon.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off) UartAssistant.setWindowIcon(icon) - self.horizontalLayout_15 = QtWidgets.QHBoxLayout(UartAssistant) - self.horizontalLayout_15.setObjectName("horizontalLayout_15") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(UartAssistant) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.widget_7 = QtWidgets.QWidget(UartAssistant) self.widget_7.setObjectName("widget_7") self.horizontalLayout_14 = QtWidgets.QHBoxLayout(self.widget_7) @@ -37,7 +37,7 @@ class Ui_UartAssistant(object): self.splitter.setObjectName("splitter") self.widget_4 = QtWidgets.QWidget(self.splitter) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(3) + sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.widget_4.sizePolicy().hasHeightForWidth()) self.widget_4.setSizePolicy(sizePolicy) @@ -132,10 +132,20 @@ class Ui_UartAssistant(object): self.pushButtonLogLoad = QtWidgets.QPushButton(self.layoutWidget_6) self.pushButtonLogLoad.setObjectName("pushButtonLogLoad") self.horizontalLayout_13.addWidget(self.pushButtonLogLoad) - self.checkBoxAutoSaveLog = QtWidgets.QCheckBox(self.groupBox_2) - self.checkBoxAutoSaveLog.setGeometry(QtCore.QRect(12, 103, 90, 16)) + self.layoutWidget1 = QtWidgets.QWidget(self.groupBox_2) + self.layoutWidget1.setGeometry(QtCore.QRect(12, 100, 191, 31)) + self.layoutWidget1.setObjectName("layoutWidget1") + self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.layoutWidget1) + self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.checkBoxAutoSaveLog = QtWidgets.QCheckBox(self.layoutWidget1) self.checkBoxAutoSaveLog.setChecked(True) self.checkBoxAutoSaveLog.setObjectName("checkBoxAutoSaveLog") + self.horizontalLayout_4.addWidget(self.checkBoxAutoSaveLog) + self.checkBoxAutoSaveCsv = QtWidgets.QCheckBox(self.layoutWidget1) + self.checkBoxAutoSaveCsv.setChecked(False) + self.checkBoxAutoSaveCsv.setObjectName("checkBoxAutoSaveCsv") + self.horizontalLayout_4.addWidget(self.checkBoxAutoSaveCsv) self.verticalLayout_5.addWidget(self.groupBox_2) self.groupBox_3 = QtWidgets.QGroupBox(self.widget) self.groupBox_3.setMinimumSize(QtCore.QSize(0, 0)) @@ -187,27 +197,58 @@ class Ui_UartAssistant(object): self.widget_5.setSizePolicy(sizePolicy) self.widget_5.setMinimumSize(QtCore.QSize(400, 0)) self.widget_5.setObjectName("widget_5") - self.horizontalLayout_9 = QtWidgets.QHBoxLayout(self.widget_5) - self.horizontalLayout_9.setContentsMargins(0, 0, 0, 0) - self.horizontalLayout_9.setSpacing(0) - self.horizontalLayout_9.setObjectName("horizontalLayout_9") - self.tabWidget = QtWidgets.QTabWidget(self.widget_5) - self.tabWidget.setMouseTracking(False) - self.tabWidget.setObjectName("tabWidget") - self.tab = QtWidgets.QWidget() - self.tab.setObjectName("tab") - self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.tab) + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.widget_5) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) self.verticalLayout_3.setObjectName("verticalLayout_3") - self.groupBox_4 = QtWidgets.QGroupBox(self.tab) - self.groupBox_4.setObjectName("groupBox_4") - self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.groupBox_4) - self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.textEditReceive = QtWidgets.QTextEdit(self.groupBox_4) + self.tabWidget = QtWidgets.QTabWidget(self.widget_5) + self.tabWidget.setObjectName("tabWidget") + self.tab1 = QtWidgets.QWidget() + self.tab1.setFocusPolicy(QtCore.Qt.TabFocus) + self.tab1.setObjectName("tab1") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tab1) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.textEditReceive = QtWidgets.QTextEdit(self.tab1) self.textEditReceive.setSizeIncrement(QtCore.QSize(0, 0)) self.textEditReceive.setObjectName("textEditReceive") - self.horizontalLayout_2.addWidget(self.textEditReceive) - self.verticalLayout_3.addWidget(self.groupBox_4) - self.groupBox_7 = QtWidgets.QGroupBox(self.tab) + self.verticalLayout_2.addWidget(self.textEditReceive) + self.tabWidget.addTab(self.tab1, "") + self.tab2 = QtWidgets.QWidget() + self.tab2.setEnabled(True) + self.tab2.setFocusPolicy(QtCore.Qt.NoFocus) + self.tab2.setObjectName("tab2") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.tab2) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.tableWidget = QtWidgets.QTableWidget(self.tab2) + self.tableWidget.setGridStyle(QtCore.Qt.SolidLine) + self.tableWidget.setRowCount(10) + self.tableWidget.setColumnCount(5) + self.tableWidget.setObjectName("tableWidget") + item = QtWidgets.QTableWidgetItem() + item.setBackground(QtGui.QColor(172, 172, 172)) + self.tableWidget.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + item.setBackground(QtGui.QColor(172, 172, 172)) + self.tableWidget.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + item.setBackground(QtGui.QColor(172, 172, 172)) + self.tableWidget.setHorizontalHeaderItem(2, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(3, item) + item = QtWidgets.QTableWidgetItem() + item.setBackground(QtGui.QColor(172, 172, 172)) + self.tableWidget.setHorizontalHeaderItem(4, item) + self.tableWidget.horizontalHeader().setCascadingSectionResizes(False) + self.tableWidget.horizontalHeader().setDefaultSectionSize(50) + self.tableWidget.horizontalHeader().setMinimumSectionSize(20) + self.tableWidget.horizontalHeader().setSortIndicatorShown(True) + self.tableWidget.horizontalHeader().setStretchLastSection(True) + self.tableWidget.verticalHeader().setVisible(False) + self.tableWidget.verticalHeader().setCascadingSectionResizes(False) + self.tableWidget.verticalHeader().setDefaultSectionSize(25) + self.verticalLayout_4.addWidget(self.tableWidget) + self.tabWidget.addTab(self.tab2, "") + self.verticalLayout_3.addWidget(self.tabWidget) + self.groupBox_7 = QtWidgets.QGroupBox(self.widget_5) self.groupBox_7.setObjectName("groupBox_7") self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.groupBox_7) self.horizontalLayout_3.setObjectName("horizontalLayout_3") @@ -222,13 +263,33 @@ class Ui_UartAssistant(object): self.horizontalLayout_3.setStretch(0, 8) self.horizontalLayout_3.setStretch(1, 1) self.verticalLayout_3.addWidget(self.groupBox_7) - self.groupBox_5 = QtWidgets.QGroupBox(self.tab) + self.groupBox_5 = QtWidgets.QGroupBox(self.widget_5) self.groupBox_5.setObjectName("groupBox_5") self.gridLayout = QtWidgets.QGridLayout(self.groupBox_5) self.gridLayout.setObjectName("gridLayout") + self.textEditSend = QtWidgets.QTextEdit(self.groupBox_5) + self.textEditSend.setObjectName("textEditSend") + self.gridLayout.addWidget(self.textEditSend, 0, 0, 3, 1) + self.pushButton_expend = QtWidgets.QPushButton(self.groupBox_5) + self.pushButton_expend.setObjectName("pushButton_expend") + self.gridLayout.addWidget(self.pushButton_expend, 0, 1, 1, 1) self.pushButtonClearReceive = QtWidgets.QPushButton(self.groupBox_5) self.pushButtonClearReceive.setObjectName("pushButtonClearReceive") self.gridLayout.addWidget(self.pushButtonClearReceive, 1, 1, 1, 1) + self.pushButtonClearSend = QtWidgets.QPushButton(self.groupBox_5) + self.pushButtonClearSend.setObjectName("pushButtonClearSend") + self.gridLayout.addWidget(self.pushButtonClearSend, 2, 1, 2, 1) + self.widget_2 = QtWidgets.QWidget(self.groupBox_5) + self.widget_2.setObjectName("widget_2") + self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.widget_2) + self.horizontalLayout_5.setObjectName("horizontalLayout_5") + self.checkBoxSendAll = QtWidgets.QCheckBox(self.widget_2) + self.checkBoxSendAll.setObjectName("checkBoxSendAll") + self.horizontalLayout_5.addWidget(self.checkBoxSendAll) + self.checkBoxAddCRC = QtWidgets.QCheckBox(self.widget_2) + self.checkBoxAddCRC.setObjectName("checkBoxAddCRC") + self.horizontalLayout_5.addWidget(self.checkBoxAddCRC) + self.gridLayout.addWidget(self.widget_2, 3, 0, 2, 1) self.pushButtonSend = QtWidgets.QPushButton(self.groupBox_5) font = QtGui.QFont() font.setFamily("3ds") @@ -239,22 +300,11 @@ class Ui_UartAssistant(object): self.pushButtonSend.setCheckable(False) self.pushButtonSend.setFlat(False) self.pushButtonSend.setObjectName("pushButtonSend") - self.gridLayout.addWidget(self.pushButtonSend, 3, 1, 1, 1) - self.pushButtonClearSend = QtWidgets.QPushButton(self.groupBox_5) - self.pushButtonClearSend.setObjectName("pushButtonClearSend") - self.gridLayout.addWidget(self.pushButtonClearSend, 2, 1, 1, 1) - self.pushButton_expend = QtWidgets.QPushButton(self.groupBox_5) - self.pushButton_expend.setObjectName("pushButton_expend") - self.gridLayout.addWidget(self.pushButton_expend, 0, 1, 1, 1) - self.textEditSend = QtWidgets.QTextEdit(self.groupBox_5) - self.textEditSend.setObjectName("textEditSend") - self.gridLayout.addWidget(self.textEditSend, 0, 0, 4, 1) + self.gridLayout.addWidget(self.pushButtonSend, 4, 1, 1, 1) self.verticalLayout_3.addWidget(self.groupBox_5) - self.verticalLayout_3.setStretch(0, 6) + self.verticalLayout_3.setStretch(0, 7) self.verticalLayout_3.setStretch(1, 1) self.verticalLayout_3.setStretch(2, 2) - self.tabWidget.addTab(self.tab, "") - self.horizontalLayout_9.addWidget(self.tabWidget) self.widget_6 = QtWidgets.QWidget(self.splitter) self.widget_6.setEnabled(True) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) @@ -273,7 +323,7 @@ class Ui_UartAssistant(object): self.scrollArea.setWidgetResizable(False) self.scrollArea.setObjectName("scrollArea") self.scrollAreaWidgetContents = QtWidgets.QWidget() - self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, -2388, 241, 3000)) + self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 241, 3000)) self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") self.widget_8 = QtWidgets.QWidget(self.scrollAreaWidgetContents) self.widget_8.setGeometry(QtCore.QRect(12, 2, 221, 34)) @@ -291,17 +341,17 @@ class Ui_UartAssistant(object): self.widget_9 = QtWidgets.QWidget(self.scrollAreaWidgetContents) self.widget_9.setGeometry(QtCore.QRect(10, 40, 231, 3000)) self.widget_9.setObjectName("widget_9") - self.layoutWidget1 = QtWidgets.QWidget(self.widget_9) - self.layoutWidget1.setGeometry(QtCore.QRect(12, 12, 218, 2941)) - self.layoutWidget1.setObjectName("layoutWidget1") - self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.layoutWidget1) + self.layoutWidget2 = QtWidgets.QWidget(self.widget_9) + self.layoutWidget2.setGeometry(QtCore.QRect(12, 12, 218, 2941)) + self.layoutWidget2.setObjectName("layoutWidget2") + self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.layoutWidget2) self.verticalLayout_8.setSizeConstraint(QtWidgets.QLayout.SetMaximumSize) self.verticalLayout_8.setContentsMargins(0, 0, 0, 0) self.verticalLayout_8.setObjectName("verticalLayout_8") self.scrollArea.setWidget(self.scrollAreaWidgetContents) self.horizontalLayout_16.addWidget(self.scrollArea) self.horizontalLayout_14.addWidget(self.splitter) - self.horizontalLayout_15.addWidget(self.widget_7) + self.horizontalLayout_2.addWidget(self.widget_7) self.retranslateUi(UartAssistant) self.comboBox_localAddr.setCurrentIndex(0) @@ -330,6 +380,7 @@ class Ui_UartAssistant(object): self.pushButtonLogSave.setText(_translate("UartAssistant", "保存日志")) self.pushButtonLogLoad.setText(_translate("UartAssistant", "加载日志")) self.checkBoxAutoSaveLog.setText(_translate("UartAssistant", "自动保存日志")) + self.checkBoxAutoSaveCsv.setText(_translate("UartAssistant", "modbus2csv")) self.groupBox_3.setTitle(_translate("UartAssistant", "定时发送")) self.checkBoxReapitSend.setText(_translate("UartAssistant", "定时发送")) self.label_7.setText(_translate("UartAssistant", "ms/次")) @@ -337,15 +388,27 @@ class Ui_UartAssistant(object): self.label_9.setText(_translate("UartAssistant", "Rx")) self.label_10.setText(_translate("UartAssistant", "Powerd by Byan")) self.label_SendNum.setText(_translate("UartAssistant", "Tx")) - self.groupBox_4.setTitle(_translate("UartAssistant", "数据接收区")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab1), _translate("UartAssistant", "数据")) + item = self.tableWidget.horizontalHeaderItem(0) + item.setText(_translate("UartAssistant", "select")) + item = self.tableWidget.horizontalHeaderItem(1) + item.setText(_translate("UartAssistant", "start")) + item = self.tableWidget.horizontalHeaderItem(2) + item.setText(_translate("UartAssistant", "num")) + item = self.tableWidget.horizontalHeaderItem(3) + item.setText(_translate("UartAssistant", "scale")) + item = self.tableWidget.horizontalHeaderItem(4) + item.setText(_translate("UartAssistant", "value")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab2), _translate("UartAssistant", "解析")) self.groupBox_7.setTitle(_translate("UartAssistant", "选择通道")) self.comboBox_channel.setItemText(0, _translate("UartAssistant", "ALL")) self.pushButtonClearChannel.setText(_translate("UartAssistant", "清空")) self.groupBox_5.setTitle(_translate("UartAssistant", "数据发送区")) - self.pushButtonClearReceive.setText(_translate("UartAssistant", "清除接收")) - self.pushButtonSend.setText(_translate("UartAssistant", "发送")) - self.pushButtonClearSend.setText(_translate("UartAssistant", "清除发送")) self.pushButton_expend.setText(_translate("UartAssistant", "快捷指令")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("UartAssistant", "数据")) + self.pushButtonClearReceive.setText(_translate("UartAssistant", "清除接收")) + self.pushButtonClearSend.setText(_translate("UartAssistant", "清除发送")) + self.checkBoxSendAll.setText(_translate("UartAssistant", "发送全部通道")) + self.checkBoxAddCRC.setText(_translate("UartAssistant", "附加校验")) + self.pushButtonSend.setText(_translate("UartAssistant", "发送")) self.label_8.setText(_translate("UartAssistant", "快捷指令")) self.checkBox_return.setText(_translate("UartAssistant", "添加\"\\r\\n\"")) diff --git a/PyNetAssistant/PyNetUi.ui b/PyNetAssistant/PyNetUi.ui index 57dec66..56fddbb 100644 --- a/PyNetAssistant/PyNetUi.ui +++ b/PyNetAssistant/PyNetUi.ui @@ -26,7 +26,7 @@ favicon.icofavicon.ico - + @@ -47,7 +47,7 @@ - 3 + 0 0 @@ -278,21 +278,37 @@ - + 12 - 103 - 90 - 16 + 100 + 191 + 31 - - 自动保存日志 - - - true - + + + + + 自动保存日志 + + + true + + + + + + + modbus2csv + + + false + + + + @@ -463,139 +479,251 @@ 0 - - - 0 - - - 0 - - - 0 - - - 0 - + - - false - 0 - + + + Qt::TabFocus + 数据 - + - - - 数据接收区 + + + + 0 + 0 + - - - - - - 0 - 0 - - - - - - - - - - - 选择通道 - - - - - - true - - - - ALL - - - - - - - - 清空 - - - - - - - - - - 数据发送区 - - - - - - 清除接收 - - - - - - - - 3ds - 12 - - - - false - - - background-color: rgb(0, 255, 0); - - - 发送 - - - false - - - false - - - - - - - 清除发送 - - - - - - - 快捷指令 - - - - - - - + + + true + + + Qt::NoFocus + + + 解析 + + + + + + Qt::SolidLine + + + 10 + + + 5 + + + false + + + 20 + + + 50 + + + true + + + true + + + false + + + false + + + 25 + + + + + + + + + + + + + + select + + + + 172 + 172 + 172 + + + + + + start + + + + 172 + 172 + 172 + + + + + + num + + + + 172 + 172 + 172 + + + + + + scale + + + + + value + + + + 172 + 172 + 172 + + + + + + + + + + + + + 选择通道 + + + + + + true + + + + ALL + + + + + + + + 清空 + + + + + + + + + + 数据发送区 + + + + + + + + + 快捷指令 + + + + + + + 清除接收 + + + + + + + 清除发送 + + + + + + + + + + 发送全部通道 + + + + + + + 附加校验 + + + + + + + + + + + 3ds + 12 + + + + false + + + background-color: rgb(0, 255, 0); + + + 发送 + + + false + + + false + + + + @@ -644,7 +772,7 @@ 0 - -2388 + 0 241 3000 diff --git a/PyNetAssistant/PyUartUi.ui b/PyNetAssistant/PyUartUi.ui deleted file mode 100644 index df9eb6d..0000000 --- a/PyNetAssistant/PyUartUi.ui +++ /dev/null @@ -1,1157 +0,0 @@ - - - UartAssistant - - - - 0 - 0 - 996 - 694 - - - - - 2 - 0 - - - - true - - - 串口助手py版 - - - - favicon.icofavicon.ico - - - - - - - - - - 16777215 - 16777215 - - - - Qt::Horizontal - - - 5 - - - - - 1 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - 220 - 291 - - - - - 271 - 291 - - - - 串口设置 - - - - - 10 - 210 - 93 - 28 - - - - 检测串口 - - - - - - 120 - 210 - 93 - 28 - - - - background-color: rgb(0, 255, 0); - - - 打开串口 - - - - - - 10 - 240 - 201 - 28 - - - - 关闭串口 - - - - - - 10 - 30 - 74 - 171 - - - - - - - 串口号 - - - - - - - 波特率 - - - - - - - 数据位 - - - - - - - 校验位 - - - - - - - 停止位 - - - - - - - 流控方式 - - - - - - - - - 80 - 30 - 128 - 171 - - - - - - - - - - 0 - - - true - - - 4800 - - - 0 - - - - 4800 - - - - - 9600 - - - - - 14400 - - - - - 19200 - - - - - 115200 - - - - - 921600 - - - - - 1500000 - - - - - 新建项目 - - - - - 新建项目 - - - - - 新建项目 - - - - - 自定义 - - - - - - - - true - - - 8 - - - 3 - - - - 5 - - - - - 6 - - - - - 7 - - - - - 8 - - - - - - - - true - - - 0 - - - - None - - - - - Odd - - - - - Even - - - - - - - - true - - - - 1 - - - - - 2 - - - - - - - - true - - - - No Ctrl Flow - - - - - SW Ctrl Flow - - - - - - - - - - - - - 220 - 165 - - - - - 271 - 165 - - - - 收发设置 - - - - - 10 - 20 - 197 - 79 - - - - - - - - - HEX发送 - - - - - - - HEX接收 - - - - - - - - - - - DTR - - - - - - - RTS - - - - - - - - - - - 收/发时间 - - - - - - - 收发换行 - - - - - - - - - - - 10 - 130 - 195 - 30 - - - - - - - 保存日志 - - - - - - - 加载日志 - - - - - - - - - 12 - 103 - 90 - 16 - - - - 自动保存日志 - - - true - - - - - - - - - 220 - 80 - - - - - 271 - 80 - - - - 定时发送 - - - - - 10 - 30 - 91 - 19 - - - - 定时发送 - - - - - - 170 - 30 - 51 - 16 - - - - ms/次 - - - - - - 110 - 30 - 51 - 21 - - - - 1000 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 220 - 80 - - - - - 281 - 80 - - - - - - - - - 120 - 20 - 72 - 15 - - - - Rx - - - - - - 40 - 20 - 61 - 21 - - - - - - - 140 - 20 - 61 - 21 - - - - - - - 20 - 40 - 131 - 16 - - - - Powerd by Byan - - - - - - 20 - 20 - 72 - 15 - - - - Tx - - - - - - - - - - - - - 1 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - false - - - 0 - - - - 串口数据 - - - - - - 数据接收区 - - - - - - - 1 - 1 - - - - - - - - - - - 数据发送区 - - - - - - 清除接收 - - - - - - - - 3ds - 12 - - - - false - - - background-color: rgb(0, 255, 0); - - - 发送 - - - false - - - false - - - - - - - 清除发送 - - - - - - - 快捷指令 - - - - - - - - - - - - - - - - - - true - - - - 2 - 0 - - - - - 260 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::ScrollBarAlwaysOn - - - false - - - - - 0 - 0 - 241 - 1000 - - - - - - 12 - 2 - 221 - 34 - - - - - - - 快捷指令 - - - - - - - 添加"回车换行" - - - true - - - - - - - - - 12 - 42 - 236 - 1000 - - - - - - 12 - 12 - 218 - 616 - - - - - - - - - - - - Button01 - - - - - - - - - - - - - - Button02 - - - - - - - - - - - - - - Button03 - - - - - - - - - - - - - - Button04 - - - - - - - - - - - - - - Button05 - - - - - - - - - - - - - - Button06 - - - - - - - - - - - - - - Button07 - - - - - - - - - - - - - - Button08 - - - - - - - - - - - - - - Button09 - - - - - - - - - - - - - - Button10 - - - - - - - - - - - - - - Button11 - - - - - - - - - - - - - - Button12 - - - - - - - - - - - - - - Button13 - - - - - - - - - - - - - - Button14 - - - - - - - - - - - - - - Button15 - - - - - - - - - - - - - - Button16 - - - - - - - - - - - - - - Button17 - - - - - - - - - - - - - - Button18 - - - - - - - - - - - - - - Button19 - - - - - - - - - - - - - - Button20 - - - - - - - - - - - - - - - - - - - - - - - diff --git a/PyNetAssistant/UartDataPolt.py b/PyNetAssistant/UartDataPolt.py deleted file mode 100644 index 76bec3e..0000000 --- a/PyNetAssistant/UartDataPolt.py +++ /dev/null @@ -1,347 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Tue May 28 15:40:48 2024 - -@author: WANGXIBAO -""" -# -*- coding: utf-8 -*- - - - -import time,math,os -import re,csv,datetime - -from PyQt5.QtCore import QThread, pyqtSignal -from PyQt5.QtWidgets import QMessageBox -from PyQt5.QtGui import QPen -from configparser import ConfigParser - -# 波形显示 - -# 使用线程不断更新波形数据 - -class UpdateDataThread(QThread): - _signal_update = pyqtSignal(float) # 信号 - - def __init__(self, parent=None): - super(UpdateDataThread, self).__init__(parent) - self.is_exit = False - self.x_range = 1024 - self.getDateQx = GetDataQX() - self.flag = 0 - - - - def run(self): - print("run start") - while not self.is_exit: # 直接在循环中检查退出标志 - # for i in range(self.x_range): - # print(i,self.sin.get_data(i)) - - # self._signal_update.emit(str(self.sin.get_data(i))) # 发射信号 - # time.sleep(0.01) # 实际应用中推荐使用QTimer代替 - - # 这里应该有一个 flag 默认是 0 外部调用可以传紧来1,没循环完自己置零,while 只起到监控左右 - - if self.flag == 1: - #print("flag",self.flag) - - #data = self.setReceiveData - #print("发数",datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) - print("data receive ",self.setReceiveData) - # print(f"{data:.3f}") - try: - - self._signal_update.emit(self.setReceiveData) - self.flag = 0 - - - except Exception: - QMessageBox.critical(self, '数据异常', '数据格式不对,不能绘图') - pass - - - - - def SetReceiveData(self,data_in): - self.setReceiveData = data_in - - def SetFlag(self,flag): - self.flag = flag - - def SetFilenameCsv(self,filename): - self.filenameCsv = filename - - def SetPlotItem(self,ind): #设置显示项目 - self.ind = ind - - def stop(self): - self.is_exit = True # 设置退出标志 - print("停止绘图") - def restart(self): - self.is_exit = False - - - - -class GetDataQX(): #读取请芯数据 - def __init__(self, parent=None): - super().__init__() - self.indOfReturn =0 - self.regexQx = re.compile(r'(A\+|B\+|\s)+') # 编译正则表达式 - self.TIME_FORMAT = "%Y-%m-%d %H:%M:%S" - def Transdata(self,data): - parts = re.split(self.regexQx,data) - # 过滤掉空字符串 - parts = [part for part in parts if part] - #print(parts) - methane = float(parts[1]) - airTemp = float(parts[3]) - laserTemp = float( parts[5])/1 - laerIntensity = float(parts[7])*10 - timeCrvt=time.strftime(self.TIME_FORMAT, time.localtime()) - self.data2csv =[(timeCrvt,methane,airTemp,laserTemp,laerIntensity)] - #print(self.data2csv) - - if self.indOfReturn == 0: - returnData = methane - elif self.indOfReturn == 1: - returnData = airTemp - elif self.indOfReturn == 2: - returnData = laserTemp - elif self.indOfReturn == 3: - returnData = laerIntensity - print(returnData) - return returnData - - def SaveCsv(self,filenameCsv): - # 打开一个文件用于写入,如果文件不存在则创建 - if os.path.isfile(filenameCsv) == 0: - # 文件为空,需要写入表头 - with open(filenameCsv, mode='w', newline='') as file: - writer = csv.writer(file) - writer.writerow(('time', 'Methane', 'Air Temp', 'Laser Temp', 'Laser Intensity')) - else: - with open(filenameCsv, mode='a', newline='') as file: - # 创建一个写入器对象 - writer = csv.writer(file) - # 写入数据行 - writer.writerows(self.data2csv) - - def IndOfReturn(self,ind): - self.indOfReturn = ind - - - - - -class GetDataTF(): #读取费加罗或者自定义数据 - def __init__(self, parent=None): - super().__init__() - self.indOfReturn =0 - #self.regex = re.compile(r'(A\+|B\+|\s)+') # 编译正则表达式 - self.TIME_FORMAT = "%Y-%m-%d %H:%M:%S" - self.regularIniPath = "regular.ini" # 配置文件默认路径 - self.headStr = "" - self.rowTitle=[] - self.buttons_config = [[None for _ in range(3)] for _ in range(20)] - #存放快捷按键配置 - self.CheckCfgIniData() # 初始化配置文件 - - def Transdata(self,data): - if data[:2] ==self.headStr: - # parts = re.split(self.regex,data) - # # 过滤掉空字符串 - # parts = [part for part in parts if part] - #print(parts) - # methane = float(parts[1]) - # airTemp = float(parts[3]) - # laserTemp = float( parts[5])/1 - # laerIntensity = float(parts[7])*10 - - # self.data2csv =[(timeCrvt,methane,airTemp,laserTemp,laerIntensity)] - - - self.data2csv = self.regex.findall(data) - - #print(self.data2csv) - - # if self.indOfReturn == 0: - # returnData = methane - # elif self.indOfReturn == 1: - # returnData = airTemp - # elif self.indOfReturn == 2: - # returnData = laserTemp - # elif self.indOfReturn == 3: - # returnData = laerIntensity - returnData = float(self.data2csv[self.indOfReturn]) - print("returnData",returnData) - return returnData - else: - return "noNum" - - def SaveCsv(self,filenameCsv): - # 打开一个文件用于写入,如果文件不存在则创建 - if os.path.isfile(filenameCsv) == 0: - # 文件为空,需要写入表头 - - with open(filenameCsv, mode='w', newline='') as file: - writer = csv.writer(file) - #writer.writerow(('time', 'Methane', 'Air Temp', 'Laser Temp', 'Laser Intensity')) - - writer.writerow(self.rowTitle) - else: - with open(filenameCsv, mode='a', newline='') as file: - # 创建一个写入器对象 - writer = csv.writer(file) - # 写入数据行 - timeCrvt=time.strftime(self.TIME_FORMAT, time.localtime()) - self.data2csv.insert(0, timeCrvt) - print(self.data2csv) - writer.writerows([self.data2csv]) - - def IndOfReturn(self,ind): - self.indOfReturn = ind - - def CheckCfgIniData(self): - if not os.path.exists(self.regularIniPath): - - config = ConfigParser() - config.add_section('TF_config') - config.set('TF_config', 'regular', '\+?-?\d+(?:\.\d+)?') - #config.set('TF_config', 'regular', '(A\+|B\+|\s)+') - config.set('TF_config', 'headStr', 'A+') - config.set('TF_config', 'rowTitle', 'time,Methane,Air Temp,Laser Temp,Laser Intensity,amplification,NL,ND,Sinal,SNR,PEAK,Best Piont') - - config.add_section('Quick_config') - config.set('Quick_config', 'Button00', 'write 0,2024100101|序列号') - config.set('Quick_config', 'Button01', 'write 1,65000|激光温度') - config.set('Quick_config', 'Button02', 'write 2,1000|K*1000') - config.set('Quick_config', 'Button03', 'write 3,0|B*1000') - config.set('Quick_config', 'Button04', 'write 4,0|可调电阻') - config.set('Quick_config', 'Button05', 'write 5,30|电阻抽头') - config.set('Quick_config', 'Button06', 'write 6,0|输出温度') - config.set('Quick_config', 'Button07', 'write 7,0|输出激光') - config.set('Quick_config', 'Button08', 'write 8,1|输出状态') - config.set('Quick_config', 'Button09', 'write 9,0|激光温补') - config.set('Quick_config', 'Button10', 'write 10,100|噪声长度') - config.set('Quick_config', 'Button11', 'write 11,600|扫描长度') - config.set('Quick_config', 'Button12', '') - config.set('Quick_config', 'Button13', 'write 13,30500|气温校准') - config.set('Quick_config', 'Button14', 'write 14,1|滑动开关') - config.set('Quick_config', 'Button15', 'write 15,10|滑动标准差') - config.set('Quick_config', 'Button16', 'write 16,1|浓度温补') - config.set('Quick_config', 'Button17', '') - config.set('Quick_config', 'Button18', '') - config.set('Quick_config', 'Button19', '') - with open(self.regularIniPath, 'w' ,encoding='utf-8') as f: - config.write(f) - - config = ConfigParser() - config.read(self.regularIniPath, encoding='utf-8') - try: - self.headStr = config.get('TF_config', 'headStr') - self.regex = re.compile(config.get('TF_config', 'regular')) - self.rowTitleStr = config.get('TF_config', 'rowTitle') - - self.rowTitle = self.rowTitleStr.split(',') - print(type(self.rowTitle)) - print(f"Configuration read successfully: {self.headStr}, {self.regex}, {self.rowTitle}") - - # 创建一个空字典来存储按钮名称和对应的配置 - - - # 循环遍历按钮编号,从0到19 - for i in range(20): - button_name = f'Button{i:02}' # 格式化按钮名称,确保两位数 - # 使用 get 方法安全地获取配置,如果不存在则返回空字符串 - config_value = config.get('Quick_config', button_name, fallback='') - config_value_split = config_value.split('|') - # 将按钮名称和配置信息存储在字典中 - self.buttons_config[i][0] = button_name - if len(config_value_split) == 2: - self.buttons_config[i][1] = config_value_split[0] - self.buttons_config[i][2] = config_value_split[1] - - # 打印字典查看结果 - for i in range(20): - print(f'{self.buttons_config[i][0]}: {self.buttons_config[i][1]}|{self.buttons_config[i][2]}') - - except Exception as e: - print(f"Error reading configuration: {e}") - - def SetCfgIniData(self,button_name,set_text): - config = ConfigParser() - config.read(self.regularIniPath, encoding='utf-8') - config.set('Quick_config', button_name, set_text) - with open(self.regularIniPath, 'w' ,encoding='utf-8') as f: - config.write(f) - - -class GetDataOther(): #读取费加罗或者自定义数据 - def __init__(self, parent=None): - super().__init__() - self.indOfReturn =0 - #self.regex = re.compile(r'(A\+|B\+|\s)+') # 编译正则表达式 - self.TIME_FORMAT = "%Y-%m-%d %H:%M:%S" - self.OtherIniPath = "OtherData.ini" # 配置文件默认路径 - self.headStr = "" - self.rowTitle=[] - self.CheckCfgIniData() # 初始化配置文件 - def Transdata(self,data): - if data[:2] ==self.headStr: - - self.data2csv = self.regex.findall(data) - - returnData = float(self.data2csv[self.indOfReturn]) - print("returnData",returnData) - return returnData - else: - return "noNum" - - def SaveCsv(self,filenameCsv): - # 打开一个文件用于写入,如果文件不存在则创建 - if os.path.isfile(filenameCsv) == 0: - # 文件为空,需要写入表头 - - with open(filenameCsv, mode='w', newline='') as file: - writer = csv.writer(file) - #writer.writerow(('time', 'Methane', 'Air Temp', 'Laser Temp', 'Laser Intensity')) - - writer.writerow(self.rowTitle) - else: - with open(filenameCsv, mode='a', newline='') as file: - # 创建一个写入器对象 - writer = csv.writer(file) - # 写入数据行 - timeCrvt=time.strftime(self.TIME_FORMAT, time.localtime()) - self.data2csv.insert(0, timeCrvt) - print(self.data2csv) - writer.writerows([self.data2csv]) - - def IndOfReturn(self,ind): - self.indOfReturn = ind - - def CheckCfgIniData(self): - if not os.path.exists(self.OtherIniPath): - config = ConfigParser() - config.add_section('OtherData_config') - config.set('OtherData_config', 'regular', '\+?-?\d+(?:\.\d+)?') - # config.set('TF_config', 'regular', '(A\+|B\+|\s)+') - config.set('OtherData_config', 'headStr', 'A+') - config.set('OtherData_config', 'rowTitle', 'time,DATA1,DATA2') - - with open(self.OtherIniPath, 'w') as f: - config.write(f) - - config = ConfigParser() - config.read(self.OtherIniPath, encoding='utf-8') - try: - self.headStr = config.get('OtherData_config', 'headStr') - self.regex = re.compile(config.get('OtherData_config', 'regular')) - self.rowTitleStr = config.get('OtherData_config', 'rowTitle') - self.rowTitle = self.rowTitleStr.split(',') - print(type(self.rowTitle)) - print(f"Configuration read successfully: {self.headStr}, {self.regex}, {self.rowTitle}") - except Exception as e: - print(f"Error reading configuration: {e}")