Wire Sud upload/download into the brewpi_gui client

Adds File menu actions to save the running Sud's schedule to a local
sud.json and to replace it from one, via the Sud websocket channel's
new Download/Upload messages. File dialogs are opened up front on the
GUI thread; the actual read/write happens off the websocket recv
callback, which runs on a worker thread and must not touch Qt itself.

main_window.py is regenerated from brewpi.ui via pyuic5 5.15.11, which
also picks up an unrelated pre-existing drift (the default URI had
fallen out of sync with the .ui source).
This commit is contained in:
2026-06-20 22:18:49 +02:00
parent db57f3305c
commit bb94e065f4
3 changed files with 64 additions and 2 deletions
+34
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
from main_window import Ui_MainWindow
from PyQt5 import QtWidgets, QtGui
import json
import sys
from ws.client.ws_client import WsClient
from ws.message import MessageDispatcherSync
@@ -22,16 +23,20 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.msg_heater = self.msg_dispatch.msgio_get('Heater')
self.msg_stirrer = self.msg_dispatch.msgio_get('Stirrer')
self.msg_tempctrl = self.msg_dispatch.msgio_get('TempCtrl')
self.msg_sud = self.msg_dispatch.msgio_get('Sud')
self.msg_pot.set_recv_handler(self.on_pot_changed)
self.msg_sensor.set_recv_handler(self.on_sensor_changed)
self.msg_heater.set_recv_handler(self.on_heater_changed)
self.msg_stirrer.set_recv_handler(self.on_stirrer_changed)
self.msg_tempctrl.set_recv_handler(self.on_tempctrl_changed)
self.msg_sud.set_recv_handler(self.on_sud_changed)
self.setupUi(self)
self.actionStart.triggered.connect(self.connect)
self.actionStop.triggered.connect(self.disconnect)
self.actionSudDownload.triggered.connect(self.on_action_sud_download)
self.actionSudUpload.triggered.connect(self.on_action_sud_upload)
self.Slider_pwr_soll.valueChanged.connect(self.on_slider_pwr_soll_changed)
self.Slider_temp_soll.valueChanged.connect(self.on_slider_temp_soll_changed)
self.Slider_speed_soll.valueChanged.connect(self.on_slider_stirrer_speed_soll_changed)
@@ -48,6 +53,7 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.checkbox_heater_activate_initial_update = True
self.checkbox_stirrer_activate_initial_update = True
self.heatrate_soll_initial_update = True
self.sud_download_path = None
def connect(self):
self.slider_pwr_initial_update = True
@@ -86,6 +92,24 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
print("on_checkbox_stirrer_activate_changed {}".format(value))
self.msg_stirrer.send({'Activate': int(value == 2)})
def on_action_sud_download(self):
# Pick the destination up front, on the GUI thread - the actual
# write happens in on_sud_changed(), which runs off a worker thread
# and must not touch Qt (e.g. open a file dialog) itself.
path, _ = QtWidgets.QFileDialog.getSaveFileName(self, "Download Sud", filter="JSON files (*.json)")
if not path:
return
self.sud_download_path = path
self.msg_sud.send({'Download': True})
def on_action_sud_upload(self):
path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Upload Sud", filter="JSON files (*.json)")
if not path:
return
with open(path) as f:
data = json.load(f)
self.msg_sud.send({'Upload': data})
def on_pot_changed(self, msg):
print("on_pot_changed {}".format(msg))
for key in msg:
@@ -160,6 +184,16 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.Slider_speed_soll.setMinimum(int(submsg['Min']))
self.Slider_speed_soll.setMaximum(int(submsg['Max']))
def on_sud_changed(self, msg):
print("on_sud_changed {}".format(msg))
for key in msg:
if "Json" in key and self.sud_download_path:
with open(self.sud_download_path, 'w') as f:
json.dump(msg['Json'], f, indent='\t')
self.sud_download_path = None
elif "Name" in key:
self.statusBar().showMessage("Sud schedule updated: {}".format(msg['Name']), 5000)
def closeEvent(self, event):
print("Exitting gracefully!")
self.ws_client.disconnect()