forked from M-Labs/thermostat
Compare commits
No commits in common. "bbc9204b7f594ed6bc2596edd48f99951da3fd6b" and "89621dd3a05580ec4af1aab1f2e84bb5b23314b8" have entirely different histories.
bbc9204b7f
...
89621dd3a0
@ -44,7 +44,7 @@ class AsyncioClient:
|
|||||||
pwm_report = await self.get_pwm()
|
pwm_report = await self.get_pwm()
|
||||||
for pwm_channel in pwm_report:
|
for pwm_channel in pwm_report:
|
||||||
for limit in ["max_i_neg", "max_i_pos", "max_v"]:
|
for limit in ["max_i_neg", "max_i_pos", "max_v"]:
|
||||||
if pwm_channel[limit] == 0.0:
|
if pwm_channel[limit]["value"] == 0.0:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"`{}` limit is set to zero on channel {}".format(
|
"`{}` limit is set to zero on channel {}".format(
|
||||||
limit, pwm_channel["channel"]
|
limit, pwm_channel["channel"]
|
||||||
|
@ -28,13 +28,13 @@ class Thermostat(QObject, metaclass=PropertyMeta):
|
|||||||
NUM_CHANNELS = 2
|
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._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
|
self.connection_state = ThermostatConnectionState.DISCONNECTED
|
||||||
|
|
||||||
async def start_session(self, host, port):
|
async def start_session(self, host, port):
|
||||||
|
@ -137,7 +137,7 @@ class CtrlPanel(QObject):
|
|||||||
auto_tuner_param = inner_param.opts["pid_autotune"]
|
auto_tuner_param = inner_param.opts["pid_autotune"]
|
||||||
self.autotuners.set_params(auto_tuner_param, ch, new_value)
|
self.autotuners.set_params(auto_tuner_param, ch, new_value)
|
||||||
|
|
||||||
@pyqtSlot(list)
|
@pyqtSlot("QVariantList")
|
||||||
def update_pid(self, pid_settings):
|
def update_pid(self, pid_settings):
|
||||||
for settings in pid_settings:
|
for settings in pid_settings:
|
||||||
channel = settings["channel"]
|
channel = settings["channel"]
|
||||||
@ -161,7 +161,7 @@ class CtrlPanel(QObject):
|
|||||||
"output", "control_method", "target"
|
"output", "control_method", "target"
|
||||||
).set_value_with_lock(settings["target"])
|
).set_value_with_lock(settings["target"])
|
||||||
|
|
||||||
@pyqtSlot(list)
|
@pyqtSlot("QVariantList")
|
||||||
def update_report(self, report_data):
|
def update_report(self, report_data):
|
||||||
for settings in report_data:
|
for settings in report_data:
|
||||||
channel = settings["channel"]
|
channel = settings["channel"]
|
||||||
@ -183,7 +183,7 @@ class CtrlPanel(QObject):
|
|||||||
"readings", "tec_i"
|
"readings", "tec_i"
|
||||||
).set_value_with_lock(settings["tec_i"])
|
).set_value_with_lock(settings["tec_i"])
|
||||||
|
|
||||||
@pyqtSlot(list)
|
@pyqtSlot("QVariantList")
|
||||||
def update_thermistor(self, sh_data):
|
def update_thermistor(self, sh_data):
|
||||||
for sh_param in sh_data:
|
for sh_param in sh_data:
|
||||||
channel = sh_param["channel"]
|
channel = sh_param["channel"]
|
||||||
@ -198,25 +198,22 @@ class CtrlPanel(QObject):
|
|||||||
sh_param["params"]["b"]
|
sh_param["params"]["b"]
|
||||||
)
|
)
|
||||||
|
|
||||||
@pyqtSlot(list)
|
@pyqtSlot("QVariantList")
|
||||||
def update_pwm(self, pwm_data):
|
def update_pwm(self, pwm_data):
|
||||||
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]):
|
||||||
self.params[channel].child(
|
|
||||||
"output", "polarity"
|
|
||||||
).set_value_with_lock(pwm_params["polarity"])
|
|
||||||
self.params[channel].child(
|
self.params[channel].child(
|
||||||
"output", "limits", "max_v"
|
"output", "limits", "max_v"
|
||||||
).set_value_with_lock(pwm_params["max_v"])
|
).set_value_with_lock(pwm_params["max_v"]["value"])
|
||||||
self.params[channel].child(
|
self.params[channel].child(
|
||||||
"output", "limits", "max_i_pos"
|
"output", "limits", "max_i_pos"
|
||||||
).set_value_with_lock(pwm_params["max_i_pos"])
|
).set_value_with_lock(pwm_params["max_i_pos"]["value"])
|
||||||
self.params[channel].child(
|
self.params[channel].child(
|
||||||
"output", "limits", "max_i_neg"
|
"output", "limits", "max_i_neg"
|
||||||
).set_value_with_lock(pwm_params["max_i_neg"])
|
).set_value_with_lock(pwm_params["max_i_neg"]["value"])
|
||||||
|
|
||||||
@pyqtSlot(list)
|
@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:
|
||||||
channel = postfilter_params["channel"]
|
channel = postfilter_params["channel"]
|
||||||
|
@ -34,19 +34,6 @@
|
|||||||
"type": "group",
|
"type": "group",
|
||||||
"tip": "Settings of the output to the TEC",
|
"tip": "Settings of the output to the TEC",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
|
||||||
"name": "polarity",
|
|
||||||
"title": "Polarity",
|
|
||||||
"type": "list",
|
|
||||||
"limits": {
|
|
||||||
"Normal": "normal",
|
|
||||||
"Reversed": "reversed"
|
|
||||||
},
|
|
||||||
"thermostat:set_param": {
|
|
||||||
"topic": "pwm",
|
|
||||||
"field": "polarity"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "control_method",
|
"name": "control_method",
|
||||||
"title": "Control Method",
|
"title": "Control Method",
|
||||||
@ -303,7 +290,7 @@
|
|||||||
"title": "Ki",
|
"title": "Ki",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"step": 0.1,
|
"step": 0.1,
|
||||||
"suffix": "τ⁻¹",
|
"suffix": "Hz",
|
||||||
"noUnitEditing": true,
|
"noUnitEditing": true,
|
||||||
"compactHeight": false,
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
@ -318,7 +305,7 @@
|
|||||||
"title": "Kd",
|
"title": "Kd",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"step": 0.1,
|
"step": 0.1,
|
||||||
"suffix": "τ",
|
"suffix": "s",
|
||||||
"noUnitEditing": true,
|
"noUnitEditing": true,
|
||||||
"compactHeight": false,
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
|
@ -10,14 +10,14 @@ class ZeroLimitsWarningView(QObject):
|
|||||||
self._lbl = limit_warning
|
self._lbl = limit_warning
|
||||||
self._style = style
|
self._style = style
|
||||||
|
|
||||||
@pyqtSlot(list)
|
@pyqtSlot("QVariantList")
|
||||||
def set_limits_warning(self, pwm_data: list):
|
def set_limits_warning(self, pwm_data: list):
|
||||||
channels_zeroed_limits = [set() for i in range(self._thermostat.NUM_CHANNELS)]
|
channels_zeroed_limits = [set() for i in range(self._thermostat.NUM_CHANNELS)]
|
||||||
|
|
||||||
for pwm_params in pwm_data:
|
for pwm_params in pwm_data:
|
||||||
channel = pwm_params["channel"]
|
channel = pwm_params["channel"]
|
||||||
for limit in "max_i_pos", "max_i_neg", "max_v":
|
for limit in "max_i_pos", "max_i_neg", "max_v":
|
||||||
if pwm_params[limit] == 0.0:
|
if pwm_params[limit]["value"] == 0.0:
|
||||||
channels_zeroed_limits[channel].add(limit)
|
channels_zeroed_limits[channel].add(limit)
|
||||||
|
|
||||||
channel_disabled = [False, False]
|
channel_disabled = [False, False]
|
||||||
|
@ -1,17 +1,3 @@
|
|||||||
"""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.zero_limits_warning_view import ZeroLimitsWarningView
|
||||||
from pytec.gui.view.thermostat_settings_menu import ThermostatSettingsMenu
|
from pytec.gui.view.thermostat_settings_menu import ThermostatSettingsMenu
|
||||||
from pytec.gui.view.connection_details_menu import ConnectionDetailsMenu
|
from pytec.gui.view.connection_details_menu import ConnectionDetailsMenu
|
||||||
@ -19,6 +5,18 @@ 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():
|
||||||
@ -77,7 +75,6 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
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()
|
||||||
@ -85,7 +82,6 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
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
|
||||||
@ -107,7 +103,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
[
|
[
|
||||||
[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
|
||||||
@ -169,22 +165,22 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
|
|
||||||
@pyqtSlot(int, PIDAutotuneState)
|
@pyqtSlot(int, PIDAutotuneState)
|
||||||
def _on_pid_autotune_state_changed(self, _ch, _state):
|
def _on_pid_autotune_state_changed(self, _ch, _state):
|
||||||
autotuning_channels = []
|
ch_tuning = []
|
||||||
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,
|
||||||
}:
|
}:
|
||||||
autotuning_channels.append(ch)
|
ch_tuning.append(ch)
|
||||||
|
|
||||||
if len(autotuning_channels) == 0:
|
if len(ch_tuning) == 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(
|
||||||
f"Autotuning channel {autotuning_channels}..."
|
"Autotuning channel {ch}...".format(ch=ch_tuning)
|
||||||
)
|
)
|
||||||
self.loading_spinner.start()
|
self.loading_spinner.start()
|
||||||
self.loading_spinner.show()
|
self.loading_spinner.show()
|
||||||
@ -193,12 +189,14 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
async def on_connect_btn_clicked(self):
|
async def on_connect_btn_clicked(self):
|
||||||
match self._thermostat.connection_state:
|
match self._thermostat.connection_state:
|
||||||
case ThermostatConnectionState.DISCONNECTED:
|
case ThermostatConnectionState.DISCONNECTED:
|
||||||
self._connecting_task = asyncio.current_task()
|
self._connecting_task = asyncio.create_task(
|
||||||
self._thermostat.connection_state = ThermostatConnectionState.CONNECTING
|
self._thermostat.start_session(
|
||||||
await self._thermostat.start_session(
|
host=self.connection_details_menu.host_set_line.text(),
|
||||||
host=self.connection_details_menu.host_set_line.text(),
|
port=self.connection_details_menu.port_set_spin.value(),
|
||||||
port=self.connection_details_menu.port_set_spin.value(),
|
)
|
||||||
)
|
)
|
||||||
|
self._thermostat.connection_state = ThermostatConnectionState.CONNECTING
|
||||||
|
await self._connecting_task
|
||||||
self._connecting_task = None
|
self._connecting_task = None
|
||||||
self._thermostat.connection_state = ThermostatConnectionState.CONNECTED
|
self._thermostat.connection_state = ThermostatConnectionState.CONNECTED
|
||||||
self._thermostat.start_watching()
|
self._thermostat.start_watching()
|
||||||
|
Loading…
Reference in New Issue
Block a user