diff --git a/PyMaiHak/.idea/PyMaiHak.iml b/PyMaiHak/.idea/PyMaiHak.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/PyMaiHak/.idea/PyMaiHak.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/PyNetAssistant_Sever/.idea/.gitignore b/PyNetAssistant_Sever/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/PyNetAssistant_Sever/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/PyNetAssistant_Sever/.idea/PyNetAssistant.iml b/PyNetAssistant_Sever/.idea/PyNetAssistant.iml new file mode 100644 index 0000000..909438d --- /dev/null +++ b/PyNetAssistant_Sever/.idea/PyNetAssistant.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/PyNetAssistant_Sever/.idea/inspectionProfiles/Project_Default.xml b/PyNetAssistant_Sever/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..3dce9c6 --- /dev/null +++ b/PyNetAssistant_Sever/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/PyNetAssistant_Sever/.idea/inspectionProfiles/profiles_settings.xml b/PyNetAssistant_Sever/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/PyNetAssistant_Sever/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/PyNetAssistant_Sever/.idea/misc.xml b/PyNetAssistant_Sever/.idea/misc.xml new file mode 100644 index 0000000..a6218fe --- /dev/null +++ b/PyNetAssistant_Sever/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/PyNetAssistant_Sever/.idea/modules.xml b/PyNetAssistant_Sever/.idea/modules.xml new file mode 100644 index 0000000..17c958b --- /dev/null +++ b/PyNetAssistant_Sever/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/PyNetAssistant_Sever/.idea/vcs.xml b/PyNetAssistant_Sever/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/PyNetAssistant_Sever/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PyNetAssistant_Sever/NetDataSplit.py b/PyNetAssistant_Sever/NetDataSplit.py new file mode 100644 index 0000000..80a1a81 --- /dev/null +++ b/PyNetAssistant_Sever/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_Sever/PyNet.ini b/PyNetAssistant_Sever/PyNet.ini new file mode 100644 index 0000000..e72be59 --- /dev/null +++ b/PyNetAssistant_Sever/PyNet.ini @@ -0,0 +1,220 @@ +[UI_config] +port = 10086 +hex_send = 0 +hex_receive = 0 +add_date = 0 +cr_lf = 2 +auto_sav_log = 2 +send_sever = 2 + +[Modbus_config] +funcode = F4 +position = 5 +alarm_lim = 0 + +[Server_config] +nir_offset = 0 + +[DisHex_config] +row00 = |||||0 +row01 = |||||0 +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 = 10 +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_Sever/PyNetSever.build.zip b/PyNetAssistant_Sever/PyNetSever.build.zip new file mode 100644 index 0000000..884eba0 Binary files /dev/null and b/PyNetAssistant_Sever/PyNetSever.build.zip differ diff --git a/PyNetAssistant_Sever/PyNetSever.py b/PyNetAssistant_Sever/PyNetSever.py new file mode 100644 index 0000000..71159cd --- /dev/null +++ b/PyNetAssistant_Sever/PyNetSever.py @@ -0,0 +1,761 @@ +# -*- coding: utf-8 -*- +""" +Created on Sun Sep 29 09:01:22 2024 + +@author: WANGXIBAO +""" +import csv +import datetime +import os +import threading + +from flask import Flask, render_template +from flask_socketio import SocketIO + +os.environ['QT_OPENGL'] = 'software' # 强制使用软件渲染 +import re +import socket +import sys +import time + +from configparser import ConfigParser + +from PyQt5 import QtWidgets +from PyQt5.QtCore import QTimer +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__() + self.setupUi(self) + self.quick_num = 99 + self.init() #信号和槽 + + self.IniPath = "PyNet.ini" + self.log_time = 10 + self.funcode = "F4" + self.position = 5 + self.CheckCfgIniData() #更改按钮的文字 + self.log_count = 0 + 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.setPlainText("") + self.textEditReceive.setMaximumBlockCount(5000) + + self.textEditSend.setText("") + + self.get_all_local_ips() + + # 定时器接收数据 + #self.timer = QTimer() + self.timer: QTimer = QTimer() + #self.timer.timeout.connect(self.data_receive) + timeout_signal = self.timer + timeout_signal.timeout.connect(self.data_receive) + + #加载快捷指令 + self.widget_6.hide() + #加载快捷指令的按键值 + + # self.init_flask() #flask + # 初始化 Flask 在后台线程中 + threading.Thread(target=self.init_flask, daemon=True).start() + self.methane = 0 # 用于缓存 + self.co2 = 0 # 用于缓存 + self.ethane = 0 # 用于缓存 + self.temperature = 0 # 用于缓存 + self.nir_offset = 0 # 用于平移数据 + #建立信号与槽 + 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.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) + self.checkBoxReapitSend.stateChanged.connect(self.data_send_timer) + # 快捷指令扩展区域 + self.pushButton_expend.clicked.connect(self.adjust_sidebar) + # 清空网络通道列表 + self.pushButtonClearChannel.clicked.connect(self.channel_clear) + # 动态创建控件并存储引用 + for i in range(self.quick_num): # 从0到20 + index_str = f"{i:02}" # 确保编号为两位数字形式 + horizontalLayoutName = f"horizontalLayoutQuick_{index_str}" + horizontalLayout = QtWidgets.QHBoxLayout() + horizontalLayout.setObjectName(horizontalLayoutName) + + # 创建 QLineEdit 并设置动态属性 + lineEditName = f"lineEditQuick_{index_str}" + setattr(self, lineEditName, QtWidgets.QLineEdit(self.layoutWidget1)) + getattr(self, lineEditName).setObjectName(lineEditName) + horizontalLayout.addWidget(getattr(self, lineEditName)) + # 创建 QPushButton 并设置动态属性 + buttonName = f"pushButtonQuick_{index_str}" + setattr(self, buttonName, QtWidgets.QPushButton(self.layoutWidget1)) + 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)) + # 建立表格解析并显示hex + self.tableWidget.setRowCount(self.quick_num) + for i in range(self.quick_num): # 从0到20 + item = QtWidgets.QTableWidgetItem() + item.setCheckState(0) + self.tableWidget.setItem(i, 0, item) + + self.double_click_timers = {} # 存储双击定时器 + + #%% 重写关闭按钮 + def closeEvent(self, event): + + 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) + print(ip_addresses) + for ip in ip_addresses: + self.comboBox_localAddr.insertItem(0, ip) + self.comboBox_localAddr.setCurrentIndex(0) + + # 打开网络连接 + def open_net(self): + 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 + print("绑定地址", udp_addr) + try: + self.udp_socket.bind(udp_addr) + print("开始监听。。。") + # 设置套接字为非阻塞模式 + self.udp_socket.setblocking(False) + 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'): + self.timer.stop() + self.udp_socket.close() + #使能相关按钮 + self.pushButton_closeNet.setEnabled(False) + self.pushButton_openNet.setEnabled(True) + print("关闭网络连接") + + def set_textEditReceive_cursor(self): + # 获取到text光标 + textCursor = self.textEditReceive.textCursor() + # 滚动到底部 + textCursor.movePosition(textCursor.End) + # 设置光标到text中去 + self.textEditReceive.setTextCursor(textCursor) + + #接收数据 + 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().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') + + 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]) + if not self.is_in_comboBox_channel(recv_addr): + self.comboBox_channel.addItem(recv_addr) + # 在接收窗口显示 + # 获取到text光标 + self.set_textEditReceive_cursor() + #选择要显示的通道 + 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] + self.textEditReceive.insertPlainText(nowTime + " ") + #self.add_line_to_textedit(nowTime + " ") + # 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 + + # self.textEditReceive.insertPlainText(out_s) + self.textEditReceive.insertPlainText('<' + 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('<' + 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光标 + self.set_textEditReceive_cursor() + # 统计接收字符的数量 + self.data_num_received += num + self.lineEditReceiveNum.setText(str(self.data_num_received)) + + # 自动保存日志 + 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" + #当表示浓度的字符不为0时 将数据单独记录 + if int(line_utf8[14:18], 16) > self.alarm_lim: + sav_name_alarm = 'alarm_' + line_utf8[0:8] + '_' + datetime.datetime.now().strftime( + "%Y-%m-%d") + '.txt' + sav_str_alarm = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")[:23] + " " + out_s[ + 12:] + "\r\n" + with open(sav_name_alarm, mode='a', newline='', encoding='utf-8', errors='replace') as file: + file.writelines(sav_str_alarm) + + 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" + # Ascii 数据保存 + else: + 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.checkBoxSendSever.isChecked(): + self.send_data_to_server(line) + + 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] + " " + 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: + 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: + 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(): + input_s = input_s.strip() + send_list = [] + while input_s != '': + try: + num = int(input_s[0:2], 16) + except ValueError: + QMessageBox.critical(self, '串口异常', '请输入规范十六进制数据,以空格分开!') + return None + + input_s = input_s[2:].strip() + send_list.append(num) + + input_s = bytes(send_list) + # ASCII发送 + else: + input_s = (input_s).encode('utf-8') + input_s = re.sub(b'(? 1000: + current_lines = current_lines[-1000:] # 只保留最新的100行 + # 将更新后的行列表转换回字符串并设置为textEdit的内容 + self.textEditReceive.setPlainText('\n'.join(current_lines)) + + #检查是否在comboBox_channel中 + 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): + 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): + 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', 'send_sever', '0') + + # Modbus_config + config.add_section('Modbus_config') + config.set('Modbus_config', 'funcode', 'F4') #识别码 + config.set('Modbus_config', 'position', '5') #识别码所在位置 + config.set('Modbus_config', 'alarm_lim', '0') + # Server_config + config.add_section('Server_config') + config.set('Server_config', 'nir_offset','0') + #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: + config.write(f) + + # 读取数据 + try: + config = ConfigParser() + config.read(self.IniPath, encoding='utf-8') + # 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')) + send_sever = int(config.get('UI_config', 'send_sever')) + 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.checkBoxSendSever.setChecked(send_sever) + + # Modbus_config + self.funcode = config.get('Modbus_config', 'funcode') + self.position = int(config.get('Modbus_config', 'position')) + self.alarm_lim = int(config.get('Modbus_config', 'alarm_lim')) + + # Server_config + self.nir_offset = int(config.get('Server_config', 'nir_offset')) + + # 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): + idx = f'{i:02}' + button_name = f'Button{idx}' # 格式化按钮名称,确保两位数 + # 使用 get 方法安全地获取配置,如果不存在则返回空字符串 + config_value = config.get('Quick_config', button_name, fallback='') + config_value_split = config_value.split('|') + # 将按钮名称和配置信息存储在字典中 + if len(config_value_split) == 2: + # 打印字典查看结果,并赋值 + 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}") + QMessageBox.critical(self, "Error", f"Error reading configuration: {e}") + + def SavConfig(self): + #关闭界面前保存快捷区域的命令和名称 + config = ConfigParser() + config.read(self.IniPath, encoding='utf-8') + # 保存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', 'send_sever', str(self.checkBoxSendSever.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 + + if self.double_click_timers[idx] is None: + self.double_click_timers[idx] = True + QTimer.singleShot(200, lambda: self.onButtonSigleClick(idx)) + else: + self.onButtonDoubleClick(idx) + + def onButtonSigleClick(self, idx): + index_str = f"{idx:02}" + 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()}") + text = lineEdit.text() + if self.checkBox_return.isChecked(): + text = text + "\r\n" + self.data_send(text) + + def onButtonDoubleClick(self, idx): + # 槽函数处理按钮双击事件 + self.double_click_timers[idx] = None + index_str = f"{idx:02}" + print(f"Double click detected on Button {index_str}.") + button = getattr(self, f"pushButtonQuick_{index_str}") + new_name, ok = QInputDialog.getText(self, 'Button Rename', 'Enter new button name:') + if ok and new_name: + button.setText(new_name) + + + + + def init_flask(self): + # 创建Flask应用 + self.app = Flask(__name__) # 修改为实例变量 + self.app.config['SECRET_KEY'] = 'secret!' + self.socketio = SocketIO(self.app) + + # 主页路由 + @self.app.route('/') + def index(): + return render_template('index.html') + + # 启动Flask-SocketIO服务器 + self.socketio.run(self.app, host='0.0.0.0', port=8000, allow_unsafe_werkzeug=True) + + def send_data_to_server(self, data: list[str]): + + + if data[0] == 'Z02': + numbers = re.findall(r'-?\d+\.?\d*', data[1]) + if numbers: + # 假设我们只发送第一个数字,如果有多个数字可以根据需要处理 + self.co2 = float(numbers[0]) + self.socketio.emit('co2_data', {'value': self.co2}) + print(f"发送二氧化碳数据: {self.co2}") + else: + print("未找到有效的数字") + if data[0] == 'Z03': + numbers = re.findall(r'-?\d+\.?\d*', data[1]) + if len(numbers) > 1: + # 假设我们只发送第一个数字,如果有多个数字可以根据需要处理 + self.methane = int(float(numbers[0]) * 10000) + self.socketio.emit('methane_data', {'value': self.methane}) + print(f"发送甲烷数据: {self.methane}") + self.temperature = float(numbers[1]) + self.socketio.emit('temperature_data', {'value': self.temperature}) + print(f"发送温度数据: {self.temperature}") + else: + print("未找到有效的数字") + if data[0] == 'Z01': + numbers = re.findall(r'-?\d+\.?\d*', data[1]) + if numbers: + # 假设我们只发送第一个数字,如果有多个数字可以根据需要处理 0.6457 0.8 + methane_nir = float(numbers[0]) + delta = int((methane_nir*0.55 + 2000 - self.methane) /4 + self.nir_offset) + if delta <= 600: + self.ethane = 0 + else: + self.ethane = delta + + self.socketio.emit('ethane_data', {'value': self.ethane}) + print(f"发送乙烷数据: {self.ethane}") + self.sav_multi_csv() # 乙烷数据更新时保存一次数据 + else: + print("未找到有效的数字") + + def sav_multi_csv(self): + filename = f"{datetime.datetime.now().strftime('%Y-%m-%d')}.csv" + timestamp = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')[:23] + + with open(filename, mode='a', newline='', encoding='utf-8') as file: + writer = csv.writer(file) + # 写入表头 + if file.tell() == 0: + writer.writerow(['time', 'Temperature', 'Methane', 'Ethane', 'CO2']) + # 写入数据 + writer.writerow([timestamp, self.temperature, self.methane, self.ethane, self.co2]) + +#执行 +if __name__ == '__main__': + app = QtWidgets.QApplication(sys.argv) + myshow = Pyqt5Net() + myshow.show() + sys.exit(app.exec_()) diff --git a/PyNetAssistant_Sever/PyNetUi.py b/PyNetAssistant_Sever/PyNetUi.py new file mode 100644 index 0000000..40601a3 --- /dev/null +++ b/PyNetAssistant_Sever/PyNetUi.py @@ -0,0 +1,418 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'PyNetUi.ui' +# +# Created by: PyQt5 UI code generator 5.15.10 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_UartAssistant(object): + def setupUi(self, UartAssistant): + UartAssistant.setObjectName("UartAssistant") + UartAssistant.resize(956, 650) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(2) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(UartAssistant.sizePolicy().hasHeightForWidth()) + UartAssistant.setSizePolicy(sizePolicy) + UartAssistant.setAcceptDrops(True) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap("favicon.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + UartAssistant.setWindowIcon(icon) + 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) + self.horizontalLayout_14.setObjectName("horizontalLayout_14") + self.splitter = QtWidgets.QSplitter(self.widget_7) + self.splitter.setMaximumSize(QtCore.QSize(16777215, 16777215)) + self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setHandleWidth(5) + self.splitter.setObjectName("splitter") + self.widget_4 = QtWidgets.QWidget(self.splitter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widget_4.sizePolicy().hasHeightForWidth()) + self.widget_4.setSizePolicy(sizePolicy) + self.widget_4.setMinimumSize(QtCore.QSize(230, 0)) + self.widget_4.setObjectName("widget_4") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget_4) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setSpacing(0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.widget = QtWidgets.QWidget(self.widget_4) + self.widget.setObjectName("widget") + self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.widget) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.groupBox = QtWidgets.QGroupBox(self.widget) + self.groupBox.setMinimumSize(QtCore.QSize(0, 0)) + self.groupBox.setBaseSize(QtCore.QSize(271, 291)) + self.groupBox.setObjectName("groupBox") + self.layoutWidget = QtWidgets.QWidget(self.groupBox) + self.layoutWidget.setGeometry(QtCore.QRect(10, 20, 201, 201)) + self.layoutWidget.setObjectName("layoutWidget") + self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.verticalLayout.setObjectName("verticalLayout") + self.label = QtWidgets.QLabel(self.layoutWidget) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.comboBox_protocol = QtWidgets.QComboBox(self.layoutWidget) + self.comboBox_protocol.setObjectName("comboBox_protocol") + self.comboBox_protocol.addItem("") + self.verticalLayout.addWidget(self.comboBox_protocol) + self.label_2 = QtWidgets.QLabel(self.layoutWidget) + self.label_2.setObjectName("label_2") + self.verticalLayout.addWidget(self.label_2) + self.comboBox_localAddr = QtWidgets.QComboBox(self.layoutWidget) + self.comboBox_localAddr.setToolTipDuration(0) + self.comboBox_localAddr.setEditable(True) + self.comboBox_localAddr.setObjectName("comboBox_localAddr") + self.comboBox_localAddr.addItem("") + self.comboBox_localAddr.addItem("") + self.verticalLayout.addWidget(self.comboBox_localAddr) + self.label_3 = QtWidgets.QLabel(self.layoutWidget) + self.label_3.setObjectName("label_3") + self.verticalLayout.addWidget(self.label_3) + self.lineEdit_port = QtWidgets.QLineEdit(self.layoutWidget) + self.lineEdit_port.setObjectName("lineEdit_port") + self.verticalLayout.addWidget(self.lineEdit_port) + self.pushButton_openNet = QtWidgets.QPushButton(self.layoutWidget) + self.pushButton_openNet.setStyleSheet("background-color: rgb(0, 255, 0);") + self.pushButton_openNet.setObjectName("pushButton_openNet") + self.verticalLayout.addWidget(self.pushButton_openNet) + self.pushButton_closeNet = QtWidgets.QPushButton(self.layoutWidget) + self.pushButton_closeNet.setObjectName("pushButton_closeNet") + self.verticalLayout.addWidget(self.pushButton_closeNet) + self.verticalLayout_5.addWidget(self.groupBox) + self.groupBox_2 = QtWidgets.QGroupBox(self.widget) + self.groupBox_2.setMinimumSize(QtCore.QSize(0, 0)) + self.groupBox_2.setBaseSize(QtCore.QSize(271, 165)) + self.groupBox_2.setObjectName("groupBox_2") + self.layoutWidget_5 = QtWidgets.QWidget(self.groupBox_2) + self.layoutWidget_5.setGeometry(QtCore.QRect(10, 20, 197, 79)) + self.layoutWidget_5.setObjectName("layoutWidget_5") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.layoutWidget_5) + self.verticalLayout_6.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.horizontalLayout_10 = QtWidgets.QHBoxLayout() + self.horizontalLayout_10.setObjectName("horizontalLayout_10") + self.checkBoxHexSend = QtWidgets.QCheckBox(self.layoutWidget_5) + self.checkBoxHexSend.setObjectName("checkBoxHexSend") + self.horizontalLayout_10.addWidget(self.checkBoxHexSend) + self.checkBoxHexReceive = QtWidgets.QCheckBox(self.layoutWidget_5) + self.checkBoxHexReceive.setObjectName("checkBoxHexReceive") + self.horizontalLayout_10.addWidget(self.checkBoxHexReceive) + self.verticalLayout_6.addLayout(self.horizontalLayout_10) + self.horizontalLayout_12 = QtWidgets.QHBoxLayout() + self.horizontalLayout_12.setObjectName("horizontalLayout_12") + self.checkBoxAddDate = QtWidgets.QCheckBox(self.layoutWidget_5) + self.checkBoxAddDate.setObjectName("checkBoxAddDate") + self.horizontalLayout_12.addWidget(self.checkBoxAddDate) + self.checkBoxCRLF = QtWidgets.QCheckBox(self.layoutWidget_5) + self.checkBoxCRLF.setObjectName("checkBoxCRLF") + self.horizontalLayout_12.addWidget(self.checkBoxCRLF) + self.verticalLayout_6.addLayout(self.horizontalLayout_12) + self.layoutWidget_6 = QtWidgets.QWidget(self.groupBox_2) + self.layoutWidget_6.setGeometry(QtCore.QRect(10, 130, 195, 30)) + self.layoutWidget_6.setObjectName("layoutWidget_6") + self.horizontalLayout_13 = QtWidgets.QHBoxLayout(self.layoutWidget_6) + self.horizontalLayout_13.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_13.setObjectName("horizontalLayout_13") + self.pushButtonLogSave = QtWidgets.QPushButton(self.layoutWidget_6) + self.pushButtonLogSave.setObjectName("pushButtonLogSave") + self.horizontalLayout_13.addWidget(self.pushButtonLogSave) + self.pushButtonLogLoad = QtWidgets.QPushButton(self.layoutWidget_6) + self.pushButtonLogLoad.setObjectName("pushButtonLogLoad") + self.horizontalLayout_13.addWidget(self.pushButtonLogLoad) + 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.checkBoxSendSever = QtWidgets.QCheckBox(self.layoutWidget1) + self.checkBoxSendSever.setChecked(False) + self.checkBoxSendSever.setObjectName("checkBoxSendSever") + self.horizontalLayout_4.addWidget(self.checkBoxSendSever) + self.verticalLayout_5.addWidget(self.groupBox_2) + self.groupBox_3 = QtWidgets.QGroupBox(self.widget) + self.groupBox_3.setMinimumSize(QtCore.QSize(0, 0)) + self.groupBox_3.setBaseSize(QtCore.QSize(271, 80)) + self.groupBox_3.setObjectName("groupBox_3") + self.checkBoxReapitSend = QtWidgets.QCheckBox(self.groupBox_3) + self.checkBoxReapitSend.setGeometry(QtCore.QRect(10, 30, 91, 19)) + self.checkBoxReapitSend.setObjectName("checkBoxReapitSend") + self.label_7 = QtWidgets.QLabel(self.groupBox_3) + self.label_7.setGeometry(QtCore.QRect(170, 30, 51, 16)) + self.label_7.setObjectName("label_7") + self.lineEditTime = QtWidgets.QLineEdit(self.groupBox_3) + self.lineEditTime.setGeometry(QtCore.QRect(110, 30, 51, 21)) + self.lineEditTime.setObjectName("lineEditTime") + self.verticalLayout_5.addWidget(self.groupBox_3) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_5.addItem(spacerItem) + self.groupBox_6 = QtWidgets.QGroupBox(self.widget) + self.groupBox_6.setMinimumSize(QtCore.QSize(0, 0)) + self.groupBox_6.setBaseSize(QtCore.QSize(281, 80)) + self.groupBox_6.setTitle("") + self.groupBox_6.setObjectName("groupBox_6") + self.label_9 = QtWidgets.QLabel(self.groupBox_6) + self.label_9.setGeometry(QtCore.QRect(120, 20, 72, 15)) + self.label_9.setObjectName("label_9") + self.lineEditSendNum = QtWidgets.QLineEdit(self.groupBox_6) + self.lineEditSendNum.setGeometry(QtCore.QRect(40, 20, 61, 21)) + self.lineEditSendNum.setObjectName("lineEditSendNum") + self.lineEditReceiveNum = QtWidgets.QLineEdit(self.groupBox_6) + self.lineEditReceiveNum.setGeometry(QtCore.QRect(140, 20, 61, 21)) + self.lineEditReceiveNum.setObjectName("lineEditReceiveNum") + self.label_10 = QtWidgets.QLabel(self.groupBox_6) + self.label_10.setGeometry(QtCore.QRect(20, 40, 131, 16)) + self.label_10.setObjectName("label_10") + self.label_SendNum = QtWidgets.QLabel(self.groupBox_6) + self.label_SendNum.setGeometry(QtCore.QRect(20, 20, 72, 15)) + self.label_SendNum.setObjectName("label_SendNum") + self.verticalLayout_5.addWidget(self.groupBox_6) + self.verticalLayout_5.setStretch(0, 8) + self.verticalLayout_5.setStretch(1, 6) + self.verticalLayout_5.setStretch(2, 2) + self.verticalLayout_5.setStretch(4, 2) + self.horizontalLayout.addWidget(self.widget) + self.widget_5 = QtWidgets.QWidget(self.splitter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widget_5.sizePolicy().hasHeightForWidth()) + self.widget_5.setSizePolicy(sizePolicy) + self.widget_5.setMinimumSize(QtCore.QSize(400, 0)) + self.widget_5.setObjectName("widget_5") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.widget_5) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + 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.QPlainTextEdit(self.tab1) + self.textEditReceive.setSizeIncrement(QtCore.QSize(0, 0)) + self.textEditReceive.setObjectName("textEditReceive") + 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(6) + 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() + self.tableWidget.setHorizontalHeaderItem(4, item) + item = QtWidgets.QTableWidgetItem() + item.setBackground(QtGui.QColor(172, 172, 172)) + self.tableWidget.setHorizontalHeaderItem(5, 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") + self.comboBox_channel = QtWidgets.QComboBox(self.groupBox_7) + self.comboBox_channel.setEditable(True) + self.comboBox_channel.setObjectName("comboBox_channel") + self.comboBox_channel.addItem("") + self.horizontalLayout_3.addWidget(self.comboBox_channel) + self.pushButtonClearChannel = QtWidgets.QPushButton(self.groupBox_7) + self.pushButtonClearChannel.setObjectName("pushButtonClearChannel") + self.horizontalLayout_3.addWidget(self.pushButtonClearChannel) + 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.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") + font.setPointSize(12) + self.pushButtonSend.setFont(font) + self.pushButtonSend.setAutoFillBackground(False) + self.pushButtonSend.setStyleSheet("background-color: rgb(0, 255, 0);") + self.pushButtonSend.setCheckable(False) + self.pushButtonSend.setFlat(False) + self.pushButtonSend.setObjectName("pushButtonSend") + self.gridLayout.addWidget(self.pushButtonSend, 4, 1, 1, 1) + self.verticalLayout_3.addWidget(self.groupBox_5) + self.verticalLayout_3.setStretch(0, 7) + self.verticalLayout_3.setStretch(1, 1) + self.verticalLayout_3.setStretch(2, 2) + self.widget_6 = QtWidgets.QWidget(self.splitter) + self.widget_6.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widget_6.sizePolicy().hasHeightForWidth()) + self.widget_6.setSizePolicy(sizePolicy) + self.widget_6.setMinimumSize(QtCore.QSize(280, 0)) + self.widget_6.setObjectName("widget_6") + self.horizontalLayout_16 = QtWidgets.QHBoxLayout(self.widget_6) + self.horizontalLayout_16.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_16.setSpacing(0) + self.horizontalLayout_16.setObjectName("horizontalLayout_16") + self.scrollArea = QtWidgets.QScrollArea(self.widget_6) + self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) + self.scrollArea.setWidgetResizable(False) + self.scrollArea.setObjectName("scrollArea") + self.scrollAreaWidgetContents = QtWidgets.QWidget() + 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)) + self.widget_8.setObjectName("widget_8") + self.horizontalLayout_17 = QtWidgets.QHBoxLayout(self.widget_8) + self.horizontalLayout_17.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_17.setObjectName("horizontalLayout_17") + self.label_8 = QtWidgets.QLabel(self.widget_8) + self.label_8.setObjectName("label_8") + self.horizontalLayout_17.addWidget(self.label_8) + self.checkBox_return = QtWidgets.QCheckBox(self.widget_8) + self.checkBox_return.setChecked(True) + self.checkBox_return.setObjectName("checkBox_return") + self.horizontalLayout_17.addWidget(self.checkBox_return) + self.widget_9 = QtWidgets.QWidget(self.scrollAreaWidgetContents) + self.widget_9.setGeometry(QtCore.QRect(10, 40, 231, 3000)) + self.widget_9.setObjectName("widget_9") + 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_2.addWidget(self.widget_7) + + self.retranslateUi(UartAssistant) + self.comboBox_localAddr.setCurrentIndex(0) + self.tabWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(UartAssistant) + + def retranslateUi(self, UartAssistant): + _translate = QtCore.QCoreApplication.translate + UartAssistant.setWindowTitle(_translate("UartAssistant", "串口助手py版")) + self.groupBox.setTitle(_translate("UartAssistant", "网络设置")) + self.label.setText(_translate("UartAssistant", "协议类型")) + self.comboBox_protocol.setItemText(0, _translate("UartAssistant", "UDP")) + self.label_2.setText(_translate("UartAssistant", "本地主机地址")) + self.comboBox_localAddr.setCurrentText(_translate("UartAssistant", "127.0.0.1")) + self.comboBox_localAddr.setItemText(0, _translate("UartAssistant", "127.0.0.1")) + self.comboBox_localAddr.setItemText(1, _translate("UartAssistant", "0.0.0.0")) + self.label_3.setText(_translate("UartAssistant", "本地主机端口")) + self.lineEdit_port.setText(_translate("UartAssistant", "9000")) + self.pushButton_openNet.setText(_translate("UartAssistant", "打开网络")) + self.pushButton_closeNet.setText(_translate("UartAssistant", "关闭网络")) + self.groupBox_2.setTitle(_translate("UartAssistant", "收发设置")) + self.checkBoxHexSend.setText(_translate("UartAssistant", "HEX发送")) + self.checkBoxHexReceive.setText(_translate("UartAssistant", "HEX接收")) + self.checkBoxAddDate.setText(_translate("UartAssistant", "收/发时间")) + self.checkBoxCRLF.setText(_translate("UartAssistant", "收发换行")) + self.pushButtonLogSave.setText(_translate("UartAssistant", "保存日志")) + self.pushButtonLogLoad.setText(_translate("UartAssistant", "加载日志")) + self.checkBoxAutoSaveLog.setText(_translate("UartAssistant", "自动保存日志")) + self.checkBoxSendSever.setText(_translate("UartAssistant", "启动服务")) + self.groupBox_3.setTitle(_translate("UartAssistant", "定时发送")) + self.checkBoxReapitSend.setText(_translate("UartAssistant", "定时发送")) + self.label_7.setText(_translate("UartAssistant", "ms/次")) + self.lineEditTime.setText(_translate("UartAssistant", "1000")) + self.label_9.setText(_translate("UartAssistant", "Rx")) + self.label_10.setText(_translate("UartAssistant", "Powerd by Byan")) + self.label_SendNum.setText(_translate("UartAssistant", "Tx")) + 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", "hex")) + item = self.tableWidget.horizontalHeaderItem(5) + 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.pushButton_expend.setText(_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_Sever/PyNetUi.ui b/PyNetAssistant_Sever/PyNetUi.ui new file mode 100644 index 0000000..a8faa40 --- /dev/null +++ b/PyNetAssistant_Sever/PyNetUi.ui @@ -0,0 +1,853 @@ + + + UartAssistant + + + + 0 + 0 + 956 + 650 + + + + + 2 + 0 + + + + true + + + 串口助手py版 + + + + favicon.icofavicon.ico + + + + + + + + + + 16777215 + 16777215 + + + + Qt::Horizontal + + + 5 + + + + + 0 + 0 + + + + + 230 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + 0 + 0 + + + + + 271 + 291 + + + + 网络设置 + + + + + 10 + 20 + 201 + 201 + + + + + + + 协议类型 + + + + + + + + UDP + + + + + + + + 本地主机地址 + + + + + + + 0 + + + true + + + 127.0.0.1 + + + 0 + + + + 127.0.0.1 + + + + + 0.0.0.0 + + + + + + + + 本地主机端口 + + + + + + + 9000 + + + + + + + background-color: rgb(0, 255, 0); + + + 打开网络 + + + + + + + 关闭网络 + + + + + + + + + + + + 0 + 0 + + + + + 271 + 165 + + + + 收发设置 + + + + + 10 + 20 + 197 + 79 + + + + + + + + + HEX发送 + + + + + + + HEX接收 + + + + + + + + + + + 收/发时间 + + + + + + + 收发换行 + + + + + + + + + + + 10 + 130 + 195 + 30 + + + + + + + 保存日志 + + + + + + + 加载日志 + + + + + + + + + 12 + 100 + 191 + 31 + + + + + + + 自动保存日志 + + + true + + + + + + + 启动服务 + + + false + + + + + + + + + + + + 0 + 0 + + + + + 271 + 80 + + + + 定时发送 + + + + + 10 + 30 + 91 + 19 + + + + 定时发送 + + + + + + 170 + 30 + 51 + 16 + + + + ms/次 + + + + + + 110 + 30 + 51 + 21 + + + + 1000 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 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 + + + + + 400 + 0 + + + + + + + 0 + + + + Qt::TabFocus + + + 数据 + + + + + + + 0 + 0 + + + + + + + + + true + + + Qt::NoFocus + + + 解析 + + + + + + Qt::SolidLine + + + 10 + + + 6 + + + false + + + 20 + + + 50 + + + true + + + true + + + false + + + false + + + 25 + + + + + + + + + + + + + + select + + + + 172 + 172 + 172 + + + + + + start + + + + 172 + 172 + 172 + + + + + + num + + + + 172 + 172 + 172 + + + + + + scale + + + + + hex + + + + + value + + + + 172 + 172 + 172 + + + + + + + + + + + + + 选择通道 + + + + + + true + + + + ALL + + + + + + + + 清空 + + + + + + + + + + 数据发送区 + + + + + + + + + 快捷指令 + + + + + + + 清除接收 + + + + + + + 清除发送 + + + + + + + + + + 发送全部通道 + + + + + + + 附加校验 + + + + + + + + + + + 3ds + 12 + + + + false + + + background-color: rgb(0, 255, 0); + + + 发送 + + + false + + + false + + + + + + + + + + + true + + + + 0 + 0 + + + + + 280 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::ScrollBarAlwaysOn + + + false + + + + + 0 + 0 + 241 + 3000 + + + + + + 12 + 2 + 221 + 34 + + + + + + + 快捷指令 + + + + + + + 添加"\r\n" + + + true + + + + + + + + + 10 + 40 + 231 + 3000 + + + + + + 12 + 12 + 218 + 2941 + + + + + QLayout::SetMaximumSize + + + + + + + + + + + + + + + + + + + diff --git a/PyNetAssistant_Sever/PyUart.py b/PyNetAssistant_Sever/PyUart.py new file mode 100644 index 0000000..24cbfba --- /dev/null +++ b/PyNetAssistant_Sever/PyUart.py @@ -0,0 +1,670 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon May 27 14:31:38 2024 + +@author: WANGXIBAO +""" + +import sys +import serial,re +import serial.tools.list_ports +import time,datetime + +from PyQt5 import QtWidgets +from PyQt5.QtWidgets import QMessageBox ,QFileDialog,QInputDialog +from PyQt5.QtCore import QTimer +from PyUartUi import Ui_UartAssistant +from PyQt5.QtGui import QIcon + + +class PyQt5Serial(QtWidgets.QWidget,Ui_UartAssistant): + # %%初始化程序 + def __init__(self): + super(PyQt5Serial, self).__init__() + self.setupUi(self) + + + + + + self.init() + self.ser = serial.Serial() #创建一个空对象 + self.port_check() + + # 设置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.pushButtonCloseSerial.setEnabled(False) + + # 发送框、文本框清除 + self.textEditReceive.setText("") + self.textEditSend.setText("") + # %%第二个TAB 初始化画图页面表格 + + + # 加载Qchart波形界面 + + + #加载快捷指令 + self.widget_6.hide() + #加载快捷指令的按键值 + + + + + # 用于暂存接收的串口数据 + self.buffer = b'' + # 用于暂存解码数据 + self.lineUtf8 = "" + # 用于标志是否开始存CSV + self.CsvFlag = 0 + # ============================================================================= +# def wheelEvent(self, event): +# if self.plot_view.underMouse: +# # 鼠标滚轮:缩放Qchart波形 +# if event.angleDelta().y() >= 0: +# # 鼠标滚轮向上 +# if event.x() < ( +# self.plot_view.width() + self.plot_view.x()) and event.x() > self.plot_view.x(): +# if event.y() < ( +# self.plot_view.height() + self.plot_view.y()) and event.y() > self.plot_view.y(): +# self.plot_qchart.zoomIn() +# else: +# # 鼠标滚轮向下 +# if event.x() < ( +# self.plot_view.width() + self.plot_view.x()) and event.x() > self.plot_view.x(): +# if event.y() < ( +# self.plot_view.height() + self.plot_view.y()) and event.y() > self.plot_view.y(): +# self.plot_qchart.zoomOut() +# ============================================================================= + #%% 重写关闭按钮 + def closeEvent(self, event): + self.update_data_thread.stop() + # 可选:加入超时判断,防止线程未能正常退出导致程序无法关闭 + if not self.update_data_thread.wait(1000): # 等待5秒 + print("线程未在指定时间内退出,可能需要进一步处理") + + + # 如果串口已经打开,则关闭串口 + if self.ser.is_open: + self.port_close() + + #关闭界面前保存快捷区域的命令和名称 + for i in range(20): # 假设有20个按钮 + button_name = f'Button{i:02}' # 格式化按钮名称,确保两位数 + set_text = getattr(self, f'lineEditQuick_{i+1}').text()+ "|" + getattr(self, f'pushButtonQuick_{i+1}').text() + self.get_data_tf.SetCfgIniData(button_name, set_text) + + + + + # 调用父类的关闭事件处理函数 + super().closeEvent(event) + + + + + # %%建立控件信号与槽关系 + def init(self): + # 串口检测按钮 + self.pushButtonTestSerial.clicked.connect(self.port_check) + # 串口打开按钮 + self.pushButtonOpenSerial.clicked.connect(self.port_open) + # 串口关闭按钮 + self.pushButtonCloseSerial.clicked.connect(self.port_close) + + # 定时发送数据 + self.timer_send = QTimer() + self.timer_send.timeout.connect(self.data_send) + self.checkBoxReapitSend.stateChanged.connect(self.data_send_timer) + + # 发送数据按钮 + self.pushButtonSend.clicked.connect(lambda:self.data_send(text_quick= None)) + + # 保存日志 + self.pushButtonLogSave.clicked.connect(self.savefiles) + # 加载日志 + self.pushButtonLogLoad.clicked.connect(self.openfiles) + + # 跳转链接 + #self.commandLinkButton1.clicked.connect(self.link) + + # 清除发送按钮 + self.pushButtonClearSend.clicked.connect(self.send_data_clear) + + # 清除接收按钮 + self.pushButtonClearReceive.clicked.connect(self.receive_data_clear) + + + + + # 快捷指令扩展区域 + self.pushButton_expend.clicked.connect(self.adjust_sidebar) + # 创建一个通用的槽函数来处理所有按钮 +# 例如,使用lambda表达式传递额外的参数 + for i in range(1, 21): # 假设有20个按钮 + # getattr(self, f'pushButtonQuick_{i}').clicked.connect( + # lambda checked, line_edit=f'lineEditQuick_{i}': self.onPushButtonQuickClicked(line_edit) + # ) + # 连接左键点击事件 + button = getattr(self, f'pushButtonQuick_{i}') + line_edit = f'lineEditQuick_{i}' + button.clicked.connect(lambda checked, line_edit=line_edit: self.onPushButtonQuickClicked(line_edit)) + + # 连接右键点击事件 + # button_id = f'pushButtonQuick_{i}' + # button.setContextMenuPolicy(Qt.CustomContextMenu) + # button.customContextMenuRequested.connect(lambda position, button_id=button_id: self.onButtonRightClicked(button_id)) + + # %% 串口检测 + def port_check(self): + # 检测所有存在的串口,将信息存储在字典中 + self.Com_Dict = {} + port_list = list(serial.tools.list_ports.comports()) + + self.comboBoxSerial.clear() + for port in port_list: + self.Com_Dict["%s" % port[0]] = "%s" % port[1] + self.comboBoxSerial.addItem(port[0]) + + # 无串口判断 + if len(self.Com_Dict) == 0: + self.comboBoxSerial.addItem("无串口") + # %%打开串口 + def port_open(self): + self.ser.port = self.comboBoxSerial.currentText() # 串口号 + self.ser.baudrate = int(self.comboBoxBaudrate.currentText()) # 波特率 + self.ser.timeout = 0.01 + + + + flag_data = int(self.comboBoxDataBits.currentText()) # 数据位 + if flag_data == 5: + self.ser.bytesize = serial.FIVEBITS + elif flag_data == 6: + self.ser.bytesize = serial.SIXBITS + elif flag_data == 7: + self.ser.bytesize = serial.SEVENBITS + else: + self.ser.bytesize = serial.EIGHTBITS + + flag_data = self.comboBoxCheckBit.currentText() # 校验位 + if flag_data == "None": + self.ser.parity = serial.PARITY_NONE + elif flag_data == "Odd": + self.ser.parity = serial.PARITY_ODD + else: + self.ser.parity = serial.PARITY_EVEN + + flag_data = int(self.comboBoxStopBit.currentText()) # 停止位 + if flag_data == 1: + self.ser.stopbits = serial.STOPBITS_ONE + else: + self.ser.stopbits = serial.STOPBITS_TWO + + flag_data = self.comboBoxFlow.currentText() # 流控 + if flag_data == "No Ctrl Flow": + self.ser.xonxoff = False #软件流控 + self.ser.dsrdtr = False #硬件流控 DTR + self.ser.rtscts = False #硬件流控 RTS + elif flag_data == "SW Ctrl Flow": + self.ser.xonxoff = True #软件流控 + else: + if self.checkBoxDTR.isChecked(): + self.ser.dsrdtr = True #硬件流控 DTR + if self.checkBoxRTS.isChecked(): + self.ser.rtscts = True #硬件流控 RTS + try: + time.sleep(0.1) + if self.ser.is_open: + self.ser.close() + self.ser.open() + except: + QMessageBox.critical(self, "串口异常", "此串口不能被打开!") + return None + + # 串口打开后,切换开关串口按钮使能状态,防止失误操作 + if self.ser.isOpen(): + self.pushButtonOpenSerial.setEnabled(False) + self.pushButtonCloseSerial.setEnabled(True) + self.comboBoxBaudrate.setEnabled(False) + self.comboBoxSerial.setEnabled(False) + self.pushButton_expend.setEnabled(True) + #self.formGroupBox1.setTitle("串口状态(开启)") + + #日志保存 + # 格式化日期时间字符串,用于文件名 + # 例如:2024-05-28_12-34-56.txt + self.file = self.ser.port+"-"+time.strftime("%Y%m%d%H%M%S", time.localtime()) + self.filename = self.file + ".txt" + + + # 定时器接收数据 + self.timer = QTimer() + self.timer.timeout.connect(self.data_receive) + # 打开串口接收定时器,周期为1ms + self.timer.start(20) + + # %%接收数据 + def data_receive(self): + + try: + num = self.ser.inWaiting() + + + if num>0 : + #print("接收数据",datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) + try: + data = self.ser.read(num) + except: + QMessageBox.critical(self, '串口异常') + self.buffer+=data + + #print("接收完成",datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) + + if self.checkBoxAddDate.isChecked(): + nowTime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f") + nowTime = nowTime[:-3] + self.textEditReceive.insertPlainText(nowTime + " ") + + # HEX显示数据 + if self.checkBoxHexReceive.checkState(): + out_s = '' + for i in range(0, len(data)): + out_s = out_s + '{:02X}'.format(data[i]) + ' ' + + self.textEditReceive.insertPlainText(out_s) + # ASCII显示数据 + else: + #print("解码前",datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) + self.textEditReceive.insertPlainText(data.decode('utf-8',errors='replace')) + #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(): + self.AutoSaveLog() + + + + except: + # QMessageBox.critical(self, '串口异常', '串口接收数据异常,请重新连接设备!') + # 获取到text光标 + textCursor = self.textEditReceive.textCursor() + # 滚动到底部 + textCursor.movePosition(textCursor.End) + # 设置光标到text中去 + self.textEditReceive.setTextCursor(textCursor) + self.textEditReceive.insertPlainText("串口断开,重连中...\r\n") + self.ser.close() + + try: + print("重连中...") + time.sleep(1) + if not self.ser.is_open: + self.ser.open() + print("重连成功") + else: + print("串口已连接,无需重连") + except Exception as e: + + print(f"重连失败{e}") + + + + # %%定时发送数据 + def data_send_timer(self): + try: + if 1<= int(self.lineEditTime.text()) <= 30000: # 定时时间1ms~30s内 + if self.checkBoxReapitSend.isChecked(): + self.timer_send.start(int(self.lineEditTime.text())) + self.lineEditTime.setEnabled(False) + else: + self.timer_send.stop() + self.lineEditTime.setEnabled(True) + else: + QMessageBox.critical(self, '定时发送数据异常', '定时发送数据周期仅可设置在30秒内!') + except: + QMessageBox.critical(self, '定时发送数据异常', '请设置正确的数值类型!') + + # %%发送数据 + def data_send(self,text_quick = None): + if self.ser.isOpen(): + if text_quick== None: + input_s = self.textEditSend.toPlainText() + else: + input_s = text_quick + + # 判断是否为非空字符串 + 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(): + input_s = input_s.strip() + send_list = [] + while input_s != '': + try: + num = int(input_s[0:2], 16) + except ValueError: + QMessageBox.critical(self, '串口异常', '请输入规范十六进制数据,以空格分开!') + return None + + input_s = input_s[2:].strip() + send_list.append(num) + + input_s = bytes(send_list) + # ASCII发送 + else: + input_s = (input_s).encode('utf-8') + input_s = re.sub(b'(? + + + + 气体浓度和温度实时显示 + + + +

