完成曲线绘制
This commit is contained in:
parent
bc1fccc16b
commit
06a541bbbb
25
aboutwindow.py
Normal file
25
aboutwindow.py
Normal file
@ -0,0 +1,25 @@
|
||||
from PyQt5.QtWidgets import *
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
|
||||
|
||||
class AboutWindow(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super(AboutWindow, self).__init__(parent)
|
||||
|
||||
self.setWindowTitle('关于')
|
||||
self.setWindowIcon(QIcon('gml.png'))
|
||||
self.setStyleSheet("QTextBrowser{font-size: 12pt;}")
|
||||
|
||||
self.textbrowser = QTextBrowser()
|
||||
self.textbrowser.setHtml(
|
||||
'<center><b>NodeHost</b></center><br>' +
|
||||
'<br>' +
|
||||
'本软件为分布式环境监测系统的上位机软件<br>' +
|
||||
'由 GML-Group 制作'
|
||||
)
|
||||
|
||||
layout = QHBoxLayout()
|
||||
layout.addWidget(self.textbrowser)
|
||||
self.setLayout(layout)
|
||||
self.setWindowModality(Qt.ApplicationModal)
|
||||
24
data.json
24
data.json
@ -1,23 +1 @@
|
||||
{
|
||||
"time": "2021-10-24 00:43:56",
|
||||
"node2": {
|
||||
"humi": 44.9,
|
||||
"temp": 25.2,
|
||||
"light": 360.8
|
||||
},
|
||||
"node3": {
|
||||
"humi": 43.2,
|
||||
"temp": 26.8,
|
||||
"light": 25.8
|
||||
},
|
||||
"node4": {
|
||||
"humi": 43.4,
|
||||
"temp": 26.6,
|
||||
"light": 25.8
|
||||
},
|
||||
"node5": {
|
||||
"humi": 44.5,
|
||||
"temp": 25.6,
|
||||
"light": 30.0
|
||||
}
|
||||
}
|
||||
{"time": "2021-10-30 16:25:15", "node2": {"humi": 40.9, "temp": 25.6, "light": 389.2}, "node3": {"humi": 44.5, "temp": 26.7, "light": 14.2}, "node4": {"humi": 46.3, "temp": 26.0, "light": 12.5}, "node5": {"humi": 46.5, "temp": 25.3, "light": 13.3}}
|
||||
143
drawwindow.py
Normal file
143
drawwindow.py
Normal file
@ -0,0 +1,143 @@
|
||||
from PyQt5.QtWidgets import *
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtChart import QChart, QChartView, QLineSeries, QDateTimeAxis, QValueAxis
|
||||
|
||||
|
||||
class DrawWindow(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.setGeometry(200, 200, 600, 400)
|
||||
self.setWindowIcon(QIcon("gml.png"))
|
||||
|
||||
self.humi_series = QLineSeries()
|
||||
self.temp_series = QLineSeries()
|
||||
self.light_series = QLineSeries()
|
||||
|
||||
ctime = QDateTime.currentDateTime()
|
||||
|
||||
humi_chart = QChart()
|
||||
humi_chart.setTheme(QChart.ChartThemeLight)
|
||||
humi_chart.addSeries(self.humi_series)
|
||||
humi_chart.setTitle("时间-湿度变化曲线")
|
||||
|
||||
temp_chart = QChart()
|
||||
temp_chart.setTheme(QChart.ChartThemeLight)
|
||||
temp_chart.addSeries(self.temp_series)
|
||||
temp_chart.setTitle("时间-温度变化曲线")
|
||||
|
||||
light_chart = QChart()
|
||||
light_chart.setTheme(QChart.ChartThemeLight)
|
||||
light_chart.addSeries(self.light_series)
|
||||
light_chart.setTitle("时间-光照度变化曲线")
|
||||
|
||||
self.humi_dtaxisX = QDateTimeAxis()
|
||||
self.temp_dtaxisX = QDateTimeAxis()
|
||||
self.light_dtaxisX = QDateTimeAxis()
|
||||
self.humi_vlaxisY = QValueAxis()
|
||||
self.temp_vlaxisY = QValueAxis()
|
||||
self.light_vlaxisY = QValueAxis()
|
||||
self.humi_dtaxisX.setMin(ctime.addSecs(0))
|
||||
self.humi_dtaxisX.setMax(ctime.addSecs(-60))
|
||||
self.temp_dtaxisX.setMin(ctime.addSecs(0))
|
||||
self.temp_dtaxisX.setMax(ctime.addSecs(-60))
|
||||
self.light_dtaxisX.setMin(ctime.addSecs(0))
|
||||
self.light_dtaxisX.setMax(ctime.addSecs(-60))
|
||||
self.humi_vlaxisY.setMin(40)
|
||||
self.humi_vlaxisY.setMax(50)
|
||||
self.temp_vlaxisY.setMin(20)
|
||||
self.temp_vlaxisY.setMax(30)
|
||||
self.light_vlaxisY.setMin(0)
|
||||
self.light_vlaxisY.setMax(100)
|
||||
|
||||
self.humi_dtaxisX.setFormat("hh:mm:ss")
|
||||
self.humi_dtaxisX.setTickCount(10)
|
||||
self.temp_dtaxisX.setFormat("hh:mm:ss")
|
||||
self.temp_dtaxisX.setTickCount(10)
|
||||
self.light_dtaxisX.setFormat("hh:mm:ss")
|
||||
self.light_dtaxisX.setTickCount(10)
|
||||
self.humi_vlaxisY.setTickCount(10)
|
||||
self.temp_vlaxisY.setTickCount(10)
|
||||
self.light_vlaxisY.setTickCount(1)
|
||||
|
||||
self.humi_dtaxisX.setTitleText("时间")
|
||||
self.temp_dtaxisX.setTitleText("时间")
|
||||
self.light_dtaxisX.setTitleText("时间")
|
||||
self.humi_vlaxisY.setTitleText("湿度")
|
||||
self.temp_vlaxisY.setTitleText("温度")
|
||||
self.light_vlaxisY.setTitleText("光照度")
|
||||
|
||||
self.humi_vlaxisY.setGridLineVisible(True)
|
||||
self.humi_vlaxisY.setGridLineColor(Qt.gray)
|
||||
self.temp_vlaxisY.setGridLineVisible(True)
|
||||
self.temp_vlaxisY.setGridLineColor(Qt.gray)
|
||||
self.light_vlaxisY.setGridLineVisible(True)
|
||||
self.light_vlaxisY.setGridLineColor(Qt.gray)
|
||||
self.humi_dtaxisX.setGridLineVisible(True)
|
||||
self.humi_dtaxisX.setGridLineColor(Qt.gray)
|
||||
self.temp_dtaxisX.setGridLineVisible(True)
|
||||
self.temp_dtaxisX.setGridLineColor(Qt.gray)
|
||||
self.light_dtaxisX.setGridLineVisible(True)
|
||||
self.light_dtaxisX.setGridLineColor(Qt.gray)
|
||||
|
||||
humi_chart.addAxis(self.humi_dtaxisX, Qt.AlignBottom)
|
||||
humi_chart.addAxis(self.humi_vlaxisY, Qt.AlignLeft)
|
||||
temp_chart.addAxis(self.temp_dtaxisX, Qt.AlignBottom)
|
||||
temp_chart.addAxis(self.temp_vlaxisY, Qt.AlignLeft)
|
||||
light_chart.addAxis(self.light_dtaxisX, Qt.AlignBottom)
|
||||
light_chart.addAxis(self.light_vlaxisY, Qt.AlignLeft)
|
||||
|
||||
self.humi_series.attachAxis(self.humi_dtaxisX)
|
||||
self.humi_series.attachAxis(self.humi_vlaxisY)
|
||||
self.temp_series.attachAxis(self.temp_dtaxisX)
|
||||
self.temp_series.attachAxis(self.temp_vlaxisY)
|
||||
self.light_series.attachAxis(self.light_dtaxisX)
|
||||
self.light_series.attachAxis(self.light_vlaxisY)
|
||||
|
||||
humi_chartview = QChartView(humi_chart)
|
||||
temp_chartview = QChartView(temp_chart)
|
||||
light_chartview = QChartView(light_chart)
|
||||
|
||||
layout = QGridLayout()
|
||||
layout.addWidget(humi_chartview, 1, 1)
|
||||
layout.addWidget(temp_chartview, 1, 2)
|
||||
layout.addWidget(light_chartview, 2, 1)
|
||||
self.setLayout(layout)
|
||||
|
||||
self.node_seq = 2
|
||||
|
||||
def start(self, node_seq: int):
|
||||
self.setWindowTitle(f"节点{node_seq}数据监测图")
|
||||
self.node_seq = node_seq
|
||||
self.show()
|
||||
|
||||
def addPoint(self, node_seq: int, node_data: dict):
|
||||
|
||||
if self.node_seq == node_seq:
|
||||
ctime = QDateTime.currentDateTime()
|
||||
self.humi_dtaxisX.setMin(ctime.addSecs(-60))
|
||||
self.humi_dtaxisX.setMax(ctime.addSecs(0))
|
||||
self.temp_dtaxisX.setMin(ctime.addSecs(-60))
|
||||
self.temp_dtaxisX.setMax(ctime.addSecs(0))
|
||||
self.light_dtaxisX.setMin(ctime.addSecs(-60))
|
||||
self.light_dtaxisX.setMax(ctime.addSecs(0))
|
||||
|
||||
if self.humi_vlaxisY.max() - 2 < node_data['humi'] or self.humi_vlaxisY.min() + 2 > node_data['humi']:
|
||||
self.humi_vlaxisY.setMin(node_data['humi'] * 0.8)
|
||||
self.humi_vlaxisY.setMax(node_data['humi'] * 1.2)
|
||||
|
||||
if self.temp_vlaxisY.max() - 2 < node_data['temp'] or self.temp_vlaxisY.min() + 2 > node_data['temp']:
|
||||
self.temp_vlaxisY.setMin(node_data['temp'] * 0.8)
|
||||
self.temp_vlaxisY.setMax(node_data['temp'] * 1.2)
|
||||
|
||||
if self.light_vlaxisY.max() - 20 < node_data['light'] or self.light_vlaxisY.min() + 20 > node_data['light']:
|
||||
self.light_vlaxisY.setMin(node_data['light'] * 0.8)
|
||||
self.light_vlaxisY.setMax(node_data['light'] * 1.2)
|
||||
|
||||
self.humi_series.append(
|
||||
ctime.toMSecsSinceEpoch(), node_data['humi'])
|
||||
self.temp_series.append(
|
||||
ctime.toMSecsSinceEpoch(), node_data['temp'])
|
||||
self.light_series.append(
|
||||
ctime.toMSecsSinceEpoch(), node_data['light'])
|
||||
71
index.html
Normal file
71
index.html
Normal file
@ -0,0 +1,71 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>分布式环境监测</title>
|
||||
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js">
|
||||
</script>
|
||||
<style>
|
||||
.container {
|
||||
width: 60%;
|
||||
margin: 10% auto 0;
|
||||
background-color: #f0f0f0;
|
||||
padding: 2% 5%;
|
||||
border-radius: 10px
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
ul li {
|
||||
line-height: 2.3
|
||||
}
|
||||
|
||||
a {
|
||||
color: #20a53a
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>分布式环境监测数据页面</h1>
|
||||
<h3>数据由网关向节点收集,上传至远程服务器</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<time></time>
|
||||
</li>
|
||||
<li>
|
||||
<node2></node2>
|
||||
</li>
|
||||
<li>
|
||||
<node3></node3>
|
||||
</li>
|
||||
<li>
|
||||
<node4></node4>
|
||||
</li>
|
||||
<li>
|
||||
<node5></node5>
|
||||
</li>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$.ajaxSetup({ cache: false });
|
||||
setInterval(function () {
|
||||
$.getJSON("/data.json", function (data) {
|
||||
$("time").text("数据更新时间: " + data.time);
|
||||
$("node2").text("节点 2: 湿度: " + data.node2.humi + "% 温度: " + data.node2.temp + "°C 光照度: " + data.node2.light + "lx");
|
||||
$("node3").text("节点 3: 湿度: " + data.node3.humi + "% 温度: " + data.node3.temp + "°C 光照度: " + data.node3.light + "lx");
|
||||
$("node4").text("节点 4: 湿度: " + data.node4.humi + "% 温度: " + data.node4.temp + "°C 光照度: " + data.node4.light + "lx");
|
||||
$("node5").text("节点 5: 湿度: " + data.node5.humi + "% 温度: " + data.node5.temp + "°C 光照度: " + data.node5.light + "lx");
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
</script>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
163
main.py
163
main.py
@ -1,165 +1,16 @@
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
import ctypes
|
||||
|
||||
import serial
|
||||
import serial.tools.list_ports
|
||||
from PyQt5.QtWidgets import *
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
|
||||
|
||||
class MainWidget(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super(MainWidget, self).__init__(parent)
|
||||
|
||||
self.setWindowTitle('Demo')
|
||||
|
||||
self.label_node2 = QLabel(
|
||||
'节点:2 湿度: % 温度: °C 光照度: lx ')
|
||||
self.label_node3 = QLabel(
|
||||
'节点:3 湿度: % 温度: °C 光照度: lx ', self)
|
||||
self.label_node4 = QLabel(
|
||||
'节点:4 湿度: % 温度: °C 光照度: lx ', self)
|
||||
self.label_node5 = QLabel(
|
||||
'节点:5 湿度: % 温度: °C 光照度: lx ', self)
|
||||
|
||||
self.combobox = QComboBox()
|
||||
|
||||
self.port_list = serial.tools.list_ports.comports()
|
||||
for port in self.port_list:
|
||||
self.combobox.addItem(port.description)
|
||||
|
||||
self.btnStart = QPushButton('开始')
|
||||
self.btnExit = QPushButton('退出')
|
||||
self.btnScanPort = QPushButton('刷新串口')
|
||||
|
||||
# 实例化多线程对象
|
||||
self.thread = Worker(self.port_list[0].name)
|
||||
|
||||
# 把控件放置在栅格布局中
|
||||
layout = QGridLayout(self)
|
||||
layout.addWidget(self.label_node2, 1, 1, 1, 4)
|
||||
layout.addWidget(self.label_node3, 2, 1, 1, 4)
|
||||
layout.addWidget(self.label_node4, 3, 1, 1, 4)
|
||||
layout.addWidget(self.label_node5, 4, 1, 1, 4)
|
||||
layout.addWidget(self.btnScanPort, 6, 1, 1, 1)
|
||||
layout.addWidget(self.combobox, 6, 2, 1, 1)
|
||||
layout.addWidget(self.btnStart, 6, 3, 1, 1)
|
||||
layout.addWidget(self.btnExit, 6, 4, 1, 1)
|
||||
|
||||
# 信号与槽函数的连接
|
||||
self.thread.sign_node.connect(self.slotUpdateNode)
|
||||
self.combobox.currentIndexChanged.connect(self.slotSelectPort)
|
||||
self.btnScanPort.clicked.connect(self.slotScanPort)
|
||||
self.btnStart.clicked.connect(self.slotStart)
|
||||
self.btnExit.clicked.connect(self.slotStop)
|
||||
|
||||
def slotScanPort(self):
|
||||
self.port_list = serial.tools.list_ports.comports()
|
||||
self.combobox.clear()
|
||||
for port in self.port_list:
|
||||
self.combobox.addItem(port.description)
|
||||
self.thread.port_name = self.port_list[0].name
|
||||
|
||||
def slotSelectPort(self, index):
|
||||
self.thread.port_name = self.port_list[index].name
|
||||
|
||||
def slotUpdateNode(self, node_seq, node_str):
|
||||
# 更新
|
||||
if (node_seq == 2):
|
||||
self.label_node2.setText(node_str)
|
||||
if (node_seq == 3):
|
||||
self.label_node3.setText(node_str)
|
||||
if (node_seq == 4):
|
||||
self.label_node4.setText(node_str)
|
||||
if (node_seq == 5):
|
||||
self.label_node5.setText(node_str)
|
||||
|
||||
def slotStart(self):
|
||||
self.combobox.setEnabled(False)
|
||||
self.btnScanPort.setEnabled(False)
|
||||
self.btnStart.setEnabled(False)
|
||||
self.btnExit.setEnabled(True)
|
||||
self.thread.start()
|
||||
|
||||
def slotStop(self):
|
||||
self.btnExit.setEnabled(False)
|
||||
del self.thread
|
||||
sys.exit()
|
||||
|
||||
|
||||
class Worker(QThread):
|
||||
sign_node = pyqtSignal(int, str)
|
||||
port_name: str
|
||||
|
||||
def __init__(self, port_name, parent=None):
|
||||
super(Worker, self).__init__(parent)
|
||||
# 设置工作状态与初始num数值
|
||||
self.port_name = port_name
|
||||
self.working = True
|
||||
|
||||
def __del__(self):
|
||||
# 线程状态改变与线程终止
|
||||
self.working = False
|
||||
self.wait()
|
||||
|
||||
def run(self):
|
||||
last_str = ''
|
||||
|
||||
self.com = serial.Serial(self.port_name, 115200)
|
||||
|
||||
while self.working == True:
|
||||
|
||||
serial_str = self.com.readline().decode('utf-8')
|
||||
|
||||
if (serial_str.find('ata') != -1):
|
||||
continue
|
||||
|
||||
str_list = serial_str.split('&') # 分割字符串
|
||||
|
||||
if len(str_list) != 5: # 数据缺失
|
||||
print('数据缺失!')
|
||||
continue
|
||||
|
||||
if (serial_str != last_str): # 检测数据是否重复
|
||||
last_str = serial_str
|
||||
|
||||
try: # 转换数据
|
||||
seq: int = int(str_list[0])
|
||||
humi: float = round(float(str_list[1]), 1)
|
||||
temp: float = round(float(str_list[2]), 1)
|
||||
light: float = round(float(str_list[3]), 1)
|
||||
|
||||
except Exception:
|
||||
print('数据错误!')
|
||||
continue
|
||||
|
||||
print(f"节点:{seq} 湿度:{humi}% 温度:{temp}°C 光照度:{light}lx")
|
||||
|
||||
# 写入 json 文件
|
||||
data = json.loads(
|
||||
open('./data.json', 'r', encoding='utf-8').read())
|
||||
|
||||
data['node' + str(seq)]['humi'] = humi
|
||||
data['node' + str(seq)]['temp'] = temp
|
||||
data['node' + str(seq)]['light'] = light
|
||||
data['time'] = time.strftime(
|
||||
'%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
|
||||
|
||||
with open('./data.json', 'w') as fp:
|
||||
fp.write(json.dumps(data))
|
||||
fp.close()
|
||||
|
||||
# 获取文本
|
||||
node_str = f"节点:{seq} 湿度:{humi}% 温度:{temp}°C 光照度:{light}lx"
|
||||
# 发射信号
|
||||
self.sign_node.emit(seq, node_str)
|
||||
from mainwindow import MainWindow
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 防止系统显示为 Python 图标
|
||||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("NoidHost")
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
app.setStyleSheet("QLabel{font-size: 18pt;}")
|
||||
demo = MainWidget()
|
||||
demo.show()
|
||||
main_widget = MainWindow()
|
||||
main_widget.show()
|
||||
sys.exit(app.exec_())
|
||||
|
||||
161
mainwindow.py
Normal file
161
mainwindow.py
Normal file
@ -0,0 +1,161 @@
|
||||
import sys
|
||||
|
||||
import serial
|
||||
import serial.tools.list_ports
|
||||
from PyQt5.QtWidgets import *
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
|
||||
from drawwindow import DrawWindow
|
||||
from aboutwindow import AboutWindow
|
||||
from serialhandler import SerialHandler
|
||||
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self, parent=None):
|
||||
super(MainWindow, self).__init__(parent)
|
||||
|
||||
self.setWindowTitle('NoidHost')
|
||||
self.setWindowIcon(QIcon('gml.png'))
|
||||
|
||||
self.statusbar = self.statusBar()
|
||||
self.statusbar.showMessage('等待连接')
|
||||
|
||||
menubar = self.menuBar()
|
||||
|
||||
# 菜单栏-文件
|
||||
exit_action = QAction('&退出', self)
|
||||
exit_action.setShortcut('Ctrl+Q')
|
||||
exit_action.setStatusTip('退出应用')
|
||||
exit_action.triggered.connect(lambda: sys.exit())
|
||||
|
||||
menubar_file = menubar.addMenu('文件')
|
||||
menubar_file.addAction(exit_action)
|
||||
|
||||
# 菜单栏-绘图
|
||||
draw_node2_action = QAction('&节点2', self)
|
||||
draw_node3_action = QAction('&节点3', self)
|
||||
draw_node4_action = QAction('&节点4', self)
|
||||
draw_node5_action = QAction('&节点5', self)
|
||||
|
||||
self.node2_drawwindow = DrawWindow()
|
||||
self.node3_drawwindow = DrawWindow()
|
||||
self.node4_drawwindow = DrawWindow()
|
||||
self.node5_drawwindow = DrawWindow()
|
||||
|
||||
menubar_draw = menubar.addMenu('绘图')
|
||||
menubar_draw.addAction(draw_node2_action)
|
||||
menubar_draw.addAction(draw_node3_action)
|
||||
menubar_draw.addAction(draw_node4_action)
|
||||
menubar_draw.addAction(draw_node5_action)
|
||||
|
||||
draw_node2_action.triggered.connect(
|
||||
lambda: self.drawStart(2))
|
||||
draw_node3_action.triggered.connect(
|
||||
lambda: self.drawStart(3))
|
||||
draw_node4_action.triggered.connect(
|
||||
lambda: self.drawStart(4))
|
||||
draw_node5_action.triggered.connect(
|
||||
lambda: self.drawStart(5))
|
||||
|
||||
# 菜单栏-关于
|
||||
self.aboutwindow = AboutWindow()
|
||||
about_action = QAction('&关于', self)
|
||||
about_action.setShortcut('Ctrl+A')
|
||||
about_action.setStatusTip('关于')
|
||||
about_action.triggered.connect(lambda: self.aboutwindow.show())
|
||||
|
||||
menubar_about = menubar.addMenu('关于')
|
||||
menubar_about.addAction(about_action)
|
||||
|
||||
self.label_node2 = QLabel(
|
||||
'节点:2 湿度: % 温度: °C 光照度: lx ')
|
||||
self.label_node3 = QLabel(
|
||||
'节点:3 湿度: % 温度: °C 光照度: lx ', self)
|
||||
self.label_node4 = QLabel(
|
||||
'节点:4 湿度: % 温度: °C 光照度: lx ', self)
|
||||
self.label_node5 = QLabel(
|
||||
'节点:5 湿度: % 温度: °C 光照度: lx ', self)
|
||||
|
||||
self.combobox = QComboBox()
|
||||
|
||||
self.port_list = serial.tools.list_ports.comports()
|
||||
for port in self.port_list:
|
||||
self.combobox.addItem(port.description)
|
||||
|
||||
self.btnStart = QPushButton('开始')
|
||||
self.btnExit = QPushButton('退出')
|
||||
self.btnScanPort = QPushButton('刷新串口')
|
||||
|
||||
# 实例化多线程对象
|
||||
self.handler = SerialHandler(self.port_list[0].name)
|
||||
|
||||
# 把控件放置在栅格布局中
|
||||
layout = QGridLayout()
|
||||
layout.addWidget(self.label_node2, 1, 1, 1, 4)
|
||||
layout.addWidget(self.label_node3, 2, 1, 1, 4)
|
||||
layout.addWidget(self.label_node4, 3, 1, 1, 4)
|
||||
layout.addWidget(self.label_node5, 4, 1, 1, 4)
|
||||
layout.addWidget(self.btnScanPort, 5, 1, 1, 1)
|
||||
layout.addWidget(self.combobox, 5, 2, 1, 1)
|
||||
layout.addWidget(self.btnStart, 5, 3, 1, 1)
|
||||
layout.addWidget(self.btnExit, 5, 4, 1, 1)
|
||||
|
||||
self.widget = QWidget()
|
||||
self.widget.setLayout(layout)
|
||||
self.widget.setStyleSheet("QLabel{font-size: 18pt;}")
|
||||
self.setCentralWidget(self.widget)
|
||||
|
||||
# 信号与槽函数的连接
|
||||
self.handler.sign_node.connect(self.slotUpdateNode)
|
||||
self.combobox.currentIndexChanged.connect(self.slotSelectPort)
|
||||
self.btnScanPort.clicked.connect(self.slotScanPort)
|
||||
self.btnStart.clicked.connect(self.slotStart)
|
||||
self.btnExit.clicked.connect(lambda: sys.exit())
|
||||
|
||||
def slotScanPort(self):
|
||||
self.port_list = serial.tools.list_ports.comports()
|
||||
self.combobox.clear()
|
||||
for port in self.port_list:
|
||||
self.combobox.addItem(port.description)
|
||||
self.handler.port_name = self.port_list[0].name
|
||||
|
||||
def slotSelectPort(self, index):
|
||||
self.handler.port_name = self.port_list[index].name
|
||||
|
||||
def slotUpdateNode(self, node_seq: int, node_data: dict):
|
||||
# 更新
|
||||
if (node_seq == 2):
|
||||
self.label_node2.setText(
|
||||
f"节点:2 湿度:{node_data['humi']}% 温度:{node_data['temp']}°C 光照度:{node_data['light']}lx")
|
||||
if (node_seq == 3):
|
||||
self.label_node3.setText(
|
||||
f"节点:3 湿度:{node_data['humi']}% 温度:{node_data['temp']}°C 光照度:{node_data['light']}lx")
|
||||
if (node_seq == 4):
|
||||
self.label_node4.setText(
|
||||
f"节点:4 湿度:{node_data['humi']}% 温度:{node_data['temp']}°C 光照度:{node_data['light']}lx")
|
||||
if (node_seq == 5):
|
||||
self.label_node5.setText(
|
||||
f"节点:5 湿度:{node_data['humi']}% 温度:{node_data['temp']}°C 光照度:{node_data['light']}lx")
|
||||
|
||||
def slotStart(self):
|
||||
self.combobox.setEnabled(False)
|
||||
self.btnScanPort.setEnabled(False)
|
||||
self.btnStart.setEnabled(False)
|
||||
self.btnExit.setEnabled(True)
|
||||
self.statusbar.showMessage('已连接')
|
||||
self.handler.start()
|
||||
|
||||
def drawStart(self, node_seq: int):
|
||||
if node_seq == 2:
|
||||
self.handler.sign_node.connect(self.node2_drawwindow.addPoint)
|
||||
self.node2_drawwindow.start(node_seq)
|
||||
elif node_seq == 3:
|
||||
self.handler.sign_node.connect(self.node3_drawwindow.addPoint)
|
||||
self.node3_drawwindow.start(node_seq)
|
||||
elif node_seq == 4:
|
||||
self.handler.sign_node.connect(self.node4_drawwindow.addPoint)
|
||||
self.node4_drawwindow.start(node_seq)
|
||||
elif node_seq == 5:
|
||||
self.handler.sign_node.connect(self.node5_drawwindow.addPoint)
|
||||
self.node5_drawwindow.start(node_seq)
|
||||
80
serialhandler.py
Normal file
80
serialhandler.py
Normal file
@ -0,0 +1,80 @@
|
||||
import time
|
||||
import json
|
||||
|
||||
import serial
|
||||
import serial.tools.list_ports
|
||||
from PyQt5.QtWidgets import *
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
|
||||
|
||||
class SerialHandler(QThread):
|
||||
sign_node = pyqtSignal(int, dict)
|
||||
port_name: str
|
||||
|
||||
def __init__(self, port_name, parent=None):
|
||||
super(SerialHandler, self).__init__(parent)
|
||||
self.port_name = port_name
|
||||
self.working = True
|
||||
|
||||
def __del__(self):
|
||||
# 线程状态改变与线程终止
|
||||
self.working = False
|
||||
self.wait()
|
||||
|
||||
def run(self):
|
||||
last_str = '' # 记录上一次收到的字符串
|
||||
self.com = serial.Serial(self.port_name, 115200)
|
||||
|
||||
while self.working == True:
|
||||
|
||||
serial_str = self.com.readline().decode('utf-8')
|
||||
str_list = serial_str.split('&') # 分割字符串
|
||||
|
||||
if len(str_list) != 5: # 数据缺失
|
||||
print('数据缺失!')
|
||||
continue
|
||||
|
||||
if (serial_str != last_str): # 检测数据是否重复
|
||||
last_str = serial_str
|
||||
|
||||
try: # 转换数据
|
||||
seq: int = int(str_list[0])
|
||||
humi: float = round(float(str_list[1]), 1)
|
||||
temp: float = round(float(str_list[2]), 1)
|
||||
light: float = round(float(str_list[3]), 1)
|
||||
|
||||
except Exception:
|
||||
print('数据错误!')
|
||||
continue
|
||||
|
||||
# 检测数据合理性
|
||||
if humi > 100 or temp > 50 or light > 100000:
|
||||
print('数据不合理!')
|
||||
continue
|
||||
|
||||
print(f"节点:{seq} 湿度:{humi}% 温度:{temp}°C 光照度:{light}lx")
|
||||
|
||||
# 写入 json 文件
|
||||
data = json.loads(
|
||||
open('./data.json', 'r', encoding='utf-8').read())
|
||||
|
||||
data['node' + str(seq)]['humi'] = humi
|
||||
data['node' + str(seq)]['temp'] = temp
|
||||
data['node' + str(seq)]['light'] = light
|
||||
data['time'] = time.strftime(
|
||||
'%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
|
||||
|
||||
with open('./data.json', 'w') as fp:
|
||||
fp.write(json.dumps(data))
|
||||
fp.close()
|
||||
|
||||
# 获取文本
|
||||
node_data = {
|
||||
"seq": seq,
|
||||
"humi": humi,
|
||||
"temp": temp,
|
||||
"light": light
|
||||
}
|
||||
# 发射信号
|
||||
self.sign_node.emit(seq, node_data)
|
||||
1
server.bat
Normal file
1
server.bat
Normal file
@ -0,0 +1 @@
|
||||
python -m http.server 8520
|
||||
Loading…
x
Reference in New Issue
Block a user