Add device selection
This commit is contained in:
parent
98f365b6af
commit
8d6ae914db
@ -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")
|
||||
|
27
app/ui/widgets/device_select.py
Normal file
27
app/ui/widgets/device_select.py
Normal 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
|
Loading…
x
Reference in New Issue
Block a user