diff --git a/brewpi/brewpi.py b/brewpi/brewpi.py
index 64a10a0..f4bc9a2 100755
--- a/brewpi/brewpi.py
+++ b/brewpi/brewpi.py
@@ -96,11 +96,24 @@ if __name__ == '__main__':
# Static, global info that doesn't belong to any one task - sent once;
# a client connecting later still gets it via the dispatcher's replay
- # of accumulated global_state on subscribe.
+ # of accumulated global_state on subscribe. AmbientTemp can also be
+ # changed live by a client (e.g. the GUI's ambient temperature field).
+ msg_system = dispatcher.msgio_get("System")
+
async def send_system_info():
- await dispatcher.msgio_get("System").send({'AmbientTemp': theta_amb, 'WarpFactor': DT / DT_TASK})
+ await msg_system.send({'AmbientTemp': theta_amb, 'WarpFactor': DT / DT_TASK})
asyncio.ensure_future(send_system_info())
+ async def on_system_recv(data):
+ global theta_amb
+ if 'AmbientTemp' in data:
+ theta_amb = data['AmbientTemp']
+ pot.set_ambient_temperature(theta_amb)
+ if hasattr(tc, 'set_ambient_temperature'):
+ tc.set_ambient_temperature(theta_amb)
+ await msg_system.send({'AmbientTemp': theta_amb})
+ msg_system.set_recv_handler(on_system_recv)
+
# Message dispatcher
h_dispatcher = taskmgr.start()
h_server = server.listen("0.0.0.0", 8765)
diff --git a/client/brewpi.ui b/client/brewpi.ui
index 4787b55..3f7e0b7 100644
--- a/client/brewpi.ui
+++ b/client/brewpi.ui
@@ -3682,6 +3682,35 @@
Connect
+
+
+
+ 520
+ 500
+ 91
+ 31
+
+
+
+ Ambient [°C]
+
+
+ Qt::AlignCenter
+
+
+
+
+
+ 620
+ 500
+ 70
+ 31
+
+
+
+ Set the simulated/assumed ambient temperature - press Enter to apply
+
+
diff --git a/client/brewpi_gui.py b/client/brewpi_gui.py
index e8a0527..509593c 100755
--- a/client/brewpi_gui.py
+++ b/client/brewpi_gui.py
@@ -329,6 +329,7 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.checkbox_heater_activate.stateChanged.connect(self.on_checkbox_changed)
self.checkbox_stirrer_activate.stateChanged.connect(self.on_checkbox_stirrer_activate_changed)
+ self.lineEdit_ambient.returnPressed.connect(self.on_ambient_entry_changed)
self.send_data = Queue()
self.slider_pwr_initial_update = True
@@ -460,6 +461,7 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.sud_state = None
self.sud_user_message = None
self.ambient_temp = None
+ self.lineEdit_ambient.clear()
self.warp_factor = 1.0
self.sud_start_time = None
self.sud_paused_total = 0.0
@@ -491,10 +493,22 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
for key in msg:
if "AmbientTemp" in key:
self.ambient_temp = msg['AmbientTemp']
+ # Only sync the entry's text while the user isn't actively
+ # editing it, so a server echo doesn't clobber in-progress
+ # typing.
+ if not self.lineEdit_ambient.hasFocus():
+ self.lineEdit_ambient.setText("{:.1f}".format(self.ambient_temp))
elif "WarpFactor" in key:
self.warp_factor = msg['WarpFactor']
self.update_status_env_label()
+ def on_ambient_entry_changed(self):
+ try:
+ value = float(self.lineEdit_ambient.text())
+ except ValueError:
+ return
+ self.msg_system.send({'AmbientTemp': value})
+
def update_status_env_label(self):
ambient = "{:.1f}°C".format(self.ambient_temp) if self.ambient_temp is not None else "-"
self.status_label_env.setText("Ambient: {} Warp: {:.1f}x".format(ambient, self.warp_factor))
diff --git a/client/main_window.py b/client/main_window.py
index 6a01936..d0d1661 100644
--- a/client/main_window.py
+++ b/client/main_window.py
@@ -1230,6 +1230,13 @@ class Ui_MainWindow(object):
self.btn_connect = QtWidgets.QPushButton(self.centralwidget)
self.btn_connect.setGeometry(QtCore.QRect(440, 500, 70, 31))
self.btn_connect.setObjectName("btn_connect")
+ self.label_ambient = QtWidgets.QLabel(self.centralwidget)
+ self.label_ambient.setGeometry(QtCore.QRect(520, 500, 91, 31))
+ self.label_ambient.setAlignment(QtCore.Qt.AlignCenter)
+ self.label_ambient.setObjectName("label_ambient")
+ self.lineEdit_ambient = QtWidgets.QLineEdit(self.centralwidget)
+ self.lineEdit_ambient.setGeometry(QtCore.QRect(620, 500, 70, 31))
+ self.lineEdit_ambient.setObjectName("lineEdit_ambient")
self.label_8 = QtWidgets.QLabel(self.centralwidget)
self.label_8.setGeometry(QtCore.QRect(200, 500, 67, 31))
self.label_8.setAlignment(QtCore.Qt.AlignCenter)
@@ -1298,6 +1305,8 @@ class Ui_MainWindow(object):
self.label_state.setText(_translate("MainWindow", "State"))
self.plainTextUri.setPlainText(_translate("MainWindow", "ws://localhost:8765"))
self.btn_connect.setText(_translate("MainWindow", "Connect"))
+ self.label_ambient.setText(_translate("MainWindow", "Ambient [°C]"))
+ self.lineEdit_ambient.setToolTip(_translate("MainWindow", "Set the simulated/assumed ambient temperature - press Enter to apply"))
self.label_8.setText(_translate("MainWindow", "Host"))
self.menu_File.setTitle(_translate("MainWindow", "&File"))
self.menu_Help.setTitle(_translate("MainWindow", "&Help"))
diff --git a/components/pid/temp_controller_smith.py b/components/pid/temp_controller_smith.py
index 066fdfb..c3008b0 100755
--- a/components/pid/temp_controller_smith.py
+++ b/components/pid/temp_controller_smith.py
@@ -28,6 +28,10 @@ class TempController(TempControllerBase):
self.model.set_thermal_params(M, C)
self.model_delay.set_thermal_params(M, C)
+ def set_ambient_temperature(self, theta_amb):
+ self.model.set_ambient_temperature(theta_amb)
+ self.model_delay.set_ambient_temperature(theta_amb)
+
def on_state_entered(self, state):
if state == States.HEAT:
self.model.initial(self.theta_ist)