气体浓度和温度实时显示

+
+
+
甲烷浓度
+
0
+
ppm
+
+
+
乙烷浓度
+
0
+
ppm
+
+
+
二氧化碳浓度
+
0
+
ppm
+
+
+
温度
+
0
+
°C
+
+
+ + + + + \ No newline at end of file diff --git a/PyNetAssistant_Sever/udp.ini b/PyNetAssistant_Sever/udp.ini new file mode 100644 index 0000000..4d9046f --- /dev/null +++ b/PyNetAssistant_Sever/udp.ini @@ -0,0 +1,4 @@ +[NetConfig] +ip = 127.0.0.1 +port = 9000 + diff --git a/PyNetAssistant_Sever/untitled0.py b/PyNetAssistant_Sever/untitled0.py new file mode 100644 index 0000000..1b79a82 --- /dev/null +++ b/PyNetAssistant_Sever/untitled0.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +""" +Created on Sun Sep 29 21:35:04 2024 + +@author: wxb51 +""" + +import sys +from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout, QLineEdit, QPushButton + +class Example(QWidget): + def __init__(self): + super().__init__() + + self.initUI() + + def initUI(self): + # 创建一个垂直布局 + self.verticalLayout = QVBoxLayout() + + # 创建一个放置布局的小部件 + self.layoutWidget = QWidget(self) + + # 循环创建水平布局、文本输入框和按钮 + for i in range(21): # 从0到20 + horizontalLayout = QHBoxLayout() + horizontalLayout.setObjectName(f"horizontalLayout_{i}") + + lineEdit = QLineEdit(self.layoutWidget) + lineEdit.setObjectName(f"lineEdit_{i}") + horizontalLayout.addWidget(lineEdit) + + pushButton = QPushButton(self.layoutWidget) + pushButton.setObjectName(f"pushButton_{i}") + horizontalLayout.addWidget(pushButton) + + self.verticalLayout.addLayout(horizontalLayout) + + # 将垂直布局设置为主布局 + self.setLayout(self.verticalLayout) + + # 设置窗口标题 + self.setWindowTitle('Multiple Layouts Example') + +if __name__ == '__main__': + app = QApplication(sys.argv) + ex = Example() + ex.show() + sys.exit(app.exec_()) \ No newline at end of file diff --git a/test/pythonProject1/.idea/pythonProject1.iml b/test/pythonProject1/.idea/pythonProject1.iml new file mode 100644 index 0000000..6f1ddae --- /dev/null +++ b/test/pythonProject1/.idea/pythonProject1.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file