Create client watcher, that would poll Thermostat for config

Signed-off-by: Egor Savkin <es@m-labs.hk>
Egor Savkin 2023-05-19 13:45:01 +08:00 committed by atse
parent f1a0a19bcc
commit 8ba2969bbc
1 changed files with 60 additions and 11 deletions

View File

@ -1,5 +1,5 @@
from PyQt6 import QtWidgets, uic from PyQt6 import QtWidgets, uic
from PyQt6.QtCore import QThread, QThreadPool, pyqtSignal, QRunnable, QObject, QSignalBlocker, pyqtSlot from PyQt6.QtCore import QThread, QThreadPool, pyqtSignal, QRunnable, QObject, QSignalBlocker, pyqtSlot, QDeadlineTimer
from pyqtgraph import PlotWidget from pyqtgraph import PlotWidget
from pyqtgraph.parametertree import Parameter, ParameterTree, ParameterItem, registerParameterType from pyqtgraph.parametertree import Parameter, ParameterTree, ParameterItem, registerParameterType
import pyqtgraph as pg import pyqtgraph as pg
@ -18,6 +18,8 @@ ui: Ui_MainWindow = None
thread_pool = QThreadPool.globalInstance() thread_pool = QThreadPool.globalInstance()
connection_watcher = None connection_watcher = None
client_watcher = None
app: QtWidgets.QApplication = None
def get_argparser(): def get_argparser():
@ -39,7 +41,7 @@ class WatchConnectTask(QThread):
connecting = pyqtSignal() connecting = pyqtSignal()
fan_update = pyqtSignal(object) fan_update = pyqtSignal(object)
def __init__(self, ip, port, parent): def __init__(self, parent, ip, port):
self.ip = ip self.ip = ip
self.port = port self.port = port
super().__init__(parent) super().__init__(parent)
@ -55,8 +57,8 @@ class WatchConnectTask(QThread):
self.connecting.emit() self.connecting.emit()
tec_client = Client(host=self.ip, port=self.port, timeout=30) tec_client = Client(host=self.ip, port=self.port, timeout=30)
self.connected.emit(True) self.connected.emit(True)
self.hw_rev.emit(tec_client.hw_rev()) thread_pool.start(ClientTask(lambda: self.hw_rev.emit(tec_client.hw_rev())))
self.fan_update.emit(tec_client.fan()) #thread_pool.start(ClientTask(lambda: self.fan_update.emit(tec_client.fan())))
except Exception as e: except Exception as e:
logging.error(f"Failed communicating to the {self.ip}:{self.port}: {e}") logging.error(f"Failed communicating to the {self.ip}:{self.port}: {e}")
self.connected.emit(False) self.connected.emit(False)
@ -67,7 +69,39 @@ class WatchConnectTask(QThread):
if tec_client: if tec_client:
tec_client.disconnect() tec_client.disconnect()
tec_client = None tec_client = None
self.connected.emit(False) self.connected.emit(False)
class ClientWatcher(QThread):
fan_update = pyqtSignal(object)
pwm_update = pyqtSignal(object)
report_update = pyqtSignal(object)
pid_update = pyqtSignal(object)
def __init__(self, parent, update_s):
self.update_s = update_s
self.running = True
super().__init__(parent)
def run(self):
while self.running:
thread_pool.start(ClientTask(lambda: self.update_params()))
self.msleep(int(self.update_s * 1000))
def update_params(self):
self.fan_update.emit(tec_client.fan())
@pyqtSlot()
def stop_watching(self):
self.running = False
deadline = QDeadlineTimer()
deadline.setDeadline(100)
self.wait(deadline)
self.terminate()
@pyqtSlot()
def set_update_s(self):
self.update_s = ui.report_refresh_spin.value()
class ClientTask(QRunnable): class ClientTask(QRunnable):
@ -77,16 +111,18 @@ class ClientTask(QRunnable):
self.kwargs = kwargs self.kwargs = kwargs
super().__init__() super().__init__()
def run(self) -> None: def run(self):
try: try:
self.func(*self.args, **self.kwargs) self.func(*self.args, **self.kwargs)
except (TimeoutError, OSError): except (TimeoutError, OSError):
logging.warning("Client connection error, disconnecting", exc_info=True) logging.warning("Client connection error, disconnecting", exc_info=True)
if connection_watcher: if connection_watcher:
thread_pool.clear() # clearing all next requests
connection_watcher.client_disconnected() connection_watcher.client_disconnected()
def connected(result): def connected(result):
global client_watcher, connection_watcher
ui.graph_group.setEnabled(result) ui.graph_group.setEnabled(result)
ui.hw_rev_lbl.setEnabled(result) ui.hw_rev_lbl.setEnabled(result)
ui.fan_group.setEnabled(result) ui.fan_group.setEnabled(result)
@ -99,6 +135,15 @@ def connected(result):
if not result: if not result:
ui.hw_rev_lbl.setText("Thermostat vX.Y") ui.hw_rev_lbl.setText("Thermostat vX.Y")
ui.fan_group.setStyleSheet("") ui.fan_group.setStyleSheet("")
if client_watcher:
client_watcher.stop_watching()
client_watcher = None
elif client_watcher is None:
client_watcher = ClientWatcher(ui.main_widget, ui.report_refresh_spin.value())
client_watcher.fan_update.connect(fan_update)
ui.report_apply_btn.clicked.connect(client_watcher.set_update_s)
app.aboutToQuit.connect(client_watcher.stop_watching)
client_watcher.start()
def hw_rev(hw_rev_d: dict): def hw_rev(hw_rev_d: dict):
@ -144,25 +189,29 @@ def fan_auto_set(enabled):
def connect(): def connect():
global connection_watcher global connection_watcher
connection_watcher = WatchConnectTask(ui.ip_set_line.text(), ui.port_set_spin.value(), ui.main_widget) connection_watcher = WatchConnectTask(ui.main_widget, ui.ip_set_line.text(), ui.port_set_spin.value())
connection_watcher.connected.connect(connected) connection_watcher.connected.connect(connected)
connection_watcher.connecting.connect(lambda: ui.status_lbl.setText("Connecting...")) connection_watcher.connecting.connect(lambda: ui.status_lbl.setText("Connecting..."))
connection_watcher.hw_rev.connect(hw_rev) connection_watcher.hw_rev.connect(hw_rev)
connection_watcher.fan_update.connect(fan_update) connection_watcher.fan_update.connect(fan_update)
connection_watcher.start() connection_watcher.start()
app.aboutToQuit.connect(connection_watcher.terminate)
def main(): def main():
global ui global ui, thread_pool, app
args = get_argparser().parse_args() args = get_argparser().parse_args()
if args.logLevel: if args.logLevel:
logging.basicConfig(level=getattr(logging, args.logLevel)) logging.basicConfig(level=getattr(logging, args.logLevel))
app = QtWidgets.QApplication(sys.argv) app = QtWidgets.QApplication(sys.argv)
main_window = QtWidgets.QMainWindow() main_window = QtWidgets.QMainWindow()
#ui = Ui_MainWindow() ui = Ui_MainWindow()
#ui.setupUi(main_window) ui.setupUi(main_window)
ui = uic.loadUi('tec_qt.ui', main_window) # ui = uic.loadUi('tec_qt.ui', main_window)
thread_pool = QThreadPool(parent=ui.main_widget)
thread_pool.setMaxThreadCount(1) # avoid concurrent requests
ui.connect_btn.clicked.connect(lambda _checked: connect()) ui.connect_btn.clicked.connect(lambda _checked: connect())
ui.fan_power_slider.valueChanged.connect(fan_set) ui.fan_power_slider.valueChanged.connect(fan_set)