Compare commits

..

24 Commits

Author SHA1 Message Date
b7cc9db03c No need to create a new task for waiting 2024-09-09 18:29:24 +08:00
92d574a0e3 fixup! Zero limits warning cleanup 2024-09-09 16:29:32 +08:00
2d3bc96da9 super init's first 2024-09-09 15:44:07 +08:00
7efd184496 Format 2024-09-09 15:10:30 +08:00
14621e11a6 ch_tuning -> autotuning_channels 2024-09-09 15:10:16 +08:00
cfe9ee3985 Module docstring?? 2024-09-09 15:09:04 +08:00
a60f55d1c8 Reorder imports 2024-09-09 15:08:17 +08:00
a466e3e09d Sensible names for views 2024-09-09 15:06:22 +08:00
b0a4e1218a fixup! tec_qt: Private everything possible 2024-09-09 15:00:44 +08:00
d199770de1 Unprivate conn_menu
Used for autoconnect
2024-09-09 15:00:14 +08:00
9911f72059 Order? 2024-09-09 14:54:37 +08:00
f62adbbc1a Reorder 2024-09-09 14:54:37 +08:00
c416fd8b2b Not async 2024-09-09 14:54:37 +08:00
b3ba577268 Remove report mode from thermostat data model 2024-09-09 14:54:37 +08:00
3c1228e8a8 Remove report mode box 2024-09-09 14:54:37 +08:00
23653a1ecd More sensible names 2024-09-09 14:54:37 +08:00
29221ce570 tec_qt: Private everything possible 2024-09-09 14:54:35 +08:00
2334a922f7 Remove error handling for connecting task
Just let the exception propagate, even when stopping the connection
2024-09-09 14:54:24 +08:00
1aab3ca1d6 Update thermostat state from controller code 2024-09-09 14:54:24 +08:00
41d4154a28 extra func out 2024-09-09 14:54:24 +08:00
6473905488 No need extra function 2024-09-09 14:54:24 +08:00
b13f481381 State update explicitly 2024-09-09 14:54:24 +08:00
66303efd11 Zero limits warning cleanup 2024-09-02 16:12:55 +08:00
f0e7488682 Add NUM_CHANNELS to Thermostat! 2024-09-02 16:06:21 +08:00
8 changed files with 147 additions and 199 deletions

View File

@ -14,6 +14,7 @@ class ThermostatConnectionState(Enum):
class Thermostat(QObject, metaclass=PropertyMeta): class Thermostat(QObject, metaclass=PropertyMeta):
connection_state = Property(ThermostatConnectionState)
hw_rev = Property(dict) hw_rev = Property(dict)
fan = Property(dict) fan = Property(dict)
thermistor = Property(list) thermistor = Property(list)
@ -23,24 +24,44 @@ class Thermostat(QObject, metaclass=PropertyMeta):
report = Property(list) report = Property(list)
connection_error = pyqtSignal() connection_error = pyqtSignal()
connection_state_changed = pyqtSignal(ThermostatConnectionState)
NUM_CHANNELS = 2
def __init__(self, parent, update_s, disconnect_cb=None): def __init__(self, parent, update_s, disconnect_cb=None):
super().__init__(parent)
self._update_s = update_s self._update_s = update_s
self._client = AsyncioClient() self._client = AsyncioClient()
self._watch_task = None self._watch_task = None
self._report_mode_task = None
self._poll_for_report = True
self._update_params_task = None self._update_params_task = None
self.disconnect_cb = disconnect_cb self.disconnect_cb = disconnect_cb
super().__init__(parent) self.connection_state = ThermostatConnectionState.DISCONNECTED
async def start_session(self, host, port): async def start_session(self, host, port):
self.connection_state_changed.emit(ThermostatConnectionState.CONNECTING)
await self._client.connect(host, port) await self._client.connect(host, port)
self.hw_rev = await self.get_hw_rev() self.hw_rev = await self._client.hw_rev()
self.connection_state_changed.emit(ThermostatConnectionState.CONNECTED)
self.start_watching() @asyncSlot()
async def end_session(self):
self.stop_watching()
if self.disconnect_cb is not None:
if asyncio.iscoroutinefunction(self.disconnect_cb):
await self.disconnect_cb()
else:
self.disconnect_cb()
await self._client.disconnect()
def start_watching(self):
self._watch_task = asyncio.create_task(self.run())
def stop_watching(self):
if self._watch_task is not None:
self._watch_task.cancel()
self._watch_task = None
self._update_params_task.cancel()
self._update_params_task = None
async def run(self): async def run(self):
self._update_params_task = asyncio.create_task(self.update_params()) self._update_params_task = asyncio.create_task(self.update_params())
@ -53,28 +74,16 @@ class Thermostat(QObject, metaclass=PropertyMeta):
"Encountered an error while polling for information from Thermostat.", "Encountered an error while polling for information from Thermostat.",
exc_info=True, exc_info=True,
) )
await self.handle_connection_error() await self.end_session()
self.connection_state = ThermostatConnectionState.DISCONNECTED
self.connection_error.emit()
return return
self._update_params_task = asyncio.create_task(self.update_params()) self._update_params_task = asyncio.create_task(self.update_params())
await asyncio.sleep(self._update_s) await asyncio.sleep(self._update_s)
async def handle_connection_error(self):
await self.end_session()
self.connection_error.emit()
async def get_hw_rev(self):
return await self._client.hw_rev()
async def update_params(self): async def update_params(self):
if self._poll_for_report: self.fan, self.pwm, self.report, self.pid, self.thermistor, self.postfilter = (
( await asyncio.gather(
self.fan,
self.pwm,
self.report,
self.pid,
self.thermistor,
self.postfilter,
) = await asyncio.gather(
self._client.get_fan(), self._client.get_fan(),
self._client.get_pwm(), self._client.get_pwm(),
self._client.report(), self._client.report(),
@ -82,56 +91,14 @@ class Thermostat(QObject, metaclass=PropertyMeta):
self._client.get_steinhart_hart(), self._client.get_steinhart_hart(),
self._client.get_postfilter(), self._client.get_postfilter(),
) )
else: )
self.fan, self.pwm, self.pid, self.thermistor, self.postfilter = (
await asyncio.gather(
self._client.get_fan(),
self._client.get_pwm(),
self._client.get_pid(),
self._client.get_steinhart_hart(),
self._client.get_postfilter(),
)
)
def connected(self): def connected(self):
return self._client.connected() return self._client.connected()
def start_watching(self): @pyqtSlot(float)
self._watch_task = asyncio.create_task(self.run()) def set_update_s(self, update_s):
self._update_s = update_s
@asyncSlot()
async def stop_watching(self):
if self._watch_task is not None:
await self.set_report_mode(False)
self._watch_task.cancel()
self._watch_task = None
self._update_params_task.cancel()
self._update_params_task = None
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()
async def report_mode(self):
async for report in self._client.report_mode():
self.report_update.emit(report)
@asyncSlot()
async def end_session(self):
await self.set_report_mode(False)
self.stop_watching()
if self.disconnect_cb is not None:
if asyncio.iscoroutinefunction(self.disconnect_cb):
await self.disconnect_cb()
else:
self.disconnect_cb()
await self._client.disconnect()
self.connection_state_changed.emit(ThermostatConnectionState.DISCONNECTED)
async def set_ipv4(self, ipv4): async def set_ipv4(self, ipv4):
await self._client.set_param("ipv4", ipv4) await self._client.set_param("ipv4", ipv4)
@ -153,10 +120,6 @@ class Thermostat(QObject, metaclass=PropertyMeta):
async def reset(self): async def reset(self):
await self._client.reset() await self._client.reset()
@pyqtSlot(float)
def set_update_s(self, update_s):
self._update_s = update_s
async def set_fan(self, power="auto"): async def set_fan(self, power="auto"):
await self._client.set_fan(power) await self._client.set_fan(power)

View File

@ -3,12 +3,12 @@ from PyQt6.QtCore import pyqtSlot
from pytec.gui.model.thermostat import ThermostatConnectionState from pytec.gui.model.thermostat import ThermostatConnectionState
class ConnMenu(QtWidgets.QMenu): class ConnectionDetailsMenu(QtWidgets.QMenu):
def __init__(self, thermostat, connect_btn): def __init__(self, thermostat, connect_btn):
super().__init__() super().__init__()
self._thermostat = thermostat self._thermostat = thermostat
self._connect_btn = connect_btn self._connect_btn = connect_btn
self._thermostat.connection_state_changed.connect( self._thermostat.connection_state_update.connect(
self.thermostat_state_change_handler self.thermostat_state_change_handler
) )

View File

@ -46,8 +46,6 @@ registerParameterType("mutex", MutexParameter)
class CtrlPanel(QObject): class CtrlPanel(QObject):
set_zero_limits_warning_sig = pyqtSignal(list)
def __init__( def __init__(
self, self,
thermostat, thermostat,
@ -231,8 +229,6 @@ class CtrlPanel(QObject):
@pyqtSlot("QVariantList") @pyqtSlot("QVariantList")
def update_pwm(self, pwm_data): def update_pwm(self, pwm_data):
channels_zeroed_limits = [set() for i in range(self.NUM_CHANNELS)]
for pwm_params in pwm_data: for pwm_params in pwm_data:
channel = pwm_params["channel"] channel = pwm_params["channel"]
with QSignalBlocker(self.params[channel]): with QSignalBlocker(self.params[channel]):
@ -246,11 +242,6 @@ class CtrlPanel(QObject):
"Output Config", "Limits", "Max Heating Current" "Output Config", "Limits", "Max Heating Current"
).setValue(pwm_params["max_i_neg"]["value"] * 1000) ).setValue(pwm_params["max_i_neg"]["value"] * 1000)
for limit in "max_i_pos", "max_i_neg", "max_v":
if pwm_params[limit]["value"] == 0.0:
channels_zeroed_limits[channel].add(limit)
self.set_zero_limits_warning_sig.emit(channels_zeroed_limits)
@pyqtSlot("QVariantList") @pyqtSlot("QVariantList")
def update_postfilter(self, postfilter_data): def update_postfilter(self, postfilter_data):
for postfilter_params in postfilter_data: for postfilter_params in postfilter_data:

View File

@ -17,7 +17,7 @@ class LiveDataPlotter(QObject):
self._thermostat.report_update.connect(self.update_report) self._thermostat.report_update.connect(self.update_report)
self._thermostat.pid_update.connect(self.update_pid) self._thermostat.pid_update.connect(self.update_pid)
self._thermostat.connection_state_changed.connect( self._thermostat.connection_state_update.connect(
self.thermostat_state_change_handler self.thermostat_state_change_handler
) )

View File

@ -369,7 +369,7 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<layout class="QHBoxLayout" name="report_layout" stretch="0,1,1,1"> <layout class="QHBoxLayout" name="report_layout" stretch="0,1,1">
<property name="spacing"> <property name="spacing">
<number>6</number> <number>6</number>
</property> </property>
@ -435,31 +435,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="report_box">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
<property name="baseSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Report</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QPushButton" name="report_apply_btn"> <widget class="QPushButton" name="report_apply_btn">
<property name="sizePolicy"> <property name="sizePolicy">

View File

