2023-07-26 13:03:16 +08:00
from PyQt6 import QtWidgets , QtGui , QtCore
2023-06-27 17:34:39 +08:00
from PyQt6 . QtCore import pyqtSignal , QObject , QSignalBlocker , pyqtSlot
2023-08-04 13:30:44 +08:00
from pyqtgraph . parametertree import Parameter , ParameterTree , ParameterItem
2023-05-19 11:23:39 +08:00
import pyqtgraph as pg
2023-07-06 16:06:33 +08:00
from pglive . sources . data_connector import DataConnector
from pglive . kwargs import Axis
from pglive . sources . live_plot import LiveLinePlot
from pglive . sources . live_plot_widget import LivePlotWidget
from pglive . sources . live_axis import LiveAxis
2023-05-19 11:23:39 +08:00
import sys
import argparse
import logging
2023-06-26 10:20:48 +08:00
import asyncio
2023-07-31 12:33:00 +08:00
from pytec . aioclient import Client , StoppedConnecting
2023-06-27 17:34:39 +08:00
import qasync
from qasync import asyncSlot , asyncClose
2023-05-19 11:23:39 +08:00
# pyuic6 -x tec_qt.ui -o ui_tec_qt.py
from ui_tec_qt import Ui_MainWindow
2023-06-28 15:01:47 +08:00
class CommandsParameter ( Parameter ) :
2023-08-08 12:41:57 +08:00
pass
2023-06-28 15:01:47 +08:00
2023-07-14 16:14:19 +08:00
THERMOSTAT_PARAMETERS = [ [
2023-06-28 15:01:47 +08:00
{ ' name ' : ' Constant Current ' , ' type ' : ' float ' , ' value ' : 0 , ' step ' : 0.1 , ' limits ' : ( - 3 , 3 ) , ' siPrefix ' : True ,
' suffix ' : ' A ' , ' commands ' : [ f ' pwm { ch } i_set {{ value }} ' ] } ,
2023-08-04 17:46:38 +08:00
{ ' name ' : ' Temperature PID ' , ' type ' : ' bool ' , ' value ' : False , ' commands ' : [ f ' pwm { ch } pid ' ] ,
2023-06-28 15:01:47 +08:00
' children ' : [
{ ' name ' : ' Set Temperature ' , ' type ' : ' float ' , ' value ' : 25 , ' step ' : 0.1 , ' limits ' : ( - 273 , 300 ) , ' siPrefix ' : True ,
2023-08-04 17:46:38 +08:00
' suffix ' : ' °C ' , ' commands ' : [ f ' pid { ch } target {{ value }} ' ] } ,
2023-06-28 15:01:47 +08:00
] } ,
{ ' name ' : ' Output Config ' , ' expanded ' : False , ' type ' : ' group ' , ' children ' : [
2023-08-04 12:57:46 +08:00
{ ' name ' : ' Max Current ' , ' type ' : ' float ' , ' value ' : 0 , ' step ' : 0.1 , ' limits ' : ( 0 , 3 ) , ' siPrefix ' : True , ' prefix ' : ' ± ' ,
2023-06-28 15:01:47 +08:00
' suffix ' : ' A ' , ' commands ' : [ f ' pwm { ch } max_i_pos {{ value }} ' , f ' pwm { ch } max_i_neg {{ value }} ' ,
f ' pid { ch } output_min - {{ value }} ' , f ' pid { ch } output_max {{ value }} ' ] } ,
{ ' name ' : ' Max Voltage ' , ' type ' : ' float ' , ' value ' : 0 , ' step ' : 0.1 , ' limits ' : ( 0 , 5 ) , ' siPrefix ' : True ,
' suffix ' : ' V ' , ' commands ' : [ f ' pwm { ch } max_v {{ value }} ' ] } ,
] } ,
{ ' name ' : ' Thermistor Config ' , ' expanded ' : False , ' type ' : ' group ' , ' children ' : [
2023-07-18 17:16:35 +08:00
{ ' name ' : ' T₀ ' , ' type ' : ' float ' , ' value ' : 25 , ' step ' : 0.1 , ' limits ' : ( - 100 , 100 ) , ' siPrefix ' : True ,
' suffix ' : ' °C ' , ' commands ' : [ f ' s-h { ch } t0 {{ value }} ' ] } ,
{ ' name ' : ' R₀ ' , ' type ' : ' float ' , ' value ' : 10000 , ' step ' : 1 , ' siPrefix ' : True , ' suffix ' : ' Ω ' ,
2023-06-28 15:01:47 +08:00
' commands ' : [ f ' s-h { ch } r0 {{ value }} ' ] } ,
2023-07-18 17:16:35 +08:00
{ ' name ' : ' β ' , ' type ' : ' float ' , ' value ' : 3950 , ' step ' : 1 , ' suffix ' : ' K ' , ' commands ' : [ f ' s-h { ch } b {{ value }} ' ] } ,
2023-06-28 15:01:47 +08:00
] } ,
2023-08-01 13:32:06 +08:00
{ ' name ' : ' Postfilter Config ' , ' expanded ' : False , ' type ' : ' group ' , ' children ' : [
{ ' name ' : ' Rate ' , ' type ' : ' float ' , ' value ' : 16.67 , ' step ' : 0.01 , ' suffix ' : ' Hz ' ,
' commands ' : [ f ' postfilter { ch } rate {{ value }} ' ] } ,
] } ,
2023-06-28 15:01:47 +08:00
{ ' name ' : ' PID Config ' , ' expanded ' : False , ' type ' : ' group ' , ' children ' : [
2023-07-18 17:16:35 +08:00
{ ' name ' : ' Kp ' , ' type ' : ' float ' , ' value ' : 0 , ' step ' : 0.1 , ' suffix ' : ' °C/A ' , ' commands ' : [ f ' pid { ch } kp {{ value }} ' ] } ,
{ ' name ' : ' Ki ' , ' type ' : ' float ' , ' value ' : 0 , ' step ' : 0.1 , ' suffix ' : ' °C/C ' , ' commands ' : [ f ' pid { ch } ki {{ value }} ' ] } ,
{ ' name ' : ' Kd ' , ' type ' : ' float ' , ' value ' : 0 , ' step ' : 0.1 , ' suffix ' : ' °Cs²/C ' , ' commands ' : [ f ' pid { ch } kd {{ value }} ' ] } ,
2023-06-28 15:01:47 +08:00
{ ' name ' : ' PID Auto Tune ' , ' expanded ' : False , ' type ' : ' group ' , ' children ' : [
2023-07-18 17:16:35 +08:00
{ ' name ' : ' Target Temperature ' , ' type ' : ' float ' , ' value ' : 20 , ' step ' : 0.1 , ' siPrefix ' : True , ' suffix ' : ' °C ' } ,
2023-06-28 15:01:47 +08:00
{ ' name ' : ' Test Current ' , ' type ' : ' float ' , ' value ' : 1 , ' step ' : 0.1 , ' siPrefix ' : True , ' suffix ' : ' A ' } ,
2023-08-01 13:32:55 +08:00
{ ' name ' : ' Temperature Swing ' , ' type ' : ' float ' , ' value ' : 1.5 , ' step ' : 0.1 , ' siPrefix ' : True , ' prefix ' : ' ± ' , ' suffix ' : ' °C ' } ,
2023-06-28 15:01:47 +08:00
{ ' name ' : ' Run ' , ' type ' : ' action ' , ' tip ' : ' Run ' } ,
] } ,
2023-07-28 11:34:34 +08:00
] } ,
2023-08-14 16:34:46 +08:00
{ ' name ' : ' Save to flash ' , ' type ' : ' action ' , ' tip ' : ' Save config to thermostat, applies on reset ' , ' commands ' : [ f ' save { ch } ' ] }
2023-06-28 15:01:47 +08:00
] for ch in range ( 2 ) ]
2023-07-14 16:14:19 +08:00
2023-05-19 11:23:39 +08:00
def get_argparser ( ) :
parser = argparse . ArgumentParser ( description = " ARTIQ master " )
parser . add_argument ( " --connect " , default = None , action = " store_true " ,
help = " Automatically connect to the specified Thermostat in IP:port format " )
parser . add_argument ( ' IP ' , metavar = " ip " , default = None , nargs = ' ? ' )
parser . add_argument ( ' PORT ' , metavar = " port " , default = None , nargs = ' ? ' )
parser . add_argument ( " -l " , " --log " , dest = " logLevel " , choices = [ ' DEBUG ' , ' INFO ' , ' WARNING ' , ' ERROR ' , ' CRITICAL ' ] ,
help = " Set the logging level " )
return parser
2023-08-09 11:15:29 +08:00
class WrappedClient ( QObject , Client ) :
connection_error = pyqtSignal ( )
2023-08-11 17:09:33 +08:00
def __init__ ( self , parent ) :
super ( ) . __init__ ( parent )
2023-08-09 11:15:29 +08:00
async def _read_line ( self ) :
try :
return await super ( ) . _read_line ( )
except ( OSError , TimeoutError , asyncio . TimeoutError ) as e : # TODO: Remove asyncio.TimeoutError in Python 3.11
logging . error ( " Client connection error, disconnecting " , exc_info = True )
self . connection_error . emit ( )
2023-08-11 17:09:33 +08:00
async def _check_zero_limits ( self ) :
pwm_report = await self . get_pwm ( )
for pwm_channel in pwm_report :
if ( neg := pwm_channel [ " max_i_neg " ] [ " value " ] ) != ( pos := pwm_channel [ " max_i_pos " ] [ " value " ] ) :
# Set the minimum of the 2
lcd = min ( neg , pos )
await self . set_param ( " pwm " , pwm_channel [ " channel " ] , ' max_i_neg ' , lcd )
await self . set_param ( " pwm " , pwm_channel [ " channel " ] , ' max_i_pos ' , lcd )
for limit in [ " max_i_pos " , " max_v " ] :
if pwm_channel [ limit ] [ " value " ] == 0.0 :
QtWidgets . QMessageBox . warning ( self . parent ( ) , " Limits " , " Max {} is set to zero on channel {} ! " . format ( " Current " if limit == " max_i_pos " else " Voltage " , pwm_channel [ " channel " ] ) )
2023-08-09 11:15:29 +08:00
2023-06-26 10:20:48 +08:00
class ClientWatcher ( QObject ) :
2023-07-11 12:27:43 +08:00
fan_update = pyqtSignal ( dict )
pwm_update = pyqtSignal ( list )
report_update = pyqtSignal ( list )
pid_update = pyqtSignal ( list )
2023-07-20 13:49:11 +08:00
thermistor_update = pyqtSignal ( list )
2023-08-01 13:32:06 +08:00
postfilter_update = pyqtSignal ( list )
2023-05-19 13:45:01 +08:00
2023-07-05 16:25:13 +08:00
def __init__ ( self , parent , client , update_s ) :
2023-08-16 12:25:51 +08:00
self . _update_s = update_s
self . _client = client
self . _watch_task = None
2023-08-16 13:07:26 +08:00
self . _report_mode_task = None
2023-08-16 12:25:51 +08:00
self . _poll_for_report = True
2023-05-19 13:45:01 +08:00
super ( ) . __init__ ( parent )
2023-06-26 10:20:48 +08:00
async def run ( self ) :
2023-08-08 17:16:11 +08:00
loop = asyncio . get_running_loop ( )
2023-07-13 15:45:08 +08:00
while True :
2023-08-08 17:16:11 +08:00
time = loop . time ( )
2023-06-27 17:34:39 +08:00
await self . update_params ( )
2023-08-16 12:25:51 +08:00
await asyncio . sleep ( self . _update_s - ( loop . time ( ) - time ) )
2023-05-19 13:45:01 +08:00
2023-06-27 17:34:39 +08:00
async def update_params ( self ) :
2023-08-16 12:25:51 +08:00
self . fan_update . emit ( await self . _client . get_fan ( ) )
self . pwm_update . emit ( await self . _client . get_pwm ( ) )
if self . _poll_for_report :
self . report_update . emit ( await self . _client . report ( ) )
self . pid_update . emit ( await self . _client . get_pid ( ) )
self . thermistor_update . emit ( await self . _client . get_steinhart_hart ( ) )
self . postfilter_update . emit ( await self . _client . get_postfilter ( ) )
2023-05-19 13:45:01 +08:00
2023-07-06 11:21:56 +08:00
def start_watching ( self ) :
2023-08-16 12:25:51 +08:00
self . _watch_task = asyncio . create_task ( self . run ( ) )
2023-07-06 11:21:56 +08:00
2023-05-19 13:45:01 +08:00
@pyqtSlot ( )
def stop_watching ( self ) :
2023-08-16 12:25:51 +08:00
if self . _watch_task is not None :
self . _watch_task . cancel ( )
self . _watch_task = None
2023-05-19 13:45:01 +08:00
2023-08-16 13:07:26 +08:00
async def set_report_mode ( self , enabled : bool ) :
self . _poll_for_report = not enabled
if enabled :
self . _report_mode_task = asyncio . create_task ( self . report_mode ( ) )
else :
self . _client . stop_report_mode ( )
if self . _report_mode_task is not None :
await self . _report_mode_task
self . _report_mode_task = None
async def report_mode ( self ) :
async for report in self . _client . report_mode ( ) :
self . report_update . emit ( report )
2023-07-11 12:27:43 +08:00
@pyqtSlot ( float )
2023-07-01 23:46:40 +08:00
def set_update_s ( self , update_s ) :
2023-08-16 12:25:51 +08:00
self . _update_s = update_s
2023-07-01 23:46:40 +08:00
class MainWindow ( QtWidgets . QMainWindow , Ui_MainWindow ) :
2023-07-06 16:06:33 +08:00
""" The maximum number of sample points to store. """
DEFAULT_MAX_SAMPLES = 1000
2023-07-01 23:46:40 +08:00
def __init__ ( self , args ) :
super ( ) . __init__ ( )
self . setupUi ( self )
2023-07-06 16:06:33 +08:00
self . max_samples = self . DEFAULT_MAX_SAMPLES
2023-07-31 16:19:07 +08:00
self . _set_up_connection_menu ( )
self . _set_up_thermostat_menu ( )
self . _set_up_plot_menu ( )
2023-07-19 11:38:04 +08:00
2023-08-08 11:39:39 +08:00
self . params = [
CommandsParameter . create ( name = f " Thermostat Channel { ch } Parameters " , type = ' group ' , value = ch , children = THERMOSTAT_PARAMETERS [ ch ] )
for ch in range ( 2 )
]
2023-06-28 15:01:47 +08:00
self . _set_param_tree ( )
2023-07-06 16:06:33 +08:00
self . ch0_t_plot = LiveLinePlot ( )
self . ch0_i_plot = LiveLinePlot ( )
2023-08-10 13:28:26 +08:00
self . ch0_iset_plot = LiveLinePlot ( pen = pg . mkPen ( ' r ' ) )
2023-07-06 16:06:33 +08:00
self . ch1_t_plot = LiveLinePlot ( )
self . ch1_i_plot = LiveLinePlot ( )
2023-08-10 13:28:26 +08:00
self . ch1_iset_plot = LiveLinePlot ( pen = pg . mkPen ( ' r ' ) )
2023-07-06 16:06:33 +08:00
2023-08-02 12:38:45 +08:00
self . ch0_t_line = self . ch0_t_graph . getPlotItem ( ) . addLine ( label = ' {value} °C ' )
self . ch0_t_line . setVisible ( False )
self . ch1_t_line = self . ch1_t_graph . getPlotItem ( ) . addLine ( label = ' {value} °C ' )
self . ch1_t_line . setVisible ( False )
2023-07-06 16:06:33 +08:00
self . _set_up_graphs ( )
self . ch0_t_connector = DataConnector ( self . ch0_t_plot , max_points = self . DEFAULT_MAX_SAMPLES )
self . ch0_i_connector = DataConnector ( self . ch0_i_plot , max_points = self . DEFAULT_MAX_SAMPLES )
2023-08-10 13:28:26 +08:00
self . ch0_iset_connector = DataConnector ( self . ch0_iset_plot , max_points = self . DEFAULT_MAX_SAMPLES )
2023-07-06 16:06:33 +08:00
self . ch1_t_connector = DataConnector ( self . ch1_t_plot , max_points = self . DEFAULT_MAX_SAMPLES )
self . ch1_i_connector = DataConnector ( self . ch1_i_plot , max_points = self . DEFAULT_MAX_SAMPLES )
2023-08-10 13:28:26 +08:00
self . ch1_iset_connector = DataConnector ( self . ch1_iset_plot , max_points = self . DEFAULT_MAX_SAMPLES )
2023-07-06 16:06:33 +08:00
2023-07-26 17:44:15 +08:00
self . hw_rev_data = None
2023-07-07 17:19:17 +08:00
2023-08-11 17:09:33 +08:00
self . client = WrappedClient ( self )
2023-08-09 11:15:29 +08:00
self . client . connection_error . connect ( self . bail )
2023-07-31 16:36:48 +08:00
self . client_watcher = ClientWatcher ( self , self . client , self . report_refresh_spin . value ( ) )
2023-07-14 16:10:59 +08:00
self . client_watcher . fan_update . connect ( self . fan_update )
2023-07-06 16:06:33 +08:00
self . client_watcher . report_update . connect ( self . plot )
2023-07-20 13:47:39 +08:00
self . client_watcher . report_update . connect ( self . update_report )
2023-07-20 13:48:33 +08:00
self . client_watcher . pid_update . connect ( self . update_pid )
2023-07-20 13:49:23 +08:00
self . client_watcher . pwm_update . connect ( self . update_pwm )
2023-07-20 13:49:11 +08:00
self . client_watcher . thermistor_update . connect ( self . update_thermistor )
2023-08-01 13:32:06 +08:00
self . client_watcher . postfilter_update . connect ( self . update_postfilter )
2023-07-14 16:10:59 +08:00
self . report_apply_btn . clicked . connect (
lambda : self . client_watcher . set_update_s ( self . report_refresh_spin . value ( ) )
)
2023-07-01 23:46:40 +08:00
if args . connect :
if args . IP :
2023-07-31 13:06:24 +08:00
self . host_set_line . setText ( args . IP )
2023-07-01 23:46:40 +08:00
if args . PORT :
self . port_set_spin . setValue ( int ( args . PORT ) )
self . connect_btn . click ( )
2023-07-31 16:19:07 +08:00
def _set_up_connection_menu ( self ) :
2023-07-26 16:01:57 +08:00
_translate = QtCore . QCoreApplication . translate
2023-07-26 16:43:24 +08:00
self . connection_menu = QtWidgets . QMenu ( )
self . connection_menu . setTitle ( ' Connection Settings ' )
2023-07-19 12:49:15 +08:00
2023-07-31 13:06:24 +08:00
self . host_set_line = QtWidgets . QLineEdit ( )
2023-07-26 16:01:57 +08:00
sizePolicy = QtWidgets . QSizePolicy ( QtWidgets . QSizePolicy . Policy . Fixed , QtWidgets . QSizePolicy . Policy . Expanding )
2023-07-31 13:06:24 +08:00
sizePolicy . setHeightForWidth ( self . host_set_line . sizePolicy ( ) . hasHeightForWidth ( ) )
self . host_set_line . setSizePolicy ( sizePolicy )
self . host_set_line . setMinimumSize ( QtCore . QSize ( 160 , 0 ) )
self . host_set_line . setMaximumSize ( QtCore . QSize ( 160 , 16777215 ) )
self . host_set_line . setMaxLength ( 15 )
self . host_set_line . setClearButtonEnabled ( True )
2023-07-26 16:01:57 +08:00
2023-07-31 13:10:57 +08:00
self . host_set_line . setText ( " 192.168.1.26 " )
2023-07-31 13:11:36 +08:00
self . host_set_line . setPlaceholderText ( _translate ( " MainWindow " , " IP for the Thermostat " ) )
2023-07-26 16:01:57 +08:00
2023-07-26 16:43:24 +08:00
host = QtWidgets . QWidgetAction ( self . connection_menu )
2023-07-31 13:06:24 +08:00
host . setDefaultWidget ( self . host_set_line )
2023-07-26 16:43:24 +08:00
self . connection_menu . addAction ( host )
self . connection_menu . host = host
2023-07-26 16:01:57 +08:00
2023-07-26 13:22:27 +08:00
self . port_set_spin = QtWidgets . QSpinBox ( )
sizePolicy = QtWidgets . QSizePolicy ( QtWidgets . QSizePolicy . Policy . Fixed , QtWidgets . QSizePolicy . Policy . Fixed )
sizePolicy . setHeightForWidth ( self . port_set_spin . sizePolicy ( ) . hasHeightForWidth ( ) )
self . port_set_spin . setSizePolicy ( sizePolicy )
self . port_set_spin . setMinimumSize ( QtCore . QSize ( 70 , 0 ) )
self . port_set_spin . setMaximumSize ( QtCore . QSize ( 70 , 16777215 ) )
self . port_set_spin . setMaximum ( 65535 )
2023-08-18 10:32:48 +08:00
self . port_set_spin . setValue ( 23 )
2023-07-26 13:22:27 +08:00
2023-07-26 16:43:24 +08:00
port = QtWidgets . QWidgetAction ( self . connection_menu )
2023-07-19 12:49:15 +08:00
port . setDefaultWidget ( self . port_set_spin )
2023-07-26 16:43:24 +08:00
self . connection_menu . addAction ( port )
self . connection_menu . port = port
self . connect_btn . setMenu ( self . connection_menu )
2023-07-31 16:19:07 +08:00
def _set_up_thermostat_menu ( self ) :
_translate = QtCore . QCoreApplication . translate
self . thermostat_menu = QtWidgets . QMenu ( )
self . thermostat_menu . setTitle ( ' Thermostat settings ' )
2023-07-19 12:49:15 +08:00
2023-07-26 13:03:16 +08:00
self . fan_group = QtWidgets . QWidget ( )
self . fan_group . setEnabled ( False )
self . fan_group . setMinimumSize ( QtCore . QSize ( 40 , 0 ) )
2023-08-18 10:55:52 +08:00
self . gan_layout = QtWidgets . QHBoxLayout ( self . fan_group )
2023-07-26 13:03:16 +08:00
self . gan_layout . setSpacing ( 9 )
self . fan_lbl = QtWidgets . QLabel ( parent = self . fan_group )
sizePolicy = QtWidgets . QSizePolicy ( QtWidgets . QSizePolicy . Policy . Fixed , QtWidgets . QSizePolicy . Policy . Expanding )
sizePolicy . setHeightForWidth ( self . fan_lbl . sizePolicy ( ) . hasHeightForWidth ( ) )
self . fan_lbl . setSizePolicy ( sizePolicy )
self . fan_lbl . setMinimumSize ( QtCore . QSize ( 40 , 0 ) )
self . fan_lbl . setMaximumSize ( QtCore . QSize ( 40 , 16777215 ) )
self . fan_lbl . setBaseSize ( QtCore . QSize ( 40 , 0 ) )
self . gan_layout . addWidget ( self . fan_lbl )
self . fan_power_slider = QtWidgets . QSlider ( parent = self . fan_group )
sizePolicy = QtWidgets . QSizePolicy ( QtWidgets . QSizePolicy . Policy . Fixed , QtWidgets . QSizePolicy . Policy . Expanding )
sizePolicy . setHeightForWidth ( self . fan_power_slider . sizePolicy ( ) . hasHeightForWidth ( ) )
self . fan_power_slider . setSizePolicy ( sizePolicy )
self . fan_power_slider . setMinimumSize ( QtCore . QSize ( 200 , 0 ) )
self . fan_power_slider . setMaximumSize ( QtCore . QSize ( 200 , 16777215 ) )
self . fan_power_slider . setBaseSize ( QtCore . QSize ( 200 , 0 ) )
self . fan_power_slider . setMinimum ( 1 )
self . fan_power_slider . setMaximum ( 100 )
self . fan_power_slider . setOrientation ( QtCore . Qt . Orientation . Horizontal )
self . gan_layout . addWidget ( self . fan_power_slider )
self . fan_auto_box = QtWidgets . QCheckBox ( parent = self . fan_group )
sizePolicy = QtWidgets . QSizePolicy ( QtWidgets . QSizePolicy . Policy . Fixed , QtWidgets . QSizePolicy . Policy . Expanding )
sizePolicy . setHeightForWidth ( self . fan_auto_box . sizePolicy ( ) . hasHeightForWidth ( ) )
self . fan_auto_box . setSizePolicy ( sizePolicy )
self . fan_auto_box . setMinimumSize ( QtCore . QSize ( 70 , 0 ) )
self . fan_auto_box . setMaximumSize ( QtCore . QSize ( 70 , 16777215 ) )
self . gan_layout . addWidget ( self . fan_auto_box )
2023-07-26 14:02:55 +08:00
self . fan_pwm_warning = QtWidgets . QLabel ( parent = self . fan_group )
self . fan_pwm_warning . setMinimumSize ( QtCore . QSize ( 16 , 0 ) )
self . gan_layout . addWidget ( self . fan_pwm_warning )
2023-07-26 13:03:16 +08:00
2023-07-31 16:21:15 +08:00
self . fan_power_slider . valueChanged . connect ( self . fan_set )
self . fan_auto_box . stateChanged . connect ( self . fan_auto_set )
2023-07-26 13:03:16 +08:00
self . fan_lbl . setToolTip ( _translate ( " MainWindow " , " Adjust the fan " ) )
self . fan_lbl . setText ( _translate ( " MainWindow " , " Fan: " ) )
self . fan_auto_box . setText ( _translate ( " MainWindow " , " Auto " ) )
2023-07-31 16:19:07 +08:00
fan = QtWidgets . QWidgetAction ( self . thermostat_menu )
2023-07-19 15:04:12 +08:00
fan . setDefaultWidget ( self . fan_group )
2023-07-31 16:19:07 +08:00
self . thermostat_menu . addAction ( fan )
self . thermostat_menu . fan = fan
2023-07-19 15:04:12 +08:00
2023-07-26 17:46:21 +08:00
@asyncSlot ( bool )
async def reset_thermostat ( _ ) :
await self . _on_connection_changed ( False )
2023-07-31 16:36:48 +08:00
await self . client . reset ( )
2023-07-26 17:46:21 +08:00
await asyncio . sleep ( 0.1 ) # Wait for the reset to start
self . connect_btn . click ( ) # Reconnect
self . actionReset . triggered . connect ( reset_thermostat )
2023-07-31 16:19:07 +08:00
self . thermostat_menu . addAction ( self . actionReset )
2023-07-26 17:46:21 +08:00
2023-08-01 10:33:53 +08:00
@asyncSlot ( bool )
async def dfu_mode ( _ ) :
await self . _on_connection_changed ( False )
await self . client . dfu ( )
# TODO: add a firmware flashing GUI?
self . actionEnter_DFU_Mode . triggered . connect ( dfu_mode )
2023-07-31 16:19:07 +08:00
self . thermostat_menu . addAction ( self . actionEnter_DFU_Mode )
2023-08-01 10:33:53 +08:00
2023-08-01 16:48:46 +08:00
@asyncSlot ( bool )
async def network_settings ( _ ) :
ask_network = QtWidgets . QInputDialog ( self )
ask_network . setWindowTitle ( _translate ( " MainWindow " , " Network Settings " ) )
ask_network . setLabelText ( _translate ( " MainWindow " , " Set the Thermostat ' s IPv4 address, netmask and gateway (optional) " ) )
ask_network . setTextValue ( ( await self . client . ipv4 ( ) ) [ ' addr ' ] )
@pyqtSlot ( str )
def set_ipv4 ( ipv4_settings ) :
sure = QtWidgets . QMessageBox ( self )
sure . setWindowTitle ( _translate ( " MainWindow " , " Set network? " ) )
sure . setText ( f " Setting this as network and disconnecting:<br> { ipv4_settings } " )
@asyncSlot ( object )
async def really_set ( button ) :
await self . client . set_param ( " ipv4 " , ipv4_settings )
await self . client . disconnect ( )
await self . _on_connection_changed ( False )
sure . buttonClicked . connect ( really_set )
sure . show ( )
ask_network . textValueSelected . connect ( set_ipv4 )
ask_network . show ( )
self . actionNetwork_Settings . triggered . connect ( network_settings )
2023-07-31 16:19:07 +08:00
self . thermostat_menu . addAction ( self . actionNetwork_Settings )
2023-08-01 10:34:41 +08:00
@asyncSlot ( bool )
async def load ( _ ) :
await self . client . load_config ( )
self . actionLoad_all_configs . triggered . connect ( load )
2023-07-31 16:19:07 +08:00
self . thermostat_menu . addAction ( self . actionLoad_all_configs )
2023-08-01 10:34:41 +08:00
@asyncSlot ( bool )
async def save ( _ ) :
await self . client . save_config ( )
self . actionSave_all_configs . triggered . connect ( save )
2023-07-31 16:19:07 +08:00
self . thermostat_menu . addAction ( self . actionSave_all_configs )
2023-07-28 10:42:13 +08:00
2023-07-31 16:14:14 +08:00
def about_thermostat ( ) :
QtWidgets . QMessageBox . about (
self ,
_translate ( " MainWindow " , " About Thermostat " ) ,
f """
< h1 > Sinara 8451 Thermostat v { self . hw_rev_d [ ' rev ' ] [ ' major ' ] } . { self . hw_rev_d [ ' rev ' ] [ ' minor ' ] } < / h1 >
< br >
< h2 > Settings : < / h2 >
Default fan curve :
a = { self . hw_rev_d [ ' settings ' ] [ ' fan_k_a ' ] } ,
b = { self . hw_rev_d [ ' settings ' ] [ ' fan_k_b ' ] } ,
c = { self . hw_rev_d [ ' settings ' ] [ ' fan_k_c ' ] }
< br >
Fan PWM range :
{ self . hw_rev_d [ ' settings ' ] [ ' min_fan_pwm ' ] } – { self . hw_rev_d [ ' settings ' ] [ ' max_fan_pwm ' ] }
< br >
Fan PWM frequency : { self . hw_rev_d [ ' settings ' ] [ ' fan_pwm_freq_hz ' ] } Hz
< br >
Fan available : { self . hw_rev_d [ ' settings ' ] [ ' fan_available ' ] }
< br >
Fan PWM recommended : { self . hw_rev_d [ ' settings ' ] [ ' fan_pwm_recommended ' ] }
"""
)
self . actionAbout_Thermostat . triggered . connect ( about_thermostat )
2023-07-31 16:19:07 +08:00
self . thermostat_menu . addAction ( self . actionAbout_Thermostat )
2023-07-31 16:14:14 +08:00
2023-07-31 16:19:07 +08:00
self . thermostat_settings . setMenu ( self . thermostat_menu )
def _set_up_plot_menu ( self ) :
_translate = QtCore . QCoreApplication . translate
2023-07-19 12:49:15 +08:00
2023-07-26 13:50:29 +08:00
self . plot_menu = QtWidgets . QMenu ( )
self . plot_menu . setTitle ( " Plot Settings " )
clear = QtGui . QAction ( " Clear graphs " , self . plot_menu )
2023-07-19 13:34:01 +08:00
clear . triggered . connect ( self . clear_graphs )
2023-07-26 13:50:29 +08:00
self . plot_menu . addAction ( clear )
self . plot_menu . clear = clear
2023-07-19 13:34:01 +08:00
2023-07-20 15:54:28 +08:00
self . samples_spinbox = QtWidgets . QSpinBox ( )
self . samples_spinbox . setRange ( 2 , 100000 )
self . samples_spinbox . setSuffix ( ' samples ' )
self . samples_spinbox . setValue ( self . max_samples )
self . samples_spinbox . valueChanged . connect ( self . set_max_samples )
2023-07-26 13:50:29 +08:00
limit_samples = QtWidgets . QWidgetAction ( self . plot_menu )
2023-07-20 15:54:28 +08:00
limit_samples . setDefaultWidget ( self . samples_spinbox )
2023-07-26 13:50:29 +08:00
self . plot_menu . addAction ( limit_samples )
self . plot_menu . limit_samples = limit_samples
2023-07-31 13:22:35 +08:00
self . plot_settings . setMenu ( self . plot_menu )
2023-07-20 15:54:28 +08:00
@pyqtSlot ( int )
def set_max_samples ( self , samples : int ) :
self . ch0_t_connector . max_points = samples
self . ch0_i_connector . max_points = samples
2023-08-10 13:28:26 +08:00
self . ch0_iset_connector . max_points = samples
2023-07-20 15:54:28 +08:00
self . ch1_t_connector . max_points = samples
self . ch1_i_connector . max_points = samples
2023-08-10 13:28:26 +08:00
self . ch1_iset_connector . max_points = samples
2023-07-20 15:54:28 +08:00
2023-07-06 16:06:33 +08:00
def _set_up_graphs ( self ) :
for graph in self . ch0_t_graph , self . ch0_i_graph , self . ch1_t_graph , self . ch1_i_graph :
time_axis = LiveAxis ( ' bottom ' , text = " Time since Thermostat reset " , * * { Axis . TICK_FORMAT : Axis . DURATION } )
time_axis . showLabel ( )
graph . setAxisItems ( { ' bottom ' : time_axis } )
2023-07-28 17:46:26 +08:00
graph . add_crosshair ( pg . mkPen ( color = ' red ' , width = 1 ) , { ' color ' : ' green ' } )
2023-08-02 17:32:29 +08:00
# Enable linking of axes in the graph widget's context menu
graph . register ( graph . getPlotItem ( ) . titleLabel . text ) # Slight hack getting the title
2023-07-06 16:06:33 +08:00
for graph in self . ch0_t_graph , self . ch1_t_graph :
temperature_axis = LiveAxis ( ' left ' , text = " Temperature " , units = " °C " )
temperature_axis . showLabel ( )
graph . setAxisItems ( { ' left ' : temperature_axis } )
for graph in self . ch0_i_graph , self . ch1_i_graph :
current_axis = LiveAxis ( ' left ' , text = " Current " , units = " A " )
current_axis . showLabel ( )
graph . setAxisItems ( { ' left ' : current_axis } )
self . ch0_t_graph . addItem ( self . ch0_t_plot )
self . ch0_i_graph . addItem ( self . ch0_i_plot )
2023-08-10 13:28:26 +08:00
self . ch0_i_graph . addItem ( self . ch0_iset_plot )
2023-07-06 16:06:33 +08:00
self . ch1_t_graph . addItem ( self . ch1_t_plot )
self . ch1_i_graph . addItem ( self . ch1_i_plot )
2023-08-10 13:28:26 +08:00
self . ch1_i_graph . addItem ( self . ch1_iset_plot )
2023-07-06 16:06:33 +08:00
def clear_graphs ( self ) :
2023-08-10 13:28:26 +08:00
for connector in self . ch0_t_connector , self . ch0_i_connector , self . ch0_iset_connector , self . ch1_t_connector , self . ch1_i_connector , self . ch1_iset_connector :
2023-07-06 16:06:33 +08:00
connector . clear ( )
2023-07-18 10:28:56 +08:00
async def _on_connection_changed ( self , result ) :
2023-07-01 23:46:40 +08:00
self . graph_group . setEnabled ( result )
self . report_group . setEnabled ( result )
2023-07-31 13:25:37 +08:00
self . thermostat_settings . setEnabled ( result )
2023-07-01 23:46:40 +08:00
2023-07-31 13:06:24 +08:00
self . host_set_line . setEnabled ( not result )
2023-07-01 23:46:40 +08:00
self . port_set_spin . setEnabled ( not result )
self . connect_btn . setText ( " Disconnect " if result else " Connect " )
2023-07-20 16:16:57 +08:00
if result :
2023-08-04 11:00:33 +08:00
self . hw_rev_data = await self . client . hw_rev ( )
self . _status ( self . hw_rev_data )
2023-07-20 16:16:57 +08:00
self . client_watcher . start_watching ( )
2023-08-04 12:52:15 +08:00
# await self.client.set_param("fan", 1)
2023-07-20 16:16:57 +08:00
else :
2023-07-13 17:03:49 +08:00
self . status_lbl . setText ( " Disconnected " )
2023-07-07 15:36:17 +08:00
self . fan_pwm_warning . setPixmap ( QtGui . QPixmap ( ) )
self . fan_pwm_warning . setToolTip ( " " )
2023-07-06 16:06:33 +08:00
self . clear_graphs ( )
2023-07-26 09:47:24 +08:00
self . report_box . setChecked ( False )
2023-08-16 13:07:26 +08:00
await self . client_watcher . set_report_mode ( False )
2023-07-18 11:01:51 +08:00
self . client_watcher . stop_watching ( )
2023-08-04 11:00:33 +08:00
self . status_lbl . setText ( " Disconnected " )
2023-07-01 23:46:40 +08:00
2023-07-07 17:19:17 +08:00
def _set_fan_pwm_warning ( self ) :
if self . fan_power_slider . value ( ) != 100 :
2023-07-07 15:36:17 +08:00
pixmapi = getattr ( QtWidgets . QStyle . StandardPixmap , " SP_MessageBoxWarning " )
icon = self . style ( ) . standardIcon ( pixmapi )
self . fan_pwm_warning . setPixmap ( icon . pixmap ( 16 , 16 ) )
2023-07-07 17:44:03 +08:00
self . fan_pwm_warning . setToolTip ( " Throttling the fan (not recommended on this hardware rev) " )
2023-07-07 17:19:17 +08:00
else :
self . fan_pwm_warning . setPixmap ( QtGui . QPixmap ( ) )
self . fan_pwm_warning . setToolTip ( " " )
2023-07-13 17:03:49 +08:00
def _status ( self , hw_rev_d : dict ) :
2023-07-07 17:19:17 +08:00
logging . debug ( hw_rev_d )
2023-07-13 17:03:49 +08:00
self . status_lbl . setText ( f " Connected to Thermostat v { hw_rev_d [ ' rev ' ] [ ' major ' ] } . { hw_rev_d [ ' rev ' ] [ ' minor ' ] } " )
2023-07-07 17:19:17 +08:00
self . fan_group . setEnabled ( hw_rev_d [ " settings " ] [ " fan_available " ] )
2023-07-01 23:46:40 +08:00
2023-07-11 12:27:43 +08:00
@pyqtSlot ( dict )
def fan_update ( self , fan_settings : dict ) :
2023-07-01 23:46:40 +08:00
logging . debug ( fan_settings )
if fan_settings is None :
return
2023-07-05 13:00:56 +08:00
with QSignalBlocker ( self . fan_power_slider ) :
2023-07-11 11:48:38 +08:00
self . fan_power_slider . setValue ( fan_settings [ " fan_pwm " ] or 100 ) # 0 = PWM off = full strength
2023-07-05 13:00:56 +08:00
with QSignalBlocker ( self . fan_auto_box ) :
2023-07-01 23:46:40 +08:00
self . fan_auto_box . setChecked ( fan_settings [ " auto_mode " ] )
2023-07-26 17:44:15 +08:00
if not self . hw_rev_data [ " settings " ] [ " fan_pwm_recommended " ] :
2023-07-07 17:19:17 +08:00
self . _set_fan_pwm_warning ( )
2023-07-01 23:46:40 +08:00
2023-07-11 11:55:30 +08:00
@asyncSlot ( int )
async def fan_set ( self , value ) :
2023-08-09 11:09:28 +08:00
if not self . client . connected ( ) :
2023-07-01 23:46:40 +08:00
return
2023-07-19 14:35:51 +08:00
if self . fan_auto_box . isChecked ( ) :
with QSignalBlocker ( self . fan_auto_box ) :
self . fan_auto_box . setChecked ( False )
2023-08-11 16:08:50 +08:00
await self . client . set_fan ( value )
2023-07-26 17:44:15 +08:00
if not self . hw_rev_data [ " settings " ] [ " fan_pwm_recommended " ] :
2023-07-07 17:19:17 +08:00
self . _set_fan_pwm_warning ( )
2023-07-01 23:46:40 +08:00
@asyncSlot ( int )
async def fan_auto_set ( self , enabled ) :
2023-08-09 11:09:28 +08:00
if not self . client . connected ( ) :
2023-07-01 23:46:40 +08:00
return
if enabled :
2023-08-11 16:08:50 +08:00
await self . client . set_fan ( " auto " )
self . fan_update ( await self . client . get_fan ( ) )
2023-06-27 17:34:39 +08:00
else :
2023-08-11 16:08:50 +08:00
await self . client . set_fan ( self . fan_power_slider . value ( ) )
2023-07-01 23:46:40 +08:00
2023-07-26 09:47:24 +08:00
@asyncSlot ( int )
async def on_report_box_stateChanged ( self , enabled ) :
2023-08-16 13:07:26 +08:00
await self . client_watcher . set_report_mode ( enabled )
2023-07-26 09:47:24 +08:00
2023-07-06 12:39:08 +08:00
@asyncClose
async def closeEvent ( self , event ) :
2023-08-08 16:56:36 +08:00
await self . bail ( )
2023-07-06 12:39:08 +08:00
2023-07-01 23:46:40 +08:00
@asyncSlot ( )
2023-07-18 10:36:29 +08:00
async def on_connect_btn_clicked ( self ) :
2023-08-03 14:42:11 +08:00
host , port = self . host_set_line . text ( ) , self . port_set_spin . value ( )
2023-07-01 23:46:40 +08:00
try :
2023-08-09 11:09:28 +08:00
if not ( self . client . connecting ( ) or self . client . connected ( ) ) :
2023-07-01 23:46:40 +08:00
self . status_lbl . setText ( " Connecting... " )
2023-07-14 16:16:52 +08:00
self . connect_btn . setText ( " Stop " )
2023-07-31 13:06:24 +08:00
self . host_set_line . setEnabled ( False )
2023-07-07 16:31:47 +08:00
self . port_set_spin . setEnabled ( False )
2023-07-31 12:33:00 +08:00
try :
2023-08-09 11:13:43 +08:00
await self . client . start_session ( host = host , port = port , timeout = 30 )
2023-07-31 12:33:00 +08:00
except StoppedConnecting :
2023-07-11 13:43:09 +08:00
return
2023-07-18 10:28:56 +08:00
await self . _on_connection_changed ( True )
2023-07-05 10:24:36 +08:00
else :
2023-08-08 16:56:36 +08:00
await self . bail ( )
2023-07-05 13:13:54 +08:00
2023-07-31 12:33:00 +08:00
except ( OSError , TimeoutError , asyncio . TimeoutError ) as e : # TODO: Remove asyncio.TimeoutError in Python 3.11
2023-08-03 14:42:11 +08:00
logging . error ( f " Failed communicating to { host } : { port } : { e } " )
2023-08-08 16:56:36 +08:00
await self . bail ( )
2023-08-09 11:13:43 +08:00
@asyncSlot ( )
2023-08-08 16:56:36 +08:00
async def bail ( self ) :
await self . _on_connection_changed ( False )
2023-08-09 11:13:43 +08:00
await self . client . end_session ( )
2023-06-27 17:34:39 +08:00
2023-07-06 16:06:33 +08:00
@pyqtSlot ( list )
def plot ( self , report ) :
for channel in range ( 2 ) :
temperature = report [ channel ] [ ' temperature ' ]
current = report [ channel ] [ ' tec_i ' ]
2023-08-10 13:28:26 +08:00
iset = report [ channel ] [ ' i_set ' ]
2023-07-06 16:06:33 +08:00
time = report [ channel ] [ ' time ' ]
2023-08-10 13:28:26 +08:00
if temperature is not None and current is not None and iset is not None :
2023-07-06 16:06:33 +08:00
getattr ( self , f ' ch { channel } _t_connector ' ) . cb_append_data_point ( temperature , time )
getattr ( self , f ' ch { channel } _i_connector ' ) . cb_append_data_point ( current , time )
2023-08-10 13:28:26 +08:00
getattr ( self , f ' ch { channel } _iset_connector ' ) . cb_append_data_point ( iset , time )
2023-07-06 16:06:33 +08:00
2023-06-28 15:01:47 +08:00
@asyncSlot ( object , object )
async def send_command ( self , param , changes ) :
2023-08-04 12:32:08 +08:00
for inner_param , change , data in changes :
if inner_param . opts . get ( " commands " , None ) is not None :
2023-08-04 17:46:38 +08:00
ch = param . value ( )
2023-08-04 12:32:08 +08:00
match inner_param . name ( ) :
2023-08-04 11:51:16 +08:00
case ' Temperature PID ' :
2023-08-04 12:32:08 +08:00
pid_enabled = data
getattr ( self , f ' ch { ch } _t_line ' ) . setVisible ( pid_enabled )
if pid_enabled :
getattr ( self , f ' ch { ch } _t_line ' ) . setValue ( inner_param . child ( ' Set Temperature ' ) . value ( ) )
else :
await self . client . set_param ( ' pwm ' , ch , ' i_set ' , param . child ( ' Constant Current ' ) . value ( ) )
return
2023-08-04 11:51:16 +08:00
case ' Set Temperature ' :
2023-08-04 12:32:08 +08:00
getattr ( self , f ' ch { ch } _t_line ' ) . setValue ( data )
await asyncio . gather ( * [ self . client . _command ( x . format ( value = data ) ) for x in inner_param . opts [ " commands " ] ] )
2023-06-28 15:01:47 +08:00
def _set_param_tree ( self ) :
2023-08-16 17:35:13 +08:00
for i , tree in enumerate ( ( self . ch0_tree , self . ch1_tree ) ) :
2023-08-16 14:33:16 +08:00
tree . setHeaderHidden ( True )
2023-08-08 11:39:39 +08:00
tree . setParameters ( self . params [ i ] , showTop = False )
self . params [ i ] . sigTreeStateChanged . connect ( self . send_command )
2023-06-28 15:01:47 +08:00
@pyqtSlot ( list )
def update_pid ( self , pid_settings ) :
for settings in pid_settings :
channel = settings [ " channel " ]
2023-08-08 11:39:39 +08:00
with QSignalBlocker ( self . params [ channel ] ) :
self . params [ channel ] . child ( " PID Config " , " Kp " ) . setValue ( settings [ " parameters " ] [ " kp " ] )
self . params [ channel ] . child ( " PID Config " , " Ki " ) . setValue ( settings [ " parameters " ] [ " ki " ] )
self . params [ channel ] . child ( " PID Config " , " Kd " ) . setValue ( settings [ " parameters " ] [ " kd " ] )
if self . params [ channel ] . child ( " Temperature PID " ) . value ( ) :
self . params [ channel ] . child ( " Temperature PID " , " Set Temperature " ) . setValue ( settings [ " target " ] )
2023-08-02 12:38:45 +08:00
getattr ( self , f ' ch { channel } _t_line ' ) . setValue ( settings [ " target " ] )
2023-06-28 15:01:47 +08:00
@pyqtSlot ( list )
def update_report ( self , report_data ) :
for settings in report_data :
channel = settings [ " channel " ]
2023-08-08 11:39:39 +08:00
with QSignalBlocker ( self . params [ channel ] ) :
self . params [ channel ] . child ( " Temperature PID " ) . setValue ( settings [ " pid_engaged " ] )
2023-08-02 12:38:45 +08:00
getattr ( self , f ' ch { channel } _t_line ' ) . setVisible ( settings [ " pid_engaged " ] )
2023-07-20 13:48:10 +08:00
if not settings [ " pid_engaged " ] :
2023-08-08 11:39:39 +08:00
self . params [ channel ] . child ( " Constant Current " ) . setValue ( settings [ " i_set " ] )
2023-06-28 15:01:47 +08:00
2023-07-20 13:49:11 +08:00
@pyqtSlot ( list )
def update_thermistor ( self , sh_data ) :
for sh_param in sh_data :
channel = sh_param [ " channel " ]
2023-08-08 11:39:39 +08:00
with QSignalBlocker ( self . params [ channel ] ) :
self . params [ channel ] . child ( " Thermistor Config " , " T₀ " ) . setValue ( sh_param [ " params " ] [ " t0 " ] - 273.15 )
self . params [ channel ] . child ( " Thermistor Config " , " R₀ " ) . setValue ( sh_param [ " params " ] [ " r0 " ] )
self . params [ channel ] . child ( " Thermistor Config " , " β " ) . setValue ( sh_param [ " params " ] [ " b " ] )
2023-07-20 13:49:11 +08:00
2023-07-20 13:49:23 +08:00
@pyqtSlot ( list )
def update_pwm ( self , pwm_data ) :
for pwm_params in pwm_data :
channel = pwm_params [ " channel " ]
2023-08-08 11:39:39 +08:00
with QSignalBlocker ( self . params [ channel ] ) :
self . params [ channel ] . child ( " Output Config " , " Max Voltage " ) . setValue ( pwm_params [ " max_v " ] [ " value " ] )
self . params [ channel ] . child ( " Output Config " , " Max Current " ) . setValue ( pwm_params [ " max_i_pos " ] [ " value " ] )
2023-07-20 13:49:23 +08:00
2023-08-01 13:32:06 +08:00
@pyqtSlot ( list )
def update_postfilter ( self , postfilter_data ) :
for postfilter_params in postfilter_data :
channel = postfilter_params [ " channel " ]
2023-08-08 11:39:39 +08:00
with QSignalBlocker ( self . params [ channel ] ) :
self . params [ channel ] . child ( " Postfilter Config " , " Rate " ) . setValue ( postfilter_params [ " rate " ] )
2023-08-01 13:32:06 +08:00
2023-08-16 14:33:16 +08:00
def retranslateUi ( self , MainWindow ) :
super ( ) . retranslateUi ( MainWindow )
_translate = QtCore . QCoreApplication . translate
self . ch0_t_graph . setTitle ( _translate ( " MainWindow " , " Channel 0 Temperature " ) )
self . ch0_i_graph . setTitle ( _translate ( " MainWindow " , " Channel 0 Current " ) )
self . ch1_t_graph . setTitle ( _translate ( " MainWindow " , " Channel 1 Temperature " ) )
self . ch1_i_graph . setTitle ( _translate ( " MainWindow " , " Channel 1 Current " ) )
2023-06-27 17:34:39 +08:00
async def coro_main ( ) :
2023-05-19 11:23:39 +08:00
args = get_argparser ( ) . parse_args ( )
if args . logLevel :
logging . basicConfig ( level = getattr ( logging , args . logLevel ) )
2023-06-27 17:34:39 +08:00
app_quit_event = asyncio . Event ( )
2023-06-26 10:20:48 +08:00
2023-06-27 17:34:39 +08:00
app = QtWidgets . QApplication . instance ( )
app . aboutToQuit . connect ( app_quit_event . set )
2023-06-26 10:20:48 +08:00
2023-07-01 23:46:40 +08:00
main_window = MainWindow ( args )
2023-05-19 11:23:39 +08:00
main_window . show ( )
2023-06-26 10:20:48 +08:00
2023-06-27 17:34:39 +08:00
await app_quit_event . wait ( )
def main ( ) :
qasync . run ( coro_main ( ) )
2023-05-19 11:23:39 +08:00
if __name__ == ' __main__ ' :
main ( )