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:
@@ -3675,6 +3675,8 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>&File</string>
|
<string>&File</string>
|
||||||
</property>
|
</property>
|
||||||
|
<addaction name="actionSudDownload"/>
|
||||||
|
<addaction name="actionSudUpload"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menu_Help">
|
<widget class="QMenu" name="menu_Help">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@@ -3726,6 +3728,22 @@
|
|||||||
<string>Stop</string>
|
<string>Stop</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionSudDownload">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Download Sud...</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Save the running Sud's schedule to a local sud.json</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSudUpload">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Upload Sud...</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Replace the running Sud's schedule with a local sud.json</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from main_window import Ui_MainWindow
|
from main_window import Ui_MainWindow
|
||||||
from PyQt5 import QtWidgets, QtGui
|
from PyQt5 import QtWidgets, QtGui
|
||||||
|
import json
|
||||||
import sys
|
import sys
|
||||||
from ws.client.ws_client import WsClient
|
from ws.client.ws_client import WsClient
|
||||||
from ws.message import MessageDispatcherSync
|
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_heater = self.msg_dispatch.msgio_get('Heater')
|
||||||
self.msg_stirrer = self.msg_dispatch.msgio_get('Stirrer')
|
self.msg_stirrer = self.msg_dispatch.msgio_get('Stirrer')
|
||||||
self.msg_tempctrl = self.msg_dispatch.msgio_get('TempCtrl')
|
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_pot.set_recv_handler(self.on_pot_changed)
|
||||||
self.msg_sensor.set_recv_handler(self.on_sensor_changed)
|
self.msg_sensor.set_recv_handler(self.on_sensor_changed)
|
||||||
self.msg_heater.set_recv_handler(self.on_heater_changed)
|
self.msg_heater.set_recv_handler(self.on_heater_changed)
|
||||||
self.msg_stirrer.set_recv_handler(self.on_stirrer_changed)
|
self.msg_stirrer.set_recv_handler(self.on_stirrer_changed)
|
||||||
self.msg_tempctrl.set_recv_handler(self.on_tempctrl_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.setupUi(self)
|
||||||
self.actionStart.triggered.connect(self.connect)
|
self.actionStart.triggered.connect(self.connect)
|
||||||
self.actionStop.triggered.connect(self.disconnect)
|
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_pwr_soll.valueChanged.connect(self.on_slider_pwr_soll_changed)
|
||||||
self.Slider_temp_soll.valueChanged.connect(self.on_slider_temp_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)
|
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_heater_activate_initial_update = True
|
||||||
self.checkbox_stirrer_activate_initial_update = True
|
self.checkbox_stirrer_activate_initial_update = True
|
||||||
self.heatrate_soll_initial_update = True
|
self.heatrate_soll_initial_update = True
|
||||||
|
self.sud_download_path = None
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
self.slider_pwr_initial_update = True
|
self.slider_pwr_initial_update = True
|
||||||
@@ -86,6 +92,24 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
print("on_checkbox_stirrer_activate_changed {}".format(value))
|
print("on_checkbox_stirrer_activate_changed {}".format(value))
|
||||||
self.msg_stirrer.send({'Activate': int(value == 2)})
|
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):
|
def on_pot_changed(self, msg):
|
||||||
print("on_pot_changed {}".format(msg))
|
print("on_pot_changed {}".format(msg))
|
||||||
for key in 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.setMinimum(int(submsg['Min']))
|
||||||
self.Slider_speed_soll.setMaximum(int(submsg['Max']))
|
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):
|
def closeEvent(self, event):
|
||||||
print("Exitting gracefully!")
|
print("Exitting gracefully!")
|
||||||
self.ws_client.disconnect()
|
self.ws_client.disconnect()
|
||||||
|
|||||||
+12
-2
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Form implementation generated from reading ui file 'brewpi.ui'
|
# Form implementation generated from reading ui file 'brewpi.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt5 UI code generator 5.15.10
|
# Created by: PyQt5 UI code generator 5.15.11
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
@@ -1240,6 +1240,12 @@ class Ui_MainWindow(object):
|
|||||||
self.actionPause.setObjectName("actionPause")
|
self.actionPause.setObjectName("actionPause")
|
||||||
self.actionStop = QtWidgets.QAction(MainWindow)
|
self.actionStop = QtWidgets.QAction(MainWindow)
|
||||||
self.actionStop.setObjectName("actionStop")
|
self.actionStop.setObjectName("actionStop")
|
||||||
|
self.actionSudDownload = QtWidgets.QAction(MainWindow)
|
||||||
|
self.actionSudDownload.setObjectName("actionSudDownload")
|
||||||
|
self.actionSudUpload = QtWidgets.QAction(MainWindow)
|
||||||
|
self.actionSudUpload.setObjectName("actionSudUpload")
|
||||||
|
self.menu_File.addAction(self.actionSudDownload)
|
||||||
|
self.menu_File.addAction(self.actionSudUpload)
|
||||||
self.menubar.addAction(self.menu_File.menuAction())
|
self.menubar.addAction(self.menu_File.menuAction())
|
||||||
self.menubar.addAction(self.menu_Help.menuAction())
|
self.menubar.addAction(self.menu_Help.menuAction())
|
||||||
self.toolBar.addAction(self.actionStart)
|
self.toolBar.addAction(self.actionStart)
|
||||||
@@ -1272,7 +1278,7 @@ class Ui_MainWindow(object):
|
|||||||
self.label_5.setText(_translate("MainWindow", "Power [W]"))
|
self.label_5.setText(_translate("MainWindow", "Power [W]"))
|
||||||
self.label_7.setText(_translate("MainWindow", "State"))
|
self.label_7.setText(_translate("MainWindow", "State"))
|
||||||
self.label_state.setText(_translate("MainWindow", "State"))
|
self.label_state.setText(_translate("MainWindow", "State"))
|
||||||
self.plainTextUri.setPlainText(_translate("MainWindow", "ws://localhost:8765"))
|
self.plainTextUri.setPlainText(_translate("MainWindow", "ws://brewpi:8765"))
|
||||||
self.label_8.setText(_translate("MainWindow", "Host"))
|
self.label_8.setText(_translate("MainWindow", "Host"))
|
||||||
self.menu_File.setTitle(_translate("MainWindow", "&File"))
|
self.menu_File.setTitle(_translate("MainWindow", "&File"))
|
||||||
self.menu_Help.setTitle(_translate("MainWindow", "&Help"))
|
self.menu_Help.setTitle(_translate("MainWindow", "&Help"))
|
||||||
@@ -1284,3 +1290,7 @@ class Ui_MainWindow(object):
|
|||||||
self.actionPause.setToolTip(_translate("MainWindow", "Pause"))
|
self.actionPause.setToolTip(_translate("MainWindow", "Pause"))
|
||||||
self.actionStop.setText(_translate("MainWindow", "Stop"))
|
self.actionStop.setText(_translate("MainWindow", "Stop"))
|
||||||
self.actionStop.setToolTip(_translate("MainWindow", "Stop"))
|
self.actionStop.setToolTip(_translate("MainWindow", "Stop"))
|
||||||
|
self.actionSudDownload.setText(_translate("MainWindow", "&Download Sud..."))
|
||||||
|
self.actionSudDownload.setToolTip(_translate("MainWindow", "Save the running Sud\'s schedule to a local sud.json"))
|
||||||
|
self.actionSudUpload.setText(_translate("MainWindow", "&Upload Sud..."))
|
||||||
|
self.actionSudUpload.setToolTip(_translate("MainWindow", "Replace the running Sud\'s schedule with a local sud.json"))
|
||||||
|
|||||||
Reference in New Issue
Block a user