-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbasic_display.py
More file actions
115 lines (97 loc) · 3.61 KB
/
Copy pathbasic_display.py
File metadata and controls
115 lines (97 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import sys
import glob
from collections import deque
import serial
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QComboBox, QLabel
from PyQt6.QtCore import QThread, pyqtSignal
import pyqtgraph as pg
MAX_POINTS = 200
def list_ports():
if sys.platform.startswith("win"):
return [f"COM{i}" for i in range(1, 21)]
return sorted(glob.glob("/dev/ttyACM*") + glob.glob("/dev/ttyUSB*"))
class SerialThread(QThread):
value = pyqtSignal(float)
error = pyqtSignal(str)
def __init__(self, port, baud):
super().__init__()
self.port = port
self.baud = baud
self._running = False
def run(self):
try:
ser = serial.Serial(self.port, self.baud, timeout=1)
self._running = True
while self._running:
line = ser.readline().decode("utf-8", errors="replace").strip()
if line:
try:
self.value.emit(float(line))
except ValueError:
pass
ser.close()
except Exception as e:
self.error.emit(str(e))
def stop(self):
self._running = False
self.wait()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Serial Graph")
self.resize(800, 400)
self.thread = None
self.data = deque([0.0] * MAX_POINTS, maxlen=MAX_POINTS)
w = QWidget()
self.setCentralWidget(w)
layout = QVBoxLayout(w)
controls = QHBoxLayout()
self.port_combo = QComboBox()
self.port_combo.addItems(list_ports() or ["No ports found"])
self.baud_combo = QComboBox()
self.baud_combo.addItems(["9600", "19200", "57600", "115200"])
self.btn = QPushButton("Connect")
self.btn.clicked.connect(self.toggle)
self.status = QLabel("Disconnected")
controls.addWidget(QLabel("Port:"))
controls.addWidget(self.port_combo)
controls.addWidget(QLabel("Baud:"))
controls.addWidget(self.baud_combo)
controls.addWidget(self.btn)
controls.addWidget(self.status)
controls.addStretch()
layout.addLayout(controls)
self.plot_widget = pg.PlotWidget()
self.plot_widget.setYRange(0, 500)
self.plot_widget.setLabel("left", "Value")
self.plot_widget.setLabel("bottom", "Samples")
self.plot_widget.showGrid(x=True, y=True, alpha=0.3)
self.curve = self.plot_widget.plot(list(self.data), pen=pg.mkPen("#00ff88", width=2))
layout.addWidget(self.plot_widget)
def toggle(self):
if self.thread and self.thread.isRunning():
self.thread.stop()
self.thread = None
self.btn.setText("Connect")
self.status.setText("Disconnected")
else:
port = self.port_combo.currentText()
baud = int(self.baud_combo.currentText())
self.thread = SerialThread(port, baud)
self.thread.value.connect(self.on_value)
self.thread.error.connect(lambda e: self.status.setText(f"Error: {e}"))
self.thread.start()
self.btn.setText("Disconnect")
self.status.setText(f"Connected — {port} @ {baud}")
def on_value(self, v):
self.data.append(v)
self.curve.setData(list(self.data))
def closeEvent(self, e):
if self.thread:
self.thread.stop()
e.accept()
if __name__ == "__main__":
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec())