Add device selection

This commit is contained in:
CPD 2025-02-25 12:12:42 +01:00
parent 98f365b6af
commit 8d6ae914db
2 changed files with 170 additions and 18 deletions

View File

@ -1,14 +1,26 @@
''' app/ui/main_window.py '''
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QTextEdit, QLabel
from ..utils.config import AppConfig
from PyQt6.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QTextEdit, QLabel, QDialog
from PyQt6.QtGui import QIcon
from .widgets.menubar import MenuBar
from .widgets.toolbar import ToolBar
from .widgets.statusbar import StatusBar
from .widgets.metadata_input import MetadataInput
from .widgets.plot import Plot
from .widgets.device_select import ListChoice
# from .widgets.treeview import TreeView
import multiprocessing as mp
import threading as mt
from ..utility.config import AppConfig
import cpdctrl.voltage_measurement_device as vmd
import cpdctrl.led_control_device as ledd
from cpdctrl.led_script import LedScript
from cpdctrl.utility.data import DataCollector
from cpdctrl.measurement import measure
class MainWindow(QMainWindow):
"""
@ -50,6 +62,14 @@ class MainWindow(QMainWindow):
layout.addWidget(MetadataInput(init_elements))
layout.addWidget(Plot())
self.verbose = True
# devices
self.vmdev = None
self.leddev = None
self.vmdev_autoconnect()
self.leddev_autoconnect()
def create_toolbars(self) -> None:
"""
Creates and adds the top and right toolbars to the main window.
@ -59,13 +79,11 @@ class MainWindow(QMainWindow):
style=Qt.ToolButtonStyle.ToolButtonTextUnderIcon, icon_size=(24, 24))
# Top Toolbar Buttons
self.topbar.add_button(
"Open", "resources/assets/icons/windows/imageres-10.ico", self.open_file)
self.topbar.add_button(
"Save", "resources/assets/icons/windows/shell32-259.ico", self.save_file)
self.topbar.add_button("Devices", QIcon.fromTheme(QIcon.ThemeIcon.Printer), self.vmdev_connect_from_dialog)
self.topbar.add_button("Start", QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStart), self.measure_start)
self.topbar.add_button("Save", "resources/assets/icons/windows/shell32-259.ico", self.save_file)
self.topbar.add_separator()
self.topbar.add_button(
"Exit", "resources/assets/icons/windows/shell32-220.ico", self.exit_app)
self.topbar.add_button("Exit", "resources/assets/icons/windows/shell32-220.ico", self.exit_app)
# Right Toolbar [PyQt6.QtWidgets.QToolBar]
self.rightbar = ToolBar(self, orientation=Qt.Orientation.Vertical,
@ -74,10 +92,7 @@ class MainWindow(QMainWindow):
# Right Toolbar Buttons
self.rightbar.add_separator()
self.rightbar.add_button(
"Privacy", "resources/assets/icons/windows/shell32-167.ico", self.privacy_window)
self.rightbar.add_button(
"Settings", "resources/assets/icons/windows/shell32-315.ico", self.settings_window)
self.rightbar.add_button("Settings", "resources/assets/icons/windows/shell32-315.ico", self.settings_window)
self.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.topbar)
self.addToolBar(Qt.ToolBarArea.RightToolBarArea, self.rightbar)
@ -88,6 +103,122 @@ class MainWindow(QMainWindow):
"""
# return TreeView(self)
def leddev_connect(self, leddev_type, leddev_name):
self.leddev = ledd.connect_device(leddev_type, leddev_name)
AppConfig.MAIN_CFG.set("led_device_last.type", leddev_type)
AppConfig.MAIN_CFG.set("led_device_last.name", leddev_name)
def leddev_autoconnect(self):
if AppConfig.MAIN_CFG.get_or("led_device_auto_reconnect", False):
try:
leddev_type = AppConfig.MAIN_CFG.get("led_device_last.type")
leddev_name = AppConfig.MAIN_CFG.get("led_device_last.name")
self.leddev_connect(leddev_type, leddev_name)
except KeyError:
pass
def leddev_connect_from_dialog(self):
"""
Open a dialog that lets the user choose a LED control device,
and then connects to the device.
"""
devices = ledd.list_devices()
device_dialog = ListChoice(devices)
if device_dialog.exec() == QDialog.DialogCode.Accepted:
leddev_type, leddev_name = device_dialog.get_selected()
if self.verbose: print(f"Connecting to {leddev_type}:{leddev_name}")
self.leddev_connect(leddev_type, leddev_name)
def vmdev_connect(self, vmdev_type, vmdev_name):
self.vmdev = vmd.connect_device(vmdev_type, vmdev_name)
AppConfig.MAIN_CFG.set("voltage_measurement_device_last.type", vmdev_type)
AppConfig.MAIN_CFG.set("voltage_measurement_device_last.name", vmdev_name)
def vmdev_autoconnect(self):
if AppConfig.MAIN_CFG.get_or("voltage_measurement_device_auto_reconnect", False):
try:
vmdev_type = AppConfig.MAIN_CFG.get("voltage_measurement_device_last.type")
vmdev_name = AppConfig.MAIN_CFG.get("voltage_measurement_device_last.name")
self.vmdev_connect(vmdev_type, vmdev_name)
except KeyError:
pass
def vmdev_connect_from_dialog(self):
"""
Open a dialog that lets the user choose a voltage measurement device,
and then connects to the device.
"""
devices = vmd.list_devices()
device_dialog = ListChoice(devices)
if device_dialog.exec() == QDialog.DialogCode.Accepted:
vmdev_type, vmdev_name = device_dialog.get_selected()
if self.verbose: print(f"Connecting to {vmdev_type}:{vmdev_name}")
self.vmdev_connect(vmdev_type, vmdev_name)
def measure_start(self):
if self.vmdev is None:
self.vmdev_connect_from_dialog()
if self.vmdev is None:
raise ValueError("No measurement device selected")
if self.leddev is None:
self.leddev_connect_from_dialog()
if self.leddev is None:
raise ValueError("No led control device selected")
script = 100
measurement_name = "guitest"
led_script = LedScript(script=script)
flush_after = AppConfig.MAIN_CFG.get_or("flush_after", None)
use_buffer = AppConfig.MAIN_CFG.get_or("use_buffer", False)
max_measurements = AppConfig.MAIN_CFG.get_or("max_measurements", None)
stop_on_script_end = AppConfig.MAIN_CFG.get_or("stop_on_script_end", False)
interval = AppConfig.MAIN_CFG.get_or("measurement_interval_s", 1.0)
metadata = {}
metadata["interval"] = str(interval)
metadata["name"] = measurement_name
metadata["led"] = "led"
metadata["led_script"] = str(script)
if self.verbose:
print(f"Starting measurement with:\n\tinterval = {interval}\n\tflush_after = {flush_after}\n\tuse_buffer = {use_buffer}\n\tmax_measurements = {max_measurements}\n\tstop_on_script_end = {stop_on_script_end}")
led_script = LedScript(script=script, auto_update=True, verbose=True)
data_collector = DataCollector(metadata=metadata, data_path=AppConfig.MAIN_CFG.get("datadir"), data_name=measurement_name)
# data_collector.clear()
data_queue = mp.Queue()
command_queue = mp.Queue()
# Argument order must match the definition
proc_measure = mt.Thread(target=measure, args=(
self.vmdev,
self.leddev,
led_script,
data_collector,
interval,
flush_after,
use_buffer,
max_measurements,
stop_on_script_end,
self.verbose, # verbose
command_queue,
data_queue
))
proc_measure.start()
try:
while proc_measure.is_alive():
while not data_queue.empty():
# print(data_queue.qsize(), "\n\n")
current_data = data_queue.get(block=False)
i, tval, vval, led_val = current_data
print(f"Data {i:03}: {tval}s, {vval}V, {led_val}%")
except KeyboardInterrupt:
pass
command_queue.put("stop")
proc_measure.join()
print("Measurement stopped" + " " * 50)
led_script.stop_updating() # stop watching for file updates (if enabled)
data_collector.save_csv(verbose=True)
data, metadata = data_collector.get_data()
def create_edit(self) -> QTextEdit:
"""
Creates and adds the QTextEdit widget to the main window.
@ -116,9 +247,3 @@ class MainWindow(QMainWindow):
"""
Event handler for the "Settings" button. Displays the "Settings" window.
"""
def privacy_window(self) -> None:
"""
Event handler for the "Privacy" button. Displays the "Privacy" window.
"""
print("privacy_window")

View File

@ -0,0 +1,27 @@
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QListWidget, QListWidgetItem, QLabel, QDialogButtonBox, QDialog
from typing import Callable
# QT6 non-window that presents a list of devices of which one can be connected
class ListChoice(QDialog):
def __init__(self, items: dict[str, list[str]], parent=None):
super().__init__(parent)
self.setWindowTitle("Select Device")
self.setLayout(QVBoxLayout())
self.layout().addWidget(QLabel("Select a device to connect to:"))
self.device_list = QListWidget()
self.layout().addWidget(self.device_list)
for key, items in items.items():
for item in items:
w = QListWidgetItem(f"{key}: {item}", parent=self.device_list)
w.key = key
w.item = item
# self.device_list.addItem(f"{key}: {item}")
self.buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
self.layout().addWidget(self.buttons)
self.buttons.accepted.connect(self.accept)
self.buttons.rejected.connect(self.reject)
def get_selected(self):
selected_item = self.device_list.currentItem()
return selected_item.key, selected_item.item