forked from M-Labs/thermostat
Compare commits
10 Commits
89621dd3a0
...
bbc9204b7f
Author | SHA1 | Date | |
---|---|---|---|
bbc9204b7f | |||
d092c6f9a8 | |||
7f1223b1b9 | |||
b1e5a843eb | |||
2b02ea334a | |||
3b2743c079 | |||
a7ce942aea | |||
ea8469a690 | |||
2467fc2ee2 | |||
a3baadd490 |
@ -44,7 +44,7 @@ class AsyncioClient:
|
||||
pwm_report = await self.get_pwm()
|
||||
for pwm_channel in pwm_report:
|
||||
for limit in ["max_i_neg", "max_i_pos", "max_v"]:
|
||||
if pwm_channel[limit]["value"] == 0.0:
|
||||
if pwm_channel[limit] == 0.0:
|
||||
logging.warning(
|
||||
"`{}` limit is set to zero on channel {}".format(
|
||||
limit, pwm_channel["channel"]
|
||||
|
@ -28,13 +28,13 @@ class Thermostat(QObject, metaclass=PropertyMeta):
|
||||
NUM_CHANNELS = 2
|
||||
|
||||
def __init__(self, parent, update_s, disconnect_cb=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self._update_s = update_s
|
||||
self._client = AsyncioClient()
|
||||
self._watch_task = None
|
||||
self._update_params_task = None
|
||||
self.disconnect_cb = disconnect_cb
|
||||
super().__init__(parent)
|
||||
|
||||
self.connection_state = ThermostatConnectionState.DISCONNECTED
|
||||
|
||||
async def start_session(self, host, port):
|
||||
|
@ -137,7 +137,7 @@ class CtrlPanel(QObject):
|
||||
auto_tuner_param = inner_param.opts["pid_autotune"]
|
||||
self.autotuners.set_params(auto_tuner_param, ch, new_value)
|
||||
|
||||
@pyqtSlot("QVariantList")
|
||||
@pyqtSlot(list)
|
||||
def update_pid(self, pid_settings):
|
||||
for settings in pid_settings:
|
||||
channel = settings["channel"]
|
||||
@ -161,7 +161,7 @@ class CtrlPanel(QObject):
|
||||
"output", "control_method", "target"
|
||||
).set_value_with_lock(settings["target"])
|
||||
|
||||
@pyqtSlot("QVariantList")
|
||||
@pyqtSlot(list)
|
||||
def update_report(self, report_data):
|
||||
for settings in report_data:
|
||||
channel = settings["channel"]
|
||||
@ -183,7 +183,7 @@ class CtrlPanel(QObject):
|
||||
"readings", "tec_i"
|
||||
).set_value_with_lock(settings["tec_i"])
|
||||
|
||||
@pyqtSlot("QVariantList")
|
||||
@pyqtSlot(list)
|
||||
def update_thermistor(self, sh_data):
|
||||
for sh_param in sh_data:
|
||||
channel = sh_param["channel"]
|
||||
@ -198,22 +198,25 @@ class CtrlPanel(QObject):
|
||||
sh_param["params"]["b"]
|
||||
)
|
||||
|
||||
@pyqtSlot("QVariantList")
|
||||
@pyqtSlot(list)
|
||||
def update_pwm(self, pwm_data):
|
||||
for pwm_params in pwm_data:
|
||||
channel = pwm_params["channel"]
|
||||
with QSignalBlocker(self.params[channel]):
|
||||
self.params[channel].child(
|
||||
"output", "polarity"
|
||||
).set_value_with_lock(pwm_params["polarity"])
|
||||
self.params[channel].child(
|
||||
"output", "limits", "max_v"
|
||||
).set_value_with_lock(pwm_params["max_v"]["value"])
|
||||
).set_value_with_lock(pwm_params["max_v"])
|
||||
self.params[channel].child(
|
||||
"output", "limits", "max_i_pos"
|
||||
).set_value_with_lock(pwm_params["max_i_pos"]["value"])
|
||||
).set_value_with_lock(pwm_params["max_i_pos"])
|
||||
self.params[channel].child(
|
||||
"output", "limits", "max_i_neg"
|
||||
).set_value_with_lock(pwm_params["max_i_neg"]["value"])
|
||||
).set_value_with_lock(pwm_params["max_i_neg"])
|
||||
|
||||
@pyqtSlot("QVariantList")
|
||||
@pyqtSlot(list)
|
||||
def update_postfilter(self, postfilter_data):
|
||||
for postfilter_params in postfilter_data:
|
||||
channel = postfilter_params["channel"]
|
||||
|
@ -34,6 +34,19 @@
|
||||
"type": "group",
|
||||
"tip": "Settings of the output to the TEC",
|
||||
"children": [
|
||||
{
|
||||
"name": "polarity",
|
||||
"title": "Polarity",
|
||||
"type": "list",
|
||||
"limits": {
|
||||
"Normal": "normal",
|
||||
"Reversed": "reversed"
|
||||
},
|
||||
"thermostat:set_param": {
|
||||
"topic": "pwm",
|
||||
"field": "polarity"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "control_method",
|
||||
"title": "Control Method",
|
||||
@ -290,7 +303,7 @@
|
||||
"title": "Ki",
|
||||
"type": "float",
|
||||
"step": 0.1,
|
||||
"suffix": "Hz",
|
||||
"suffix": "τ⁻¹",
|
||||
"noUnitEditing": true,
|
||||
"compactHeight": false,
|
||||
"thermostat:set_param": {
|
||||
@ -305,7 +318,7 @@
|
||||
"title": "Kd",
|
||||
"type": "float",
|
||||
"step": 0.1,
|
||||
"suffix": "s",
|
||||
"suffix": "τ",
|
||||
"noUnitEditing": true,
|
||||
"compactHeight": false,
|
||||
"thermostat:set_param": {
|
||||
@ -456,4 +469,4 @@
|
||||
"tip": "Load settings from thermostat"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -10,14 +10,14 @@ class ZeroLimitsWarningView(QObject):
|
||||
self._lbl = limit_warning
|
||||
self._style = style
|
||||
|
||||
@pyqtSlot("QVariantList")
|
||||
@pyqtSlot(list)
|
||||
def set_limits_warning(self, pwm_data: list):
|
||||
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:
|
||||
if pwm_params[limit] == 0.0:
|
||||
channels_zeroed_limits[channel].add(limit)
|
||||
|
||||
channel_disabled = [False, False]
|
||||
|
@ -1,3 +1,17 @@
|
||||
"""GUI for the Sinara 8451 Thermostat"""
|
||||
|
||||
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
|
||||
@ -5,18 +19,6 @@ from pytec.gui.view.plot_options_menu import PlotOptionsMenu
|
||||
from pytec.gui.view.live_plot_view import LiveDataPlotter
|
||||
from pytec.gui.view.ctrl_panel import CtrlPanel
|
||||
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():
|
||||
@ -75,6 +77,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
for ch in range(self.NUM_CHANNELS):
|
||||
if self._autotuners.get_state(ch) != PIDAutotuneState.STATE_OFF:
|
||||
await self._autotuners.stop_pid_from_running(ch)
|
||||
|
||||
self._thermostat.disconnect_cb = autotune_disconnect
|
||||
|
||||
@pyqtSlot()
|
||||
@ -82,6 +85,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
self._info_box.display_info_box(
|
||||
"Connection Error", "Thermostat connection lost. Is it unplugged?"
|
||||
)
|
||||
|
||||
self._thermostat.connection_error.connect(handle_connection_error)
|
||||
|
||||
# Control Panel
|
||||
@ -103,7 +107,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
[
|
||||
[getattr(self, f"ch{ch}_t_graph"), getattr(self, f"ch{ch}_i_graph")]
|
||||
for ch in range(self.NUM_CHANNELS)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
# Bottom bar menus
|
||||
@ -165,22 +169,22 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
|
||||
@pyqtSlot(int, PIDAutotuneState)
|
||||
def _on_pid_autotune_state_changed(self, _ch, _state):
|
||||
ch_tuning = []
|
||||
autotuning_channels = []
|
||||
for ch in range(self.NUM_CHANNELS):
|
||||
if self._autotuners.get_state(ch) in {
|
||||
PIDAutotuneState.STATE_READY,
|
||||
PIDAutotuneState.STATE_RELAY_STEP_UP,
|
||||
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.loading_spinner.hide()
|
||||
self.loading_spinner.stop()
|
||||
else:
|
||||
self.background_task_lbl.setText(
|
||||
"Autotuning channel {ch}...".format(ch=ch_tuning)
|
||||
f"Autotuning channel {autotuning_channels}..."
|
||||
)
|
||||
self.loading_spinner.start()
|
||||
self.loading_spinner.show()
|
||||
@ -189,14 +193,12 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
async def on_connect_btn_clicked(self):
|
||||
match self._thermostat.connection_state:
|
||||
case ThermostatConnectionState.DISCONNECTED:
|
||||
self._connecting_task = asyncio.create_task(
|
||||
self._thermostat.start_session(
|
||||
host=self.connection_details_menu.host_set_line.text(),
|
||||
port=self.connection_details_menu.port_set_spin.value(),
|
||||
)
|
||||
)
|
||||
self._connecting_task = asyncio.current_task()
|
||||
self._thermostat.connection_state = ThermostatConnectionState.CONNECTING
|
||||
await self._connecting_task
|
||||
await self._thermostat.start_session(
|
||||
host=self.connection_details_menu.host_set_line.text(),
|
||||
port=self.connection_details_menu.port_set_spin.value(),
|
||||
)
|
||||
self._connecting_task = None
|
||||
self._thermostat.connection_state = ThermostatConnectionState.CONNECTED
|
||||
self._thermostat.start_watching()
|
||||
|
Loading…
Reference in New Issue
Block a user