diagram eigefügt

This commit is contained in:
jens 2025-07-10 23:10:13 +02:00
parent 74e4b5f199
commit 7ba87e9d36
2 changed files with 152 additions and 3 deletions

View File

@ -6,6 +6,11 @@ from PyQt6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout
QGroupBox, QStatusBar, QMessageBox, QCheckBox)
from PyQt6.QtCore import QTimer, Qt
from PyQt6.QtGui import QFont
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import datetime
from collections import deque
class PHControllerGUI(QMainWindow):
def __init__(self):
@ -13,7 +18,7 @@ class PHControllerGUI(QMainWindow):
self.serial_connection = None
self.updating_tube_combo = False # Flag to prevent recursive tube commands
self.setWindowTitle("Arduino pH Controller")
self.setGeometry(100, 100, 600, 400)
self.setGeometry(100, 100, 900, 800) # Larger window for plot
# Central Widget
central_widget = QWidget()
@ -136,6 +141,30 @@ class PHControllerGUI(QMainWindow):
main_layout.addWidget(status_group)
main_layout.addWidget(control_group)
# pH Plot Group
plot_group = QGroupBox("pH-Verlauf")
plot_layout = QVBoxLayout()
# Plot controls
plot_controls_layout = QHBoxLayout()
self.clear_plot_btn = QPushButton("Diagramm löschen")
self.clear_plot_btn.clicked.connect(self.clear_ph_plot)
self.plot_enabled_checkbox = QCheckBox("pH-Aufzeichnung")
self.plot_enabled_checkbox.setChecked(True)
plot_controls_layout.addWidget(self.plot_enabled_checkbox)
plot_controls_layout.addWidget(self.clear_plot_btn)
plot_controls_layout.addStretch()
# pH Plot Widget
self.ph_plot = PHPlotWidget()
plot_layout.addLayout(plot_controls_layout)
plot_layout.addWidget(self.ph_plot)
plot_group.setLayout(plot_layout)
main_layout.addWidget(plot_group)
# Status Bar
self.status_bar = QStatusBar()
self.setStatusBar(self.status_bar)
@ -260,6 +289,8 @@ class PHControllerGUI(QMainWindow):
self.auto_dose_btn.setEnabled(enabled)
self.volume_spin.setEnabled(enabled)
self.reset_volume_checkbox.setEnabled(enabled)
self.clear_plot_btn.setEnabled(enabled)
self.plot_enabled_checkbox.setEnabled(enabled)
def send_command(self, command):
print(command)
@ -432,6 +463,9 @@ class PHControllerGUI(QMainWindow):
try:
ph_value = float(data[1:])
self.ph_label.setText(f"pH: {ph_value:.2f}")
# Add to plot if recording is enabled
if self.plot_enabled_checkbox.isChecked():
self.ph_plot.add_ph_value(ph_value)
except ValueError:
pass
elif data.startswith('P'): # Pump status
@ -488,6 +522,119 @@ class PHControllerGUI(QMainWindow):
self.close_connection()
event.accept()
def clear_ph_plot(self):
"""Clear the pH plot data"""
self.ph_plot.clear_data()
self.status_bar.showMessage("pH-Diagramm gelöscht")
class PHPlotWidget(QWidget):
def __init__(self):
super().__init__()
self.figure = Figure(figsize=(8, 4))
self.canvas = FigureCanvas(self.figure)
self.ax = self.figure.add_subplot(111)
# Data storage (keep last 300 points = 10 minutes at 2-second intervals)
self.times = deque(maxlen=300)
self.ph_values = deque(maxlen=300)
self.start_time = None # Track when recording started
# Setup plot
self.ax.set_xlabel('Zeit')
self.ax.set_ylabel('pH-Wert')
self.ax.set_title('pH-Verlauf')
self.ax.grid(True, alpha=0.3)
self.ax.set_ylim(0, 14) # pH range 0-14
# Layout
layout = QVBoxLayout()
layout.addWidget(self.canvas)
self.setLayout(layout)
# Plot line
self.line, = self.ax.plot([], [], 'b-', linewidth=2, label='pH-Wert')
self.ax.legend()
# Initial draw
self.canvas.draw()
def add_ph_value(self, ph_value):
"""Add new pH value with current timestamp"""
current_time = datetime.datetime.now()
# Set start time on first value
if self.start_time is None:
self.start_time = current_time
# Calculate relative time in seconds
relative_time = (current_time - self.start_time).total_seconds()
self.times.append(relative_time)
self.ph_values.append(ph_value)
self.update_plot()
def update_plot(self):
"""Update the plot with current data"""
if len(self.times) > 0 and len(self.ph_values) > 0:
# Update line data
self.line.set_data(self.times, self.ph_values)
# Auto-scale x-axis to show recent data
if len(self.times) > 1:
self.ax.set_xlim(min(self.times), max(self.times))
# Auto-scale y-axis around data with some margin
if len(self.ph_values) > 0:
min_ph = min(self.ph_values)
max_ph = max(self.ph_values)
margin = 0.5
self.ax.set_ylim(max(0, min_ph - margin), min(14, max_ph + margin))
# Format x-axis for time display (seconds/minutes/hours)
self.format_time_axis()
# Redraw
self.canvas.draw()
def format_time_axis(self):
"""Format the x-axis to show time in appropriate units"""
if len(self.times) == 0:
return
max_time = max(self.times)
if max_time < 120: # Less than 2 minutes - show seconds
self.ax.set_xlabel('Zeit (Sekunden)')
# No need to change tick formatting for seconds
elif max_time < 7200: # Less than 2 hours - show minutes
self.ax.set_xlabel('Zeit (Minuten)')
# Convert tick labels to minutes
import matplotlib.ticker as ticker
def format_minutes(x, pos):
return f'{x/60:.1f}'
self.ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_minutes))
else: # Show hours
self.ax.set_xlabel('Zeit (Stunden)')
# Convert tick labels to hours
import matplotlib.ticker as ticker
def format_hours(x, pos):
return f'{x/3600:.1f}'
self.ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_hours))
def clear_data(self):
"""Clear all data points"""
self.times.clear()
self.ph_values.clear()
self.start_time = None # Reset start time
self.line.set_data([], [])
self.ax.set_xlim(0, 1)
self.ax.set_ylim(0, 14)
self.ax.set_xlabel('Zeit') # Reset to default label
# Reset tick formatter to default
import matplotlib.ticker as ticker
self.ax.xaxis.set_major_formatter(ticker.ScalarFormatter())
self.canvas.draw()
def main():
app = QApplication(sys.argv)
window = PHControllerGUI()

View File

@ -1,2 +1,4 @@
PyQt6==6.9.0
PyQt6==6.7.0
pyserial==3.5
matplotlib==3.7.2
numpy<2.0.0