forked from M-Labs/thermostat
linuswck
9acff86547
- Bugs fix: 1. Params Tree user input will not get overwritten by incoming report thermostat_data_model. 2. PID Autotune Sampling Period is now set according to Thermostat sampling interval 3. PID Autotune won't get stuck in Fail State 4. Various types disconnection related Bugs 5. Number of Samples stored in the plot cannot be set 6. Limit the max settable output current to be 2000mA - Improvement: 1. Params Tree settings can be changed with external json 2. Use a Tab system to show a single channel of config instead of two 3. Expose PID Autotune lookback params 4. Icon is changed to Artiq logo - Restructure: 1. Restructure the code to follow Model-View-Delegate Design Pattern
139 lines
4.4 KiB
Python
139 lines
4.4 KiB
Python
from pytec.aioclient import Client
|
|
from PyQt6.QtCore import pyqtSignal, QObject, pyqtSlot
|
|
from qasync import asyncSlot
|
|
from model.property import Property, PropertyMeta
|
|
import asyncio
|
|
import logging
|
|
|
|
|
|
class WrappedClient(QObject, Client):
|
|
connection_error = pyqtSignal()
|
|
|
|
async def _read_line(self):
|
|
try:
|
|
return await super()._read_line()
|
|
except (Exception, TimeoutError, asyncio.exceptions.TimeoutError):
|
|
logging.error("Client connection error, disconnecting", exc_info=True)
|
|
self.connection_error.emit()
|
|
|
|
|
|
class Thermostat(QObject, metaclass=PropertyMeta):
|
|
hw_rev = Property(dict)
|
|
fan = Property(dict)
|
|
thermistor = Property(list)
|
|
pid = Property(list)
|
|
pwm = Property(list)
|
|
postfilter = Property(list)
|
|
interval = Property(list)
|
|
report = Property(list)
|
|
info_box_trigger = pyqtSignal(str, str)
|
|
|
|
def __init__(self, parent, client, update_s):
|
|
self._update_s = update_s
|
|
self._client = client
|
|
self._watch_task = None
|
|
self._report_mode_task = None
|
|
self._poll_for_report = True
|
|
super().__init__(parent)
|
|
|
|
async def run(self):
|
|
self.task = asyncio.create_task(self.update_params())
|
|
while True:
|
|
if self.task.done():
|
|
if self.task.exception() is not None:
|
|
try:
|
|
raise self.task.exception()
|
|
except (
|
|
Exception,
|
|
TimeoutError,
|
|
asyncio.exceptions.TimeoutError,
|
|
):
|
|
logging.error(
|
|
"Encountered an error while updating parameter tree.",
|
|
exc_info=True,
|
|
)
|
|
_ = self.task.result()
|
|
self.task = asyncio.create_task(self.update_params())
|
|
await asyncio.sleep(self._update_s)
|
|
|
|
async def get_hw_rev(self):
|
|
self.hw_rev = await self._client.hw_rev()
|
|
return self.hw_rev
|
|
|
|
async def update_params(self):
|
|
self.fan = await self._client.get_fan()
|
|
self.pwm = await self._client.get_pwm()
|
|
if self._poll_for_report:
|
|
self.report = await self._client.report()
|
|
self.interval = [
|
|
self.report[i]["interval"] for i in range(len(self.report))
|
|
]
|
|
self.pid = await self._client.get_pid()
|
|
self.thermistor = await self._client.get_steinhart_hart()
|
|
self.postfilter = await self._client.get_postfilter()
|
|
|
|
def connected(self):
|
|
return self._client.connected
|
|
|
|
def connecting(self):
|
|
return self._client.connecting
|
|
|
|
def start_watching(self):
|
|
self._watch_task = asyncio.create_task(self.run())
|
|
|
|
@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.task.cancel()
|
|
self.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)
|
|
self.interval = [
|
|
self.report[i]["interval"] for i in range(len(self.report))
|
|
]
|
|
|
|
async def disconnect(self):
|
|
await self._client.end_session()
|
|
|
|
async def set_ipv4(self, ipv4):
|
|
await self._client.set_param("ipv4", ipv4)
|
|
|
|
async def get_ipv4(self):
|
|
return await self._client.ipv4()
|
|
|
|
@asyncSlot()
|
|
async def save_cfg(self, ch):
|
|
await self._client.save_config(ch)
|
|
self.info_box_trigger.emit(
|
|
"Config loaded", f"Channel {ch} Config has been loaded from flash."
|
|
)
|
|
|
|
@asyncSlot()
|
|
async def load_cfg(self, ch):
|
|
await self._client.load_config(ch)
|
|
self.info_box_trigger.emit(
|
|
"Config loaded", f"Channel {ch} Config has been loaded from flash."
|
|
)
|
|
|
|
async def dfu(self):
|
|
await self._client.dfu()
|
|
|
|
async def reset(self):
|
|
await self._client.reset()
|
|
|
|
@pyqtSlot(float)
|
|
def set_update_s(self, update_s):
|
|
self._update_s = update_s
|