MainCode/adalm1000_logger.py aktualisiert
still crashing after a while D
This commit is contained in:
parent
7c72e508d7
commit
ab4506cf27
@ -3,6 +3,7 @@ import os
|
|||||||
import time
|
import time
|
||||||
import csv
|
import csv
|
||||||
import threading
|
import threading
|
||||||
|
import traceback
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import matplotlib
|
import matplotlib
|
||||||
@ -12,9 +13,11 @@ from matplotlib.figure import Figure
|
|||||||
from collections import deque
|
from collections import deque
|
||||||
from queue import Queue, Full, Empty
|
from queue import Queue, Full, Empty
|
||||||
|
|
||||||
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QLabel,
|
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||||
QPushButton, QLineEdit, QCheckBox, QFrame, QMessageBox, QFileDialog, QComboBox)
|
QGridLayout, QLabel, QPushButton, QLineEdit, QCheckBox,
|
||||||
|
QFrame, QMessageBox, QFileDialog, QComboBox)
|
||||||
from PyQt5.QtCore import Qt, QTimer, pyqtSignal, pyqtSlot, QObject, QThread
|
from PyQt5.QtCore import Qt, QTimer, pyqtSignal, pyqtSlot, QObject, QThread
|
||||||
|
from PyQt5.QtGui import QDoubleValidator
|
||||||
from PyQt5 import sip
|
from PyQt5 import sip
|
||||||
import pysmu
|
import pysmu
|
||||||
|
|
||||||
@ -74,17 +77,28 @@ class DeviceManager:
|
|||||||
return True # Under threshold - continue
|
return True # Under threshold - continue
|
||||||
|
|
||||||
def start_measurement(self, interval=0.1):
|
def start_measurement(self, interval=0.1):
|
||||||
if self.measurement_thread and self.measurement_thread.isRunning():
|
self.stop_measurement() # Ensure any existing thread is stopped
|
||||||
self.measurement_thread.stop()
|
self.measurement_thread = MeasurementThread(self.dev, interval, self)
|
||||||
|
|
||||||
self.measurement_thread = MeasurementThread(self.dev, interval, self) # Pass self as parent_manager
|
|
||||||
self.measurement_thread.start()
|
self.measurement_thread.start()
|
||||||
self.is_running = True
|
self.is_running = True
|
||||||
|
|
||||||
def stop_measurement(self):
|
def stop_measurement(self):
|
||||||
if self.measurement_thread:
|
if self.measurement_thread:
|
||||||
|
try:
|
||||||
|
# Disconnect signals first
|
||||||
|
try:
|
||||||
|
self.measurement_thread.update_signal.disconnect()
|
||||||
|
self.measurement_thread.error_signal.disconnect()
|
||||||
|
except (RuntimeError, TypeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Then stop the thread
|
||||||
self.measurement_thread.stop()
|
self.measurement_thread.stop()
|
||||||
self.measurement_thread.wait(500)
|
if not self.measurement_thread.wait(500):
|
||||||
|
self.measurement_thread.terminate()
|
||||||
|
self.measurement_thread = None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error stopping measurement thread: {e}")
|
||||||
self.is_running = False
|
self.is_running = False
|
||||||
|
|
||||||
def reset_data(self):
|
def reset_data(self):
|
||||||
@ -112,7 +126,7 @@ class MeasurementThread(QThread):
|
|||||||
update_signal = pyqtSignal(float, float, float)
|
update_signal = pyqtSignal(float, float, float)
|
||||||
error_signal = pyqtSignal(str)
|
error_signal = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, device, interval, parent_manager): # Add parent_manager
|
def __init__(self, device, interval, parent_manager):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.device = device
|
self.device = device
|
||||||
self.interval = interval
|
self.interval = interval
|
||||||
@ -122,13 +136,18 @@ class MeasurementThread(QThread):
|
|||||||
self.current_window = []
|
self.current_window = []
|
||||||
self.start_time = None
|
self.start_time = None
|
||||||
self.measurement_queue = Queue(maxsize=1)
|
self.measurement_queue = Queue(maxsize=1)
|
||||||
self.current_direction = 1 # 1 for source, -1 for sink
|
self.current_direction = 1
|
||||||
self.parent_manager = parent_manager
|
self.parent_manager = parent_manager
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self._running = False
|
||||||
|
if not self.wait(500): # Wait up to 500ms for clean shutdown
|
||||||
|
self.terminate()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Continuous measurement loop with enhanced error handling"""
|
"""Continuous measurement loop with enhanced error handling"""
|
||||||
self._running = True
|
self._running = True
|
||||||
self.start_time = time.time()
|
self.start_time = time.time() # This gets reset when mode changes
|
||||||
consecutive_errors = 0
|
consecutive_errors = 0
|
||||||
max_consecutive_errors = 5
|
max_consecutive_errors = 5
|
||||||
|
|
||||||
@ -213,10 +232,6 @@ class MeasurementThread(QThread):
|
|||||||
"""Set current direction (1 for source, -1 for sink)"""
|
"""Set current direction (1 for source, -1 for sink)"""
|
||||||
self.current_direction = direction
|
self.current_direction = direction
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self._running = False
|
|
||||||
self.wait(500)
|
|
||||||
|
|
||||||
class TestSequenceWorker(QObject):
|
class TestSequenceWorker(QObject):
|
||||||
finished = pyqtSignal()
|
finished = pyqtSignal()
|
||||||
update_phase = pyqtSignal(str)
|
update_phase = pyqtSignal(str)
|
||||||
@ -590,14 +605,14 @@ class BatteryTester(QMainWindow):
|
|||||||
self.status_timer.start(1000) #every second
|
self.status_timer.start(1000) #every second
|
||||||
|
|
||||||
def setup_ui(self):
|
def setup_ui(self):
|
||||||
"""Configure the user interface"""
|
"""Configure the user interface with all elements properly organized"""
|
||||||
# Main widget and layout
|
# Main widget and layout
|
||||||
self.central_widget = QWidget()
|
self.central_widget = QWidget()
|
||||||
self.setCentralWidget(self.central_widget)
|
self.setCentralWidget(self.central_widget)
|
||||||
self.main_layout = QVBoxLayout(self.central_widget)
|
self.main_layout = QVBoxLayout(self.central_widget)
|
||||||
self.main_layout.setContentsMargins(10, 10, 10, 10)
|
self.main_layout.setContentsMargins(10, 10, 10, 10)
|
||||||
|
|
||||||
# Mode and device selection
|
# Mode and device selection frame
|
||||||
mode_frame = QFrame()
|
mode_frame = QFrame()
|
||||||
mode_frame.setFrameShape(QFrame.StyledPanel)
|
mode_frame.setFrameShape(QFrame.StyledPanel)
|
||||||
mode_frame.setStyleSheet(f"QFrame {{ border: 1px solid {self.accent_color}; border-radius: 5px; }}")
|
mode_frame.setStyleSheet(f"QFrame {{ border: 1px solid {self.accent_color}; border-radius: 5px; }}")
|
||||||
@ -674,7 +689,7 @@ class BatteryTester(QMainWindow):
|
|||||||
display_frame.setStyleSheet(f"QFrame {{ border: 1px solid {self.accent_color}; border-radius: 5px; }}")
|
display_frame.setStyleSheet(f"QFrame {{ border: 1px solid {self.accent_color}; border-radius: 5px; }}")
|
||||||
display_layout = QGridLayout(display_frame)
|
display_layout = QGridLayout(display_frame)
|
||||||
|
|
||||||
# Measurement values - common for all modes
|
# Measurement values
|
||||||
measurement_labels = [
|
measurement_labels = [
|
||||||
("Voltage", "V"), ("Current", "A"), ("Test Phase", ""),
|
("Voltage", "V"), ("Current", "A"), ("Test Phase", ""),
|
||||||
("Elapsed Time", "s"), ("Capacity", "Ah"), ("Power", "W"),
|
("Elapsed Time", "s"), ("Capacity", "Ah"), ("Power", "W"),
|
||||||
@ -730,123 +745,103 @@ class BatteryTester(QMainWindow):
|
|||||||
self.params_frame.setStyleSheet(f"QFrame {{ border: 1px solid {self.accent_color}; border-radius: 5px; }}")
|
self.params_frame.setStyleSheet(f"QFrame {{ border: 1px solid {self.accent_color}; border-radius: 5px; }}")
|
||||||
self.params_layout = QGridLayout(self.params_frame)
|
self.params_layout = QGridLayout(self.params_frame)
|
||||||
|
|
||||||
# Common parameters
|
# Add parameter inputs
|
||||||
self.capacity = 0.2
|
row = 0
|
||||||
self.capacity_label_input = QLabel("Battery Capacity (Ah):")
|
|
||||||
self.capacity_label_input.setStyleSheet(f"color: {self.fg_color};")
|
|
||||||
self.params_layout.addWidget(self.capacity_label_input, 0, 0)
|
|
||||||
self.capacity_input = QLineEdit("0.2")
|
|
||||||
self.capacity_input.setStyleSheet(f"background-color: #3B4252; color: {self.fg_color};")
|
|
||||||
self.capacity_input.setFixedWidth(60)
|
|
||||||
self.params_layout.addWidget(self.capacity_input, 0, 1)
|
|
||||||
|
|
||||||
# C-rate for test
|
# Battery Capacity
|
||||||
self.c_rate = 0.1
|
self.capacity_label = QLabel("Capacity (Ah):")
|
||||||
self.c_rate_label = QLabel("Test C-rate:")
|
self.capacity_label.setStyleSheet(f"color: {self.fg_color};")
|
||||||
|
self.params_layout.addWidget(self.capacity_label, row, 0)
|
||||||
|
|
||||||
|
self.capacity_input = QLineEdit("1.0")
|
||||||
|
self.capacity_input.setValidator(QDoubleValidator(0.001, 100, 3))
|
||||||
|
self.params_layout.addWidget(self.capacity_input, row, 1)
|
||||||
|
row += 1
|
||||||
|
|
||||||
|
# C-Rate
|
||||||
|
self.c_rate_label = QLabel("C-Rate:")
|
||||||
self.c_rate_label.setStyleSheet(f"color: {self.fg_color};")
|
self.c_rate_label.setStyleSheet(f"color: {self.fg_color};")
|
||||||
self.params_layout.addWidget(self.c_rate_label, 1, 0)
|
self.params_layout.addWidget(self.c_rate_label, row, 0)
|
||||||
|
|
||||||
self.c_rate_input = QLineEdit("0.1")
|
self.c_rate_input = QLineEdit("0.1")
|
||||||
self.c_rate_input.setStyleSheet(f"background-color: #3B4252; color: {self.fg_color};")
|
self.c_rate_input.setValidator(QDoubleValidator(0.01, 1, 2))
|
||||||
self.c_rate_input.setFixedWidth(40)
|
self.params_layout.addWidget(self.c_rate_input, row, 1)
|
||||||
self.params_layout.addWidget(self.c_rate_input, 1, 1)
|
row += 1
|
||||||
|
|
||||||
c_rate_note = QLabel("(e.g., 0.2 for C/5)")
|
# Charge Cutoff Voltage
|
||||||
c_rate_note.setStyleSheet(f"color: {self.fg_color};")
|
|
||||||
self.params_layout.addWidget(c_rate_note, 1, 2)
|
|
||||||
|
|
||||||
# Discharge cutoff (used in Discharge and Cycle modes)
|
|
||||||
self.discharge_cutoff = 0.9
|
|
||||||
self.discharge_cutoff_label = QLabel("Discharge Cutoff (V):")
|
|
||||||
self.discharge_cutoff_label.setStyleSheet(f"color: {self.fg_color};")
|
|
||||||
self.params_layout.addWidget(self.discharge_cutoff_label, 2, 0)
|
|
||||||
self.discharge_cutoff_input = QLineEdit("0.9")
|
|
||||||
self.discharge_cutoff_input.setStyleSheet(f"background-color: #3B4252; color: {self.fg_color};")
|
|
||||||
self.discharge_cutoff_input.setFixedWidth(60)
|
|
||||||
self.params_layout.addWidget(self.discharge_cutoff_input, 2, 1)
|
|
||||||
|
|
||||||
# Charge cutoff (only for Cycle mode)
|
|
||||||
self.charge_cutoff = 1.43
|
|
||||||
self.charge_cutoff_label = QLabel("Charge Cutoff (V):")
|
self.charge_cutoff_label = QLabel("Charge Cutoff (V):")
|
||||||
self.charge_cutoff_label.setStyleSheet(f"color: {self.fg_color};")
|
self.charge_cutoff_label.setStyleSheet(f"color: {self.fg_color};")
|
||||||
self.params_layout.addWidget(self.charge_cutoff_label, 3, 0)
|
self.params_layout.addWidget(self.charge_cutoff_label, row, 0)
|
||||||
|
|
||||||
self.charge_cutoff_input = QLineEdit("1.43")
|
self.charge_cutoff_input = QLineEdit("1.43")
|
||||||
self.charge_cutoff_input.setStyleSheet(f"background-color: #3B4252; color: {self.fg_color};")
|
self.charge_cutoff_input.setValidator(QDoubleValidator(0.1, 5.0, 3))
|
||||||
self.charge_cutoff_input.setFixedWidth(60)
|
self.params_layout.addWidget(self.charge_cutoff_input, row, 1)
|
||||||
self.params_layout.addWidget(self.charge_cutoff_input, 3, 1)
|
row += 1
|
||||||
self.charge_cutoff_label.hide()
|
|
||||||
self.charge_cutoff_input.hide()
|
|
||||||
|
|
||||||
# Rest time (only for Cycle mode)
|
# Discharge Cutoff Voltage
|
||||||
self.rest_time = 0.25
|
self.discharge_cutoff_label = QLabel("Discharge Cutoff (V):")
|
||||||
self.rest_time_label = QLabel("Rest Time (hours):")
|
self.discharge_cutoff_label.setStyleSheet(f"color: {self.fg_color};")
|
||||||
|
self.params_layout.addWidget(self.discharge_cutoff_label, row, 0)
|
||||||
|
|
||||||
|
self.discharge_cutoff_input = QLineEdit("0.01")
|
||||||
|
self.discharge_cutoff_input.setValidator(QDoubleValidator(0.1, 5.0, 3))
|
||||||
|
self.params_layout.addWidget(self.discharge_cutoff_input, row, 1)
|
||||||
|
row += 1
|
||||||
|
|
||||||
|
# Rest Time
|
||||||
|
self.rest_time_label = QLabel("Rest Time (h):")
|
||||||
self.rest_time_label.setStyleSheet(f"color: {self.fg_color};")
|
self.rest_time_label.setStyleSheet(f"color: {self.fg_color};")
|
||||||
self.params_layout.addWidget(self.rest_time_label, 4, 0)
|
self.params_layout.addWidget(self.rest_time_label, row, 0)
|
||||||
self.rest_time_input = QLineEdit("0.25")
|
|
||||||
self.rest_time_input.setStyleSheet(f"background-color: #3B4252; color: {self.fg_color};")
|
|
||||||
self.rest_time_input.setFixedWidth(60)
|
|
||||||
self.params_layout.addWidget(self.rest_time_input, 4, 1)
|
|
||||||
self.rest_time_label.hide()
|
|
||||||
self.rest_time_input.hide()
|
|
||||||
|
|
||||||
# Test conditions input
|
self.rest_time_input = QLineEdit("0.5")
|
||||||
self.test_conditions_label = QLabel("Test Conditions/Chemistry:")
|
self.rest_time_input.setValidator(QDoubleValidator(0.1, 24, 1))
|
||||||
|
self.params_layout.addWidget(self.rest_time_input, row, 1)
|
||||||
|
row += 1
|
||||||
|
|
||||||
|
# Test Conditions
|
||||||
|
self.test_conditions_label = QLabel("Test Conditions:")
|
||||||
self.test_conditions_label.setStyleSheet(f"color: {self.fg_color};")
|
self.test_conditions_label.setStyleSheet(f"color: {self.fg_color};")
|
||||||
self.params_layout.addWidget(self.test_conditions_label, 5, 0)
|
self.params_layout.addWidget(self.test_conditions_label, row, 0)
|
||||||
self.test_conditions_input = QLineEdit("")
|
|
||||||
self.test_conditions_input.setStyleSheet(f"background-color: #3B4252; color: {self.fg_color};")
|
self.test_conditions_input = QLineEdit("Room Temperature")
|
||||||
self.test_conditions_input.setFixedWidth(120)
|
self.params_layout.addWidget(self.test_conditions_input, row, 1)
|
||||||
self.params_layout.addWidget(self.test_conditions_input, 5, 1)
|
|
||||||
|
|
||||||
controls_layout.addWidget(self.params_frame, 1)
|
controls_layout.addWidget(self.params_frame, 1)
|
||||||
|
|
||||||
# Button frame
|
# Button frame with single toggle button
|
||||||
button_frame = QFrame()
|
button_frame = QFrame()
|
||||||
button_frame.setFrameShape(QFrame.NoFrame)
|
button_frame.setFrameShape(QFrame.NoFrame)
|
||||||
button_layout = QVBoxLayout(button_frame)
|
button_layout = QVBoxLayout(button_frame)
|
||||||
button_layout.setContentsMargins(0, 0, 0, 0)
|
button_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
# Start/Stop buttons
|
# Single toggle button (Start/Stop)
|
||||||
self.start_button = QPushButton("START")
|
self.toggle_button = QPushButton("START")
|
||||||
self.start_button.setStyleSheet(f"""
|
self.toggle_button.setCheckable(True)
|
||||||
|
self.toggle_button.setStyleSheet(f"""
|
||||||
QPushButton {{
|
QPushButton {{
|
||||||
background-color: {self.accent_color};
|
background-color: {self.accent_color};
|
||||||
color: {self.fg_color};
|
color: {self.fg_color};
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
min-width: 80px;
|
||||||
}}
|
}}
|
||||||
QPushButton:disabled {{
|
QPushButton:checked {{
|
||||||
background-color: #4C566A;
|
|
||||||
color: #D8DEE9;
|
|
||||||
}}
|
|
||||||
""")
|
|
||||||
self.start_button.clicked.connect(self.start_test)
|
|
||||||
button_layout.addWidget(self.start_button)
|
|
||||||
|
|
||||||
self.stop_button = QPushButton("STOP")
|
|
||||||
self.stop_button.setStyleSheet(f"""
|
|
||||||
QPushButton {{
|
|
||||||
background-color: {self.warning_color};
|
background-color: {self.warning_color};
|
||||||
color: {self.fg_color};
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 6px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}}
|
}}
|
||||||
QPushButton:disabled {{
|
QPushButton:disabled {{
|
||||||
background-color: #4C566A;
|
background-color: #4C566A;
|
||||||
color: #D8DEE9;
|
color: #D8DEE9;
|
||||||
}}
|
}}
|
||||||
""")
|
""")
|
||||||
self.stop_button.clicked.connect(self.stop_test)
|
self.toggle_button.clicked.connect(self.toggle_test)
|
||||||
self.stop_button.setEnabled(False)
|
button_layout.addWidget(self.toggle_button)
|
||||||
button_layout.addWidget(self.stop_button)
|
|
||||||
|
|
||||||
# Continuous mode checkbox (only for Cycle mode)
|
# Continuous mode checkbox (only for Cycle mode)
|
||||||
self.continuous_mode_check = QCheckBox("Continuous Mode")
|
self.continuous_mode_check = QCheckBox("Continuous Mode")
|
||||||
self.continuous_mode_check.setChecked(True)
|
self.continuous_mode_check.setChecked(True)
|
||||||
self.continuous_mode_check.setStyleSheet(f"color: {self.fg_color};")
|
self.continuous_mode_check.setStyleSheet(f"color: {self.fg_color};")
|
||||||
button_layout.addWidget(self.continuous_mode_check)
|
button_layout.addWidget(self.continuous_mode_check)
|
||||||
self.continuous_mode_check.stateChanged.connect(self.handle_continuous_mode_change)
|
|
||||||
self.continuous_mode_check.hide()
|
self.continuous_mode_check.hide()
|
||||||
|
|
||||||
# Record button for Live mode
|
# Record button for Live mode
|
||||||
@ -896,55 +891,72 @@ class BatteryTester(QMainWindow):
|
|||||||
}}
|
}}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# Set initial mode
|
def toggle_test(self):
|
||||||
self.current_mode = "Live Monitoring"
|
"""Toggle between start and stop based on button state"""
|
||||||
self.mode_combo.setCurrentText(self.current_mode)
|
if self.toggle_button.isChecked():
|
||||||
self.change_mode(self.current_mode) # Initialize UI for live mode
|
# Button shows "STOP" - run start logic
|
||||||
|
self.toggle_button.setText("STOP")
|
||||||
|
self.start_test()
|
||||||
|
else:
|
||||||
|
# Button shows "START" - run stop logic
|
||||||
|
self.toggle_button.setText("START")
|
||||||
|
self.stop_test()
|
||||||
|
|
||||||
def change_mode(self, mode_name):
|
def change_mode(self, mode_name):
|
||||||
"""Change between different test modes"""
|
"""Change between different test modes"""
|
||||||
self.current_mode = mode_name
|
self.current_mode = mode_name
|
||||||
self.stop_test() # Stop any current operation
|
self.stop_test() # Stop any current operation
|
||||||
|
|
||||||
# Hide all optional parameters first
|
# Show/hide mode-specific UI elements
|
||||||
self.charge_cutoff_label.hide()
|
show_charge = mode_name in ["Cycle Test", "Charge Test"]
|
||||||
self.charge_cutoff_input.hide()
|
show_discharge = mode_name in ["Cycle Test", "Discharge Test"]
|
||||||
self.discharge_cutoff_label.hide()
|
show_rest = mode_name == "Cycle Test"
|
||||||
self.discharge_cutoff_input.hide()
|
|
||||||
self.rest_time_label.hide()
|
|
||||||
self.rest_time_input.hide()
|
|
||||||
self.continuous_mode_check.hide()
|
|
||||||
self.record_button.hide()
|
|
||||||
|
|
||||||
# Show mode-specific parameters
|
self.charge_cutoff_label.setVisible(show_charge)
|
||||||
|
self.charge_cutoff_input.setVisible(show_charge)
|
||||||
|
self.discharge_cutoff_label.setVisible(show_discharge)
|
||||||
|
self.discharge_cutoff_input.setVisible(show_discharge)
|
||||||
|
self.rest_time_label.setVisible(show_rest)
|
||||||
|
self.rest_time_input.setVisible(show_rest)
|
||||||
|
|
||||||
|
# Continuous mode checkbox only for cycle test
|
||||||
|
self.continuous_mode_check.setVisible(mode_name == "Cycle Test")
|
||||||
|
|
||||||
|
# Record button only for live monitoring
|
||||||
|
self.record_button.setVisible(mode_name == "Live Monitoring")
|
||||||
|
|
||||||
|
# Set button text based on mode
|
||||||
if mode_name == "Cycle Test":
|
if mode_name == "Cycle Test":
|
||||||
self.charge_cutoff_label.show()
|
self.toggle_button.setText("START CYCLE TEST")
|
||||||
self.charge_cutoff_input.show()
|
|
||||||
self.discharge_cutoff_label.show()
|
|
||||||
self.discharge_cutoff_input.show()
|
|
||||||
self.rest_time_label.show()
|
|
||||||
self.rest_time_input.show()
|
|
||||||
self.continuous_mode_check.show()
|
|
||||||
self.start_button.setText("START CYCLE TEST")
|
|
||||||
self.start_button.setEnabled(True) # Explicitly enable
|
|
||||||
elif mode_name == "Discharge Test":
|
elif mode_name == "Discharge Test":
|
||||||
self.discharge_cutoff_label.show()
|
self.toggle_button.setText("START DISCHARGE")
|
||||||
self.discharge_cutoff_input.show()
|
|
||||||
self.start_button.setText("START DISCHARGE")
|
|
||||||
self.start_button.setEnabled(True) # Explicitly enable
|
|
||||||
elif mode_name == "Charge Test":
|
elif mode_name == "Charge Test":
|
||||||
self.charge_cutoff_label.show()
|
self.toggle_button.setText("START CHARGE")
|
||||||
self.charge_cutoff_input.show()
|
|
||||||
self.start_button.setText("START CHARGE")
|
|
||||||
self.start_button.setEnabled(True) # Explicitly enable
|
|
||||||
elif mode_name == "Live Monitoring":
|
elif mode_name == "Live Monitoring":
|
||||||
self.record_button.show()
|
self.toggle_button.setText("START") # Will be hidden anyway
|
||||||
self.start_button.setText("START MONITORING")
|
self.toggle_button.hide()
|
||||||
# Only enable start button if device is connected
|
|
||||||
self.start_button.setEnabled(self.session_active)
|
|
||||||
|
|
||||||
# Reset measurement state
|
# Reset button state
|
||||||
self.reset_test()
|
self.toggle_button.setChecked(False)
|
||||||
|
|
||||||
|
# Reset measurement state and zero the time
|
||||||
|
if self.active_device:
|
||||||
|
dev = self.active_device
|
||||||
|
dev.reset_data() # This clears all data buffers
|
||||||
|
|
||||||
|
# Reset the measurement thread's start time
|
||||||
|
if hasattr(dev, 'measurement_thread'):
|
||||||
|
dev.measurement_thread.start_time = time.time()
|
||||||
|
|
||||||
|
# Reset UI displays
|
||||||
|
self.capacity_label.setText("0.0000")
|
||||||
|
self.energy_label.setText("0.0000")
|
||||||
|
self.cycle_label.setText("0")
|
||||||
|
self.phase_label.setText("Idle")
|
||||||
|
self.time_label.setText("00:00:00")
|
||||||
|
|
||||||
|
# Reset plot
|
||||||
|
self.reset_plot()
|
||||||
|
|
||||||
self.status_bar.showMessage(f"Mode changed to {mode_name}")
|
self.status_bar.showMessage(f"Mode changed to {mode_name}")
|
||||||
|
|
||||||
@ -1092,7 +1104,7 @@ class BatteryTester(QMainWindow):
|
|||||||
self.session_active = True
|
self.session_active = True
|
||||||
self.connection_label.setText(f"Connected: {first_serial}")
|
self.connection_label.setText(f"Connected: {first_serial}")
|
||||||
self.status_light.setStyleSheet("background-color: green; border-radius: 10px;")
|
self.status_light.setStyleSheet("background-color: green; border-radius: 10px;")
|
||||||
self.start_button.setEnabled(True)
|
self.toggle_button.setEnabled(True)
|
||||||
|
|
||||||
# Connect measurement signals
|
# Connect measurement signals
|
||||||
self.measurement_thread = self.active_device.measurement_thread
|
self.measurement_thread = self.active_device.measurement_thread
|
||||||
@ -1180,7 +1192,7 @@ class BatteryTester(QMainWindow):
|
|||||||
self.status_light.setStyleSheet("background-color: orange; border-radius: 10px;")
|
self.status_light.setStyleSheet("background-color: orange; border-radius: 10px;")
|
||||||
self.connection_label.setText("Simulated Devices")
|
self.connection_label.setText("Simulated Devices")
|
||||||
self.session_active = True
|
self.session_active = True
|
||||||
self.start_button.setEnabled(True)
|
self.toggle_button.setEnabled(True)
|
||||||
|
|
||||||
QMessageBox.warning(self, "Simulation Mode",
|
QMessageBox.warning(self, "Simulation Mode",
|
||||||
"Using simulated devices - real hardware not detected")
|
"Using simulated devices - real hardware not detected")
|
||||||
@ -1195,23 +1207,45 @@ class BatteryTester(QMainWindow):
|
|||||||
if serial not in self.devices:
|
if serial not in self.devices:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Stoppe aktuelles Gerät
|
# Stop current device
|
||||||
if self.active_device:
|
if self.active_device:
|
||||||
self.active_device.stop_measurement()
|
try:
|
||||||
if self.measurement_thread:
|
# Disconnect signals safely
|
||||||
self.measurement_thread.update_signal.disconnect()
|
if hasattr(self.active_device, 'measurement_thread'):
|
||||||
|
thread = self.active_device.measurement_thread
|
||||||
|
try:
|
||||||
|
if thread.isRunning():
|
||||||
|
thread.stop()
|
||||||
|
thread.wait(500)
|
||||||
|
thread.update_signal.disconnect()
|
||||||
|
thread.error_signal.disconnect()
|
||||||
|
except (RuntimeError, TypeError) as e:
|
||||||
|
print(f"Signal disconnect warning: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error stopping thread: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error stopping previous device: {e}")
|
||||||
|
|
||||||
# Neues Gerät aktivieren
|
# Activate new device
|
||||||
self.active_device = self.devices[serial]
|
self.active_device = self.devices[serial]
|
||||||
|
|
||||||
|
# Connect signals to new device
|
||||||
|
if hasattr(self.active_device, 'measurement_thread'):
|
||||||
|
try:
|
||||||
self.measurement_thread = self.active_device.measurement_thread
|
self.measurement_thread = self.active_device.measurement_thread
|
||||||
self.measurement_thread.update_signal.connect(self.update_measurements)
|
self.measurement_thread.update_signal.connect(self.update_measurements)
|
||||||
self.measurement_thread.error_signal.connect(self.handle_device_error)
|
self.measurement_thread.error_signal.connect(self.handle_device_error)
|
||||||
|
|
||||||
# Starte Messung erst NACH Verbindung der Signale
|
# Start measurement only AFTER connecting signals
|
||||||
|
if not self.measurement_thread.isRunning():
|
||||||
self.active_device.start_measurement(self.interval)
|
self.active_device.start_measurement(self.interval)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error connecting to new device: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
# UI aktualisieren
|
# Update UI with current device data
|
||||||
self.update_ui_from_active_device()
|
self.update_ui_from_active_device()
|
||||||
|
self.status_bar.showMessage(f"Switched to device: {serial}")
|
||||||
|
|
||||||
def update_ui_from_active_device(self):
|
def update_ui_from_active_device(self):
|
||||||
dev = self.active_device
|
dev = self.active_device
|
||||||
@ -1245,23 +1279,22 @@ class BatteryTester(QMainWindow):
|
|||||||
|
|
||||||
@pyqtSlot(float, float, float)
|
@pyqtSlot(float, float, float)
|
||||||
def update_measurements(self, voltage, current, current_time):
|
def update_measurements(self, voltage, current, current_time):
|
||||||
|
if not self.active_device:
|
||||||
|
return
|
||||||
|
|
||||||
|
dev = self.active_device
|
||||||
|
|
||||||
# Add measurement validation
|
# Add measurement validation
|
||||||
if not self.validate_measurements(voltage, current):
|
if not self.validate_measurements(voltage, current):
|
||||||
print(f"Invalid measurement: V={voltage:.4f}, I={current:.4f}")
|
print(f"Invalid measurement: V={voltage:.4f}, I={current:.4f}")
|
||||||
return
|
return
|
||||||
|
|
||||||
dev_manager = self.active_device
|
|
||||||
dev = self.active_device
|
|
||||||
|
|
||||||
with self.plot_mutex:
|
with self.plot_mutex:
|
||||||
dev_manager.time_data.append(current_time)
|
|
||||||
dev_manager.voltage_data.append(voltage)
|
|
||||||
dev_manager.current_data.append(current)
|
|
||||||
dev.time_data.append(current_time)
|
dev.time_data.append(current_time)
|
||||||
dev.voltage_data.append(voltage)
|
dev.voltage_data.append(voltage)
|
||||||
dev.current_data.append(current)
|
dev.current_data.append(current)
|
||||||
|
|
||||||
# Aggregation für Anzeige (wie bisher)
|
# Aggregation for display
|
||||||
agg_buf = dev.aggregation_buffer
|
agg_buf = dev.aggregation_buffer
|
||||||
agg_buf['time'].append(current_time)
|
agg_buf['time'].append(current_time)
|
||||||
agg_buf['voltage'].append(voltage)
|
agg_buf['voltage'].append(voltage)
|
||||||
@ -1269,7 +1302,7 @@ class BatteryTester(QMainWindow):
|
|||||||
agg_buf['count'] += 1
|
agg_buf['count'] += 1
|
||||||
|
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if now - dev_manager.aggregation_buffer['last_plot_time'] >= 0.1:
|
if now - agg_buf['last_plot_time'] >= 0.1:
|
||||||
agg_time = np.mean(agg_buf['time'])
|
agg_time = np.mean(agg_buf['time'])
|
||||||
agg_voltage = np.mean(agg_buf['voltage'])
|
agg_voltage = np.mean(agg_buf['voltage'])
|
||||||
agg_current = np.mean(agg_buf['current'])
|
agg_current = np.mean(agg_buf['current'])
|
||||||
@ -1282,12 +1315,12 @@ class BatteryTester(QMainWindow):
|
|||||||
'time': [], 'voltage': [], 'current': [], 'count': 0, 'last_plot_time': now
|
'time': [], 'voltage': [], 'current': [], 'count': 0, 'last_plot_time': now
|
||||||
}
|
}
|
||||||
|
|
||||||
# UI-Labels aktualisieren
|
# Update UI labels
|
||||||
self.voltage_label.setText(f"{voltage:.4f}")
|
self.voltage_label.setText(f"{voltage:.4f}")
|
||||||
self.current_label.setText(f"{abs(current):.4f}")
|
self.current_label.setText(f"{abs(current):.4f}")
|
||||||
self.time_label.setText(self.format_time(current_time))
|
self.time_label.setText(self.format_time(current_time))
|
||||||
|
|
||||||
# Kapazität berechnen
|
# Calculate capacity if we have enough data points
|
||||||
if len(dev.time_data) > 1:
|
if len(dev.time_data) > 1:
|
||||||
delta_t = dev.time_data[-1] - dev.time_data[-2]
|
delta_t = dev.time_data[-1] - dev.time_data[-2]
|
||||||
power = voltage * abs(current)
|
power = voltage * abs(current)
|
||||||
@ -1296,7 +1329,7 @@ class BatteryTester(QMainWindow):
|
|||||||
self.capacity_label.setText(f"{dev.capacity_ah:.4f}")
|
self.capacity_label.setText(f"{dev.capacity_ah:.4f}")
|
||||||
self.energy_label.setText(f"{dev.energy:.4f}")
|
self.energy_label.setText(f"{dev.energy:.4f}")
|
||||||
|
|
||||||
# Plot nur alle 100ms aktualisieren
|
# Update plot periodically
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if not hasattr(self, '_last_plot_update'):
|
if not hasattr(self, '_last_plot_update'):
|
||||||
self._last_plot_update = 0
|
self._last_plot_update = 0
|
||||||
@ -1326,17 +1359,22 @@ class BatteryTester(QMainWindow):
|
|||||||
|
|
||||||
def update_status(self):
|
def update_status(self):
|
||||||
"""Update status information periodically"""
|
"""Update status information periodically"""
|
||||||
now = time.time() # Define 'now' at the start of the method
|
now = time.time()
|
||||||
|
|
||||||
if self.test_running or hasattr(self, 'record_button') and self.record_button.isChecked():
|
if not self.active_device:
|
||||||
if self.time_data:
|
return
|
||||||
current_time = self.time_data[-1]
|
|
||||||
if len(self.time_data) > 1:
|
dev = self.active_device
|
||||||
delta_t = self.time_data[-1] - self.time_data[-2]
|
|
||||||
|
if self.test_running or (hasattr(self, 'record_button') and self.record_button.isChecked()):
|
||||||
|
if dev.time_data:
|
||||||
|
current_time = dev.time_data[-1]
|
||||||
|
if len(dev.time_data) > 1:
|
||||||
|
delta_t = dev.time_data[-1] - dev.time_data[-2]
|
||||||
if delta_t > 0:
|
if delta_t > 0:
|
||||||
current_current = abs(self.current_data[-1])
|
current_current = abs(dev.current_data[-1])
|
||||||
self.capacity_ah += current_current * delta_t / 3600
|
dev.capacity_ah += current_current * delta_t / 3600
|
||||||
self.capacity_label.setText(f"{self.capacity_ah:.4f}")
|
self.capacity_label.setText(f"{dev.capacity_ah:.4f}")
|
||||||
|
|
||||||
# Logging (1x per second)
|
# Logging (1x per second)
|
||||||
if (hasattr(self, 'log_writer') and
|
if (hasattr(self, 'log_writer') and
|
||||||
@ -1344,37 +1382,36 @@ class BatteryTester(QMainWindow):
|
|||||||
self.current_cycle_file is not None and
|
self.current_cycle_file is not None and
|
||||||
not self.current_cycle_file.closed):
|
not self.current_cycle_file.closed):
|
||||||
|
|
||||||
# Initialize last log time if not exists
|
|
||||||
if not hasattr(self, '_last_log_time'):
|
if not hasattr(self, '_last_log_time'):
|
||||||
self._last_log_time = now
|
self._last_log_time = now
|
||||||
|
|
||||||
if self.time_data and (now - self._last_log_time >= 1.0):
|
if dev.time_data and (now - self._last_log_time >= 1.0):
|
||||||
try:
|
try:
|
||||||
current_time = self.time_data[-1]
|
current_time = dev.time_data[-1]
|
||||||
voltage = self.voltage_data[-1]
|
voltage = dev.voltage_data[-1]
|
||||||
current = self.current_data[-1]
|
current = dev.current_data[-1]
|
||||||
|
|
||||||
if self.current_mode == "Cycle Test":
|
if self.current_mode == "Cycle Test":
|
||||||
self.log_writer.writerow([
|
self.log_writer.writerow([
|
||||||
f"{current_time:.4f}",
|
f"{current_time:.4f}",
|
||||||
f"{voltage:.6f}",
|
f"{voltage:.6f}",
|
||||||
f"{current:.6f}",
|
f"{current:.6f}",
|
||||||
self.test_phase,
|
dev.test_phase,
|
||||||
f"{self.capacity_ah:.4f}",
|
f"{dev.capacity_ah:.4f}",
|
||||||
f"{self.charge_capacity:.4f}",
|
f"{dev.charge_capacity:.4f}",
|
||||||
f"{self.coulomb_efficiency:.1f}",
|
f"{dev.coulomb_efficiency:.1f}",
|
||||||
f"{self.cycle_count}"
|
f"{dev.cycle_count}"
|
||||||
])
|
])
|
||||||
else:
|
else:
|
||||||
self.log_writer.writerow([
|
self.log_writer.writerow([
|
||||||
f"{current_time:.4f}",
|
f"{current_time:.4f}",
|
||||||
f"{voltage:.6f}",
|
f"{voltage:.6f}",
|
||||||
f"{current:.6f}",
|
f"{current:.6f}",
|
||||||
self.test_phase if hasattr(self, 'test_phase') else "Live",
|
dev.test_phase if hasattr(dev, 'test_phase') else "Live",
|
||||||
f"{self.capacity_ah:.4f}",
|
f"{dev.capacity_ah:.4f}",
|
||||||
f"{voltage * current:.4f}", # Power
|
f"{voltage * current:.4f}", # Power
|
||||||
f"{self.energy:.4f}", # Energy
|
f"{dev.energy:.4f}", # Energy
|
||||||
f"{self.cycle_count}" if hasattr(self, 'cycle_count') else "1"
|
f"{dev.cycle_count}" if hasattr(dev, 'cycle_count') else "1"
|
||||||
])
|
])
|
||||||
self.current_cycle_file.flush()
|
self.current_cycle_file.flush()
|
||||||
self._last_log_time = now
|
self._last_log_time = now
|
||||||
@ -1392,47 +1429,14 @@ class BatteryTester(QMainWindow):
|
|||||||
"""Start the selected test mode using the active device"""
|
"""Start the selected test mode using the active device"""
|
||||||
if not self.active_device:
|
if not self.active_device:
|
||||||
QMessageBox.warning(self, "No Device", "No ADALM1000 device selected.")
|
QMessageBox.warning(self, "No Device", "No ADALM1000 device selected.")
|
||||||
|
self.toggle_button.setChecked(False)
|
||||||
return
|
return
|
||||||
|
|
||||||
dev_manager = self.active_device
|
dev_manager = self.active_device
|
||||||
dev = dev_manager.dev
|
dev = dev_manager.dev
|
||||||
|
|
||||||
# Clean up any previous test
|
# Clean up any previous test
|
||||||
if hasattr(self, 'test_sequence_worker') and self.test_sequence_worker is not None:
|
self.cleanup_test_threads()
|
||||||
try:
|
|
||||||
self.test_sequence_worker.stop()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
self.test_sequence_worker.deleteLater()
|
|
||||||
if hasattr(self, 'test_sequence_thread') and self.test_sequence_thread is not None:
|
|
||||||
self.test_sequence_thread.quit()
|
|
||||||
self.test_sequence_thread.wait(500)
|
|
||||||
self.test_sequence_thread.deleteLater()
|
|
||||||
del self.test_sequence_thread
|
|
||||||
|
|
||||||
if hasattr(self, 'discharge_worker') and self.discharge_worker is not None:
|
|
||||||
try:
|
|
||||||
self.discharge_worker.stop()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
self.discharge_worker.deleteLater()
|
|
||||||
if hasattr(self, 'discharge_thread') and self.discharge_thread is not None:
|
|
||||||
self.discharge_thread.quit()
|
|
||||||
self.discharge_thread.wait(500)
|
|
||||||
self.discharge_thread.deleteLater()
|
|
||||||
del self.discharge_thread
|
|
||||||
|
|
||||||
if hasattr(self, 'charge_worker') and self.charge_worker is not None:
|
|
||||||
try:
|
|
||||||
self.charge_worker.stop()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
self.charge_worker.deleteLater()
|
|
||||||
if hasattr(self, 'charge_thread') and self.charge_thread is not None:
|
|
||||||
self.charge_thread.quit()
|
|
||||||
self.charge_thread.wait(500)
|
|
||||||
self.charge_thread.deleteLater()
|
|
||||||
del self.charge_thread
|
|
||||||
|
|
||||||
# Reset test state for active device
|
# Reset test state for active device
|
||||||
self.reset_test()
|
self.reset_test()
|
||||||
@ -1463,6 +1467,7 @@ class BatteryTester(QMainWindow):
|
|||||||
dev.channels['B'].constant(0)
|
dev.channels['B'].constant(0)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.critical(self, "Device Error", f"Failed to reset device: {e}")
|
QMessageBox.critical(self, "Device Error", f"Failed to reset device: {e}")
|
||||||
|
self.toggle_button.setChecked(False)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Reset test variables
|
# Reset test variables
|
||||||
@ -1480,8 +1485,7 @@ class BatteryTester(QMainWindow):
|
|||||||
|
|
||||||
# Update UI
|
# Update UI
|
||||||
self.phase_label.setText(dev_manager.test_phase)
|
self.phase_label.setText(dev_manager.test_phase)
|
||||||
self.start_button.setEnabled(False)
|
self.toggle_button.setText("STOP")
|
||||||
self.stop_button.setEnabled(True)
|
|
||||||
|
|
||||||
# Get parameters from UI
|
# Get parameters from UI
|
||||||
try:
|
try:
|
||||||
@ -1495,7 +1499,7 @@ class BatteryTester(QMainWindow):
|
|||||||
self.stop_test()
|
self.stop_test()
|
||||||
return
|
return
|
||||||
|
|
||||||
# Create log file (now includes device serial)
|
# Create log file
|
||||||
if not self.create_cycle_log_file():
|
if not self.create_cycle_log_file():
|
||||||
self.stop_test()
|
self.stop_test()
|
||||||
return
|
return
|
||||||
@ -1667,8 +1671,8 @@ class BatteryTester(QMainWindow):
|
|||||||
self.test_phase = "Initial Discharge"
|
self.test_phase = "Initial Discharge"
|
||||||
self.phase_label.setText(self.test_phase)
|
self.phase_label.setText(self.test_phase)
|
||||||
|
|
||||||
self.start_button.setEnabled(False)
|
self.toggle_button.setChecked(True)
|
||||||
self.stop_button.setEnabled(True)
|
self.toggle_button.setText("STOP")
|
||||||
self.status_bar.showMessage(f"Cycle test started | Current: {test_current:.4f}A")
|
self.status_bar.showMessage(f"Cycle test started | Current: {test_current:.4f}A")
|
||||||
|
|
||||||
# Create log file
|
# Create log file
|
||||||
@ -1703,8 +1707,9 @@ class BatteryTester(QMainWindow):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.critical(self, "Error", str(e))
|
QMessageBox.critical(self, "Error", str(e))
|
||||||
# Ensure buttons are in correct state if error occurs
|
# Ensure buttons are in correct state if error occurs
|
||||||
self.start_button.setEnabled(True)
|
self.toggle_button.setChecked(False)
|
||||||
self.stop_button.setEnabled(False)
|
self.toggle_button.setText("START")
|
||||||
|
self.toggle_button.setEnabled(True)
|
||||||
|
|
||||||
def start_discharge_test(self):
|
def start_discharge_test(self):
|
||||||
"""Start the battery discharge test"""
|
"""Start the battery discharge test"""
|
||||||
@ -1808,8 +1813,9 @@ class BatteryTester(QMainWindow):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.critical(self, "Error", str(e))
|
QMessageBox.critical(self, "Error", str(e))
|
||||||
# Ensure buttons are in correct state if error occurs
|
# Ensure buttons are in correct state if error occurs
|
||||||
self.start_button.setEnabled(True)
|
self.toggle_button.setChecked(False)
|
||||||
self.stop_button.setEnabled(False)
|
self.toggle_button.setText("START")
|
||||||
|
self.toggle_button.setEnabled(True)
|
||||||
|
|
||||||
def start_charge_test(self):
|
def start_charge_test(self):
|
||||||
"""Start the battery charge test"""
|
"""Start the battery charge test"""
|
||||||
@ -1912,8 +1918,9 @@ class BatteryTester(QMainWindow):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.critical(self, "Error", str(e))
|
QMessageBox.critical(self, "Error", str(e))
|
||||||
self.start_button.setEnabled(True)
|
self.toggle_button.setChecked(False)
|
||||||
self.stop_button.setEnabled(False)
|
self.toggle_button.setText("START")
|
||||||
|
self.toggle_button.setEnabled(True)
|
||||||
|
|
||||||
def start_live_monitoring(self):
|
def start_live_monitoring(self):
|
||||||
"""Start live monitoring mode for the active device"""
|
"""Start live monitoring mode for the active device"""
|
||||||
@ -1949,6 +1956,9 @@ class BatteryTester(QMainWindow):
|
|||||||
self.stop_button.setEnabled(True)
|
self.stop_button.setEnabled(True)
|
||||||
self.start_button.setEnabled(False)
|
self.start_button.setEnabled(False)
|
||||||
|
|
||||||
|
# Hide the toggle button in Live mode
|
||||||
|
self.toggle_button.hide()
|
||||||
|
|
||||||
# Status
|
# Status
|
||||||
self.status_bar.showMessage(f"Live monitoring started | Device: {dev.serial}")
|
self.status_bar.showMessage(f"Live monitoring started | Device: {dev.serial}")
|
||||||
|
|
||||||
@ -2101,8 +2111,14 @@ class BatteryTester(QMainWindow):
|
|||||||
self.active_device.test_phase = "Idle"
|
self.active_device.test_phase = "Idle"
|
||||||
self.phase_label.setText("Idle")
|
self.phase_label.setText("Idle")
|
||||||
|
|
||||||
self.stop_button.setEnabled(False)
|
# Reset button state
|
||||||
self.start_button.setEnabled(True)
|
self.toggle_button.setChecked(False)
|
||||||
|
if self.current_mode == "Cycle Test":
|
||||||
|
self.toggle_button.setText("START CYCLE TEST")
|
||||||
|
elif self.current_mode == "Discharge Test":
|
||||||
|
self.toggle_button.setText("START DISCHARGE")
|
||||||
|
elif self.current_mode == "Charge Test":
|
||||||
|
self.toggle_button.setText("START CHARGE")
|
||||||
|
|
||||||
if self.current_mode == "Live Monitoring":
|
if self.current_mode == "Live Monitoring":
|
||||||
self.status_bar.showMessage("Live monitoring stopped")
|
self.status_bar.showMessage("Live monitoring stopped")
|
||||||
@ -2226,8 +2242,9 @@ class BatteryTester(QMainWindow):
|
|||||||
|
|
||||||
# 7. Reset UI and state
|
# 7. Reset UI and state
|
||||||
self.request_stop = False
|
self.request_stop = False
|
||||||
self.start_button.setEnabled(True)
|
self.toggle_button.setChecked(False)
|
||||||
self.stop_button.setEnabled(False)
|
self.toggle_button.setText("START")
|
||||||
|
self.toggle_button.setEnabled(True)
|
||||||
|
|
||||||
# 8. Show completion message if test wasn't stopped by user
|
# 8. Show completion message if test wasn't stopped by user
|
||||||
if not self.request_stop:
|
if not self.request_stop:
|
||||||
@ -2285,8 +2302,9 @@ class BatteryTester(QMainWindow):
|
|||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
# Ensure we don't leave the UI in a locked state
|
# Ensure we don't leave the UI in a locked state
|
||||||
self.start_button.setEnabled(True)
|
self.toggle_button.setChecked(False)
|
||||||
self.stop_button.setEnabled(False)
|
self.toggle_button.setText("START")
|
||||||
|
self.toggle_button.setEnabled(True)
|
||||||
self.status_bar.showMessage("Error during test finalization")
|
self.status_bar.showMessage("Error during test finalization")
|
||||||
|
|
||||||
def reset_plot(self):
|
def reset_plot(self):
|
||||||
@ -2580,7 +2598,7 @@ class BatteryTester(QMainWindow):
|
|||||||
self.connection_label.setText(f"Connected: {self.active_device.serial}")
|
self.connection_label.setText(f"Connected: {self.active_device.serial}")
|
||||||
self.status_bar.showMessage("Successfully reconnected devices")
|
self.status_bar.showMessage("Successfully reconnected devices")
|
||||||
self.status_light.setStyleSheet("background-color: green; border-radius: 10px;")
|
self.status_light.setStyleSheet("background-color: green; border-radius: 10px;")
|
||||||
self.start_button.setEnabled(True)
|
self.toggle_button.setEnabled(True)
|
||||||
return
|
return
|
||||||
|
|
||||||
except DeviceDisconnectedError as e:
|
except DeviceDisconnectedError as e:
|
||||||
@ -2640,4 +2658,6 @@ if __name__ == "__main__":
|
|||||||
window.show()
|
window.show()
|
||||||
app.exec_()
|
app.exec_()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
QMessageBox.critical(None, "Fatal Error", f"Application failed: {str(e)}")
|
QMessageBox.critical(None, "Fatal Error", f"Application failed: {str(e)}")
|
||||||
Loading…
x
Reference in New Issue
Block a user