Show the active step in the status bar and progress on the forecast plot

on_sud_changed() now handles 'Step' messages, showing the step's
description (and clearing it once there's no active step), and tracks
IDLE/DONE <-> running transitions to time a red vertical progress line
on the Automatic tab's forecast - elapsed real time since the brew
started, plotted against the forecast's nominal-schedule time axis so
you can see how actual progress compares to the plan.
This commit is contained in:
2026-06-20 23:32:01 +02:00
parent bd658199fe
commit 4a824d09cc
+33
View File
@@ -117,6 +117,7 @@ class SudForecastPlot(FigureCanvasQTAgg):
self.ax = figure.subplots(1, 1) self.ax = figure.subplots(1, 1)
self.line, = self.ax.plot([], [], '-b', linewidth=1.5) self.line, = self.ax.plot([], [], '-b', linewidth=1.5)
self.progress_line = self.ax.axvline(0, color='r', linewidth=1.5, visible=False)
self.ax.set_xlabel("t [min]") self.ax.set_xlabel("t [min]")
self.ax.set_ylabel("Temp [°C]") self.ax.set_ylabel("Temp [°C]")
_style_axis(self.ax) _style_axis(self.ax)
@@ -156,6 +157,15 @@ class SudForecastPlot(FigureCanvasQTAgg):
self.figure.tight_layout() self.figure.tight_layout()
self.draw_idle() self.draw_idle()
def set_progress(self, t_min):
self.progress_line.set_xdata([t_min, t_min])
self.progress_line.set_visible(True)
self.draw_idle()
def clear_progress(self):
self.progress_line.set_visible(False)
self.draw_idle()
class Window(QtWidgets.QMainWindow, Ui_MainWindow): class Window(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self): def __init__(self):
@@ -170,6 +180,10 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.connected = False self.connected = False
self.sud_loaded = False self.sud_loaded = False
self.sud_state = None self.sud_state = None
# time.monotonic() of the last IDLE/DONE -> running transition, used
# to position the forecast plot's progress line; None while not
# running.
self.sud_start_time = None
self.msg_pot = self.msg_dispatch.msgio_get('Pot') self.msg_pot = self.msg_dispatch.msgio_get('Pot')
self.msg_sensor = self.msg_dispatch.msgio_get('Sensor') self.msg_sensor = self.msg_dispatch.msgio_get('Sensor')
self.msg_heater = self.msg_dispatch.msgio_get('Heater') self.msg_heater = self.msg_dispatch.msgio_get('Heater')
@@ -253,6 +267,11 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.plot_rate_ist, self.plot_rate_soll, self.plot_rate_ist, self.plot_rate_soll,
self.plot_power_set, self.plot_power_eff) self.plot_power_set, self.plot_power_eff)
if self.sud_start_time is not None:
self.forecast_plot.set_progress((time.monotonic() - self.sud_start_time) / 60.0)
else:
self.forecast_plot.clear_progress()
def disconnect(self): def disconnect(self):
# ws_client.disconnect() blocks until the websocket's close handshake # ws_client.disconnect() blocks until the websocket's close handshake
# completes (or times out, ~10s if the server doesn't ack promptly), # completes (or times out, ~10s if the server doesn't ack promptly),
@@ -274,6 +293,7 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
# Nothing reported over a dead connection can be trusted anymore. # Nothing reported over a dead connection can be trusted anymore.
self.sud_loaded = False self.sud_loaded = False
self.sud_state = None self.sud_state = None
self.sud_start_time = None
self.update_sud_actions() self.update_sud_actions()
def update_sud_actions(self): def update_sud_actions(self):
@@ -425,7 +445,20 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
elif "Name" in key: elif "Name" in key:
self.statusBar().showMessage("Sud schedule updated: {}".format(msg['Name']), 5000) self.statusBar().showMessage("Sud schedule updated: {}".format(msg['Name']), 5000)
elif "State" in key: elif "State" in key:
running_before = self.sud_state in SUD_RUNNING_STATES
self.sud_state = msg['State'] self.sud_state = msg['State']
running_now = self.sud_state in SUD_RUNNING_STATES
if running_now and not running_before:
self.sud_start_time = time.monotonic()
elif not running_now:
self.sud_start_time = None
elif "Step" in key:
step = msg['Step']
descr = step.get('Descr')
if descr:
self.statusBar().showMessage("Step {}: {}".format(step.get('Index'), descr))
else:
self.statusBar().clearMessage()
self.update_sud_actions() self.update_sud_actions()
def update_sud_forecast(self, doc): def update_sud_forecast(self, doc):