@ -6,7 +6,7 @@ from pytec.gui.view.net_settings_input_diag import NetSettingsInputDiag
from pytec.gui.model.thermostat import ThermostatConnectionState from pytec.gui.model.thermostat import ThermostatConnectionState
class ThermostatCtrlMenu(QtWidgets.QMenu): class ThermostatSettingsMenu(QtWidgets.QMenu):
def __init__(self, thermostat, info_box, style): def __init__(self, thermostat, info_box, style):
super().__init__() super().__init__()
self._thermostat = thermostat self._thermostat = thermostat
@ -16,7 +16,7 @@ class ThermostatCtrlMenu(QtWidgets.QMenu):
self.hw_rev_data = dict() self.hw_rev_data = dict()
self._thermostat.hw_rev_update.connect(self.hw_rev) self._thermostat.hw_rev_update.connect(self.hw_rev)
self._thermostat.connection_state_changed.connect( self._thermostat.connection_state_update.connect(
self.thermostat_state_change_handler self.thermostat_state_change_handler
) )
@ -188,6 +188,7 @@ class ThermostatCtrlMenu(QtWidgets.QMenu):
await self._thermostat.reset() await self._thermostat.reset()
await self._thermostat.end_session() await self._thermostat.end_session()
self._thermostat.connection_state = ThermostatConnectionState.DISCONNECTED
@asyncSlot(bool) @asyncSlot(bool)
async def dfu_request(self, _): async def dfu_request(self, _):
@ -195,6 +196,7 @@ class ThermostatCtrlMenu(QtWidgets.QMenu):
await self._thermostat.dfu() await self._thermostat.dfu()
await self._thermostat.end_session() await self._thermostat.end_session()
self._thermostat.connection_state = ThermostatConnectionState.DISCONNECTED
@asyncSlot(bool) @asyncSlot(bool)
async def net_settings_request(self, _): async def net_settings_request(self, _):
@ -209,4 +211,5 @@ class ThermostatCtrlMenu(QtWidgets.QMenu):
assert self._thermostat.connected() assert self._thermostat.connected()
await self._thermostat.set_ipv4(ipv4_settings) await self._thermostat.set_ipv4(ipv4_settings)
await self._thermostat.end_session() await self._thermostat.end_session()
self._thermostat.connection_state = ThermostatConnectionState.DISCONNECTED

View File

@ -3,15 +3,24 @@ from PyQt6 import QtWidgets, QtGui
class ZeroLimitsWarningView(QObject): class ZeroLimitsWarningView(QObject):
def __init__(self, style, limit_warning): def __init__(self, thermostat, style, limit_warning):
super().__init__() super().__init__()
self._thermostat = thermostat
self._thermostat.pwm_update.connect(self.set_limits_warning)
self._lbl = limit_warning self._lbl = limit_warning
self._style = style self._style = style
@pyqtSlot("QVariantList") @pyqtSlot("QVariantList")
def set_limits_warning(self, channels_zeroed_limits: list): def set_limits_warning(self, pwm_data: list):
channel_disabled = [False, False] channels_zeroed_limits = [set() for i in range(self._thermostat.NUM_CHANNELS)]
for pwm_params in pwm_data:
channel = pwm_params["channel"]
for limit in "max_i_pos", "max_i_neg", "max_v":
if pwm_params[limit]["value"] == 0.0:
channels_zeroed_limits[channel].add(limit)
channel_disabled = [False, False]
report_str = "The following output limit(s) are set to zero:\n" report_str = "The following output limit(s) are set to zero:\n"
for ch, zeroed_limits in enumerate(channels_zeroed_limits): for ch, zeroed_limits in enumerate(channels_zeroed_limits):
if {"max_i_pos", "max_i_neg"}.issubset(zeroed_limits): if {"max_i_pos", "max_i_neg"}.issubset(zeroed_limits):

View File

@ -1,22 +1,24 @@
from pytec.gui.view.zero_limits_warning import ZeroLimitsWarningView """GUI for the Sinara 8451 Thermostat"""
from pytec.gui.view.thermostat_ctrl_menu import ThermostatCtrlMenu
from pytec.gui.view.conn_menu import ConnMenu import json
import asyncio
import logging
import argparse
import importlib.resources
import qasync
from qasync import asyncSlot, asyncClose
from autotune import PIDAutotuneState
from PyQt6 import QtWidgets, QtGui, uic
from PyQt6.QtCore import pyqtSlot
from pytec.gui.model.thermostat import Thermostat, ThermostatConnectionState
from pytec.gui.model.pid_autotuner import PIDAutoTuner
from pytec.gui.view.zero_limits_warning_view import ZeroLimitsWarningView
from pytec.gui.view.thermostat_settings_menu import ThermostatSettingsMenu
from pytec.gui.view.connection_details_menu import ConnectionDetailsMenu
from pytec.gui.view.plot_options_menu import PlotOptionsMenu from pytec.gui.view.plot_options_menu import PlotOptionsMenu
from pytec.gui.view.live_plot_view import LiveDataPlotter from pytec.gui.view.live_plot_view import LiveDataPlotter
from pytec.gui.view.ctrl_panel import CtrlPanel from pytec.gui.view.ctrl_panel import CtrlPanel
from pytec.gui.view.info_box import InfoBox from pytec.gui.view.info_box import InfoBox
from pytec.gui.model.pid_autotuner import PIDAutoTuner
from pytec.gui.model.thermostat import Thermostat, ThermostatConnectionState
import json
from autotune import PIDAutotuneState
from qasync import asyncSlot, asyncClose
import qasync
import asyncio
import logging
import argparse
from PyQt6 import QtWidgets, QtGui, uic
from PyQt6.QtCore import pyqtSlot
import importlib.resources
def get_argparser(): def get_argparser():
@ -56,86 +58,92 @@ class MainWindow(QtWidgets.QMainWindow):
ui_file_path = importlib.resources.files("pytec.gui.view").joinpath("tec_qt.ui") ui_file_path = importlib.resources.files("pytec.gui.view").joinpath("tec_qt.ui")
uic.loadUi(ui_file_path, self) uic.loadUi(ui_file_path, self)
self.info_box = InfoBox() self._info_box = InfoBox()
# Models # Models
self.thermostat = Thermostat(self, self.report_refresh_spin.value()) self._thermostat = Thermostat(self, self.report_refresh_spin.value())
self._connecting_task = None self._connecting_task = None
self.thermostat.connection_state_changed.connect(self._on_connection_changed) self._thermostat.connection_state_update.connect(
self._on_connection_state_changed
)
self.autotuners = PIDAutoTuner(self, self.thermostat, 2) self._autotuners = PIDAutoTuner(self, self._thermostat, 2)
self.autotuners.autotune_state_changed.connect(self.pid_autotune_handler) self._autotuners.autotune_state_changed.connect(
self._on_pid_autotune_state_changed
)
# Handlers for disconnections # Handlers for disconnections
async def autotune_disconnect(): async def autotune_disconnect():
for ch in range(self.NUM_CHANNELS): for ch in range(self.NUM_CHANNELS):
if self.autotuners.get_state(ch) != PIDAutotuneState.STATE_OFF: if self._autotuners.get_state(ch) != PIDAutotuneState.STATE_OFF:
await self.autotuners.stop_pid_from_running(ch) await self._autotuners.stop_pid_from_running(ch)
self.thermostat.disconnect_cb = autotune_disconnect
self._thermostat.disconnect_cb = autotune_disconnect
@pyqtSlot() @pyqtSlot()
def handle_connection_error(): def handle_connection_error():
self.info_box.display_info_box( self._info_box.display_info_box(
"Connection Error", "Thermostat connection lost. Is it unplugged?" "Connection Error", "Thermostat connection lost. Is it unplugged?"
) )
self.thermostat.connection_error.connect(handle_connection_error)
self._thermostat.connection_error.connect(handle_connection_error)
# Control Panel # Control Panel
def get_ctrl_panel_config(args): def get_ctrl_panel_config(args):
with open(args.param_tree, "r", encoding="utf-8") as f: with open(args.param_tree, "r", encoding="utf-8") as f:
return json.load(f)["ctrl_panel"] return json.load(f)["ctrl_panel"]
self.ctrl_panel_view = CtrlPanel( self._ctrl_panel_view = CtrlPanel(
self.thermostat, self._thermostat,
self.autotuners, self._autotuners,
self.info_box, self._info_box,
[self.ch0_tree, self.ch1_tree], [self.ch0_tree, self.ch1_tree],
get_ctrl_panel_config(args), get_ctrl_panel_config(args),
) )
# Graphs # Graphs
self.channel_graphs = LiveDataPlotter( self._channel_graphs = LiveDataPlotter(
self.thermostat, self._thermostat,
[ [
[getattr(self, f"ch{ch}_t_graph"), getattr(self, f"ch{ch}_i_graph")] [getattr(self, f"ch{ch}_t_graph"), getattr(self, f"ch{ch}_i_graph")]
for ch in range(self.NUM_CHANNELS) for ch in range(self.NUM_CHANNELS)
] ],
) )
# Bottom bar menus # Bottom bar menus
self.conn_menu = ConnMenu(self.thermostat, self.connect_btn) self.connection_details_menu = ConnectionDetailsMenu(
self.connect_btn.setMenu(self.conn_menu) self._thermostat, self.connect_btn
self.thermostat_ctrl_menu = ThermostatCtrlMenu(
self.thermostat, self.info_box, self.style()
) )
self.thermostat_settings.setMenu(self.thermostat_ctrl_menu) self.connect_btn.setMenu(self.connection_details_menu)
self.plot_options_menu = PlotOptionsMenu(self.channel_graphs) self._thermostat_settings_menu = ThermostatSettingsMenu(
self.plot_settings.setMenu(self.plot_options_menu) self._thermostat, self._info_box, self.style()
)
self.thermostat_settings.setMenu(self._thermostat_settings_menu)
self._plot_options_menu = PlotOptionsMenu(self._channel_graphs)
self.plot_settings.setMenu(self._plot_options_menu)
# Status line # Status line
self.zero_limits_warning = ZeroLimitsWarningView( self._zero_limits_warning_view = ZeroLimitsWarningView(
self.style(), self.limits_warning self._thermostat, self.style(), self.limits_warning
)
self.ctrl_panel_view.set_zero_limits_warning_sig.connect(
self.zero_limits_warning.set_limits_warning
) )
self.loading_spinner.hide() self.loading_spinner.hide()
self.report_apply_btn.clicked.connect( self.report_apply_btn.clicked.connect(
lambda: self.thermostat.set_update_s(self.report_refresh_spin.value()) lambda: self._thermostat.set_update_s(self.report_refresh_spin.value())
) )
@asyncClose @asyncClose
async def closeEvent(self, _event): async def closeEvent(self, _event):
try: try:
await self.thermostat.end_session() await self._thermostat.end_session()
self._thermostat.connection_state = ThermostatConnectionState.DISCONNECTED
except: except:
pass pass
@pyqtSlot(ThermostatConnectionState) @pyqtSlot(ThermostatConnectionState)
def _on_connection_changed(self, state): def _on_connection_state_changed(self, state):
self.graph_group.setEnabled(state == ThermostatConnectionState.CONNECTED) self.graph_group.setEnabled(state == ThermostatConnectionState.CONNECTED)
self.thermostat_settings.setEnabled( self.thermostat_settings.setEnabled(
state == ThermostatConnectionState.CONNECTED state == ThermostatConnectionState.CONNECTED
@ -147,8 +155,8 @@ class MainWindow(QtWidgets.QMainWindow):
self.connect_btn.setText("Disconnect") self.connect_btn.setText("Disconnect")
self.status_lbl.setText( self.status_lbl.setText(
"Connected to Thermostat v" "Connected to Thermostat v"
f"{self.thermostat.hw_rev['rev']['major']}." f"{self._thermostat.hw_rev['rev']['major']}."
f"{self.thermostat.hw_rev['rev']['minor']}" f"{self._thermostat.hw_rev['rev']['minor']}"
) )
case ThermostatConnectionState.CONNECTING: case ThermostatConnectionState.CONNECTING:
@ -158,57 +166,56 @@ class MainWindow(QtWidgets.QMainWindow):
case ThermostatConnectionState.DISCONNECTED: case ThermostatConnectionState.DISCONNECTED:
self.connect_btn.setText("Connect") self.connect_btn.setText("Connect")
self.status_lbl.setText("Disconnected") self.status_lbl.setText("Disconnected")
self.report_box.setChecked(False)
@pyqtSlot(int, PIDAutotuneState) @pyqtSlot(int, PIDAutotuneState)
def pid_autotune_handler(self, _ch, _state): def _on_pid_autotune_state_changed(self, _ch, _state):
ch_tuning = [] autotuning_channels = []
for ch in range(self.NUM_CHANNELS): for ch in range(self.NUM_CHANNELS):
if self.autotuners.get_state(ch) in { if self._autotuners.get_state(ch) in {
PIDAutotuneState.STATE_READY, PIDAutotuneState.STATE_READY,
PIDAutotuneState.STATE_RELAY_STEP_UP, PIDAutotuneState.STATE_RELAY_STEP_UP,
PIDAutotuneState.STATE_RELAY_STEP_DOWN, PIDAutotuneState.STATE_RELAY_STEP_DOWN,
}: }:
ch_tuning.append(ch) autotuning_channels.append(ch)
if len(ch_tuning) == 0: if len(autotuning_channels) == 0:
self.background_task_lbl.setText("Ready.") self.background_task_lbl.setText("Ready.")
self.loading_spinner.hide() self.loading_spinner.hide()
self.loading_spinner.stop() self.loading_spinner.stop()
else: else:
self.background_task_lbl.setText( self.background_task_lbl.setText(
"Autotuning channel {ch}...".format(ch=ch_tuning) f"Autotuning channel {autotuning_channels}..."
) )
self.loading_spinner.start() self.loading_spinner.start()
self.loading_spinner.show() self.loading_spinner.show()
@asyncSlot() @asyncSlot()
async def on_connect_btn_clicked(self): async def on_connect_btn_clicked(self):
if (self._connecting_task is None) and (not self.thermostat.connected()): match self._thermostat.connection_state:
self._connecting_task = asyncio.create_task( case ThermostatConnectionState.DISCONNECTED:
self.thermostat.start_session( self._connecting_task = asyncio.current_task()
host=self.conn_menu.host_set_line.text(), self._thermostat.connection_state = ThermostatConnectionState.CONNECTING
port=self.conn_menu.port_set_spin.value(), await self._thermostat.start_session(
host=self.connection_details_menu.host_set_line.text(),
port=self.connection_details_menu.port_set_spin.value(),
) )
)
try:
await self._connecting_task
except (OSError, asyncio.CancelledError) as exc:
await self.thermostat.end_session()
if isinstance(exc, asyncio.CancelledError):
return
raise
finally:
self._connecting_task = None self._connecting_task = None
self._thermostat.connection_state = ThermostatConnectionState.CONNECTED
self._thermostat.start_watching()
elif self._connecting_task is not None: case ThermostatConnectionState.CONNECTING:
self._connecting_task.cancel() self._connecting_task.cancel()
else: self._connecting_task = None
await self.thermostat.end_session() await self._thermostat.end_session()
self._thermostat.connection_state = (
ThermostatConnectionState.DISCONNECTED
)
@asyncSlot(int) case ThermostatConnectionState.CONNECTED:
async def on_report_box_stateChanged(self, enabled): await self._thermostat.end_session()
await self.thermostat.set_report_mode(enabled) self._thermostat.connection_state = (
ThermostatConnectionState.DISCONNECTED
)
async def coro_main(): async def coro_main():
@ -231,9 +238,9 @@ async def coro_main():
if args.connect: if args.connect:
if args.HOST: if args.HOST:
main_window.conn_menu.host_set_line.setText(args.HOST) main_window.connection_details_menu.host_set_line.setText(args.HOST)
if args.PORT: if args.PORT:
main_window.conn_menu.port_set_spin.setValue(int(args.PORT)) main_window.connection_details_menu.port_set_spin.setValue(int(args.PORT))
main_window.connect_btn.click() main_window.connect_btn.click()
await app_quit_event.wait() await app_quit_event.wait()