feat: show status line earlier and count energy without a running Sud

Both clients' status line only showed pot mass/water/energy once a Sud
schedule was loaded and running, leaving it blank/minimal at connect
time and while idle. Show it as early as possible instead, falling back
to config.json's Pot section (mass/water_mass/volumen) when no schedule
is loaded yet; step description/remaining-time still only appear once a
schedule is actually active.

web/app.js: updateStatusLine() now mirrors updatePotVisualization()'s
existing sudEmpty ? potConfig... : sud... pattern, and adds a Volume
figure that was previously only used for the pot-fill visualization.

client/brewpi_gui.py: same treatment, plus new sud_volumen tracking
(the desktop GUI had no volume concept at all before - added by reading
the doc's own pot.volumen with a config fallback, since Sud._parse_data()
doesn't return it). The System message's 'Pot' key now also refreshes
the status label immediately so it doesn't wait for some unrelated
message to trigger a repaint.

tasks/sud.py: energy was only accumulated outside IDLE/DONE, so a
manually-driven heater with no Sud loaded/started never counted toward
the total shown in either client. Now counts in every state except
DONE - IDLE banks into a stable index -1 that's never shown per-step
(Progress tab only covers the schedule's own indices) but is included
in the status line's summed total.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M2ierBoxW3v7nUbDw3M2pE
This commit is contained in:
2026-07-06 10:45:55 +02:00
co-authored by Claude Sonnet 5
parent 57677d7881
commit 6d1429daca
3 changed files with 88 additions and 57 deletions
+48 -30
View File
@@ -457,6 +457,7 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.sud_pot_mass = 0
self.sud_grain_mass = 0
self.sud_water_mass = 0
self.sud_volumen = 0
self.sud_step_index = None
self.sud_step_descr = None
self.sud_step_type = None
@@ -745,6 +746,7 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.sud_pot_mass = 0
self.sud_grain_mass = 0
self.sud_water_mass = 0
self.sud_volumen = 0
self.sud_step_index = None
self.sud_step_descr = None
self.sud_step_type = None
@@ -787,6 +789,8 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.doubleSpinBox_pot_temp.setVisible(msg['PlantSim'])
elif "Pot" in key:
self.pot_config = msg['Pot']
if self.sud_empty:
self.update_status_step_label()
self.update_status_env_label()
def on_action_pot_reset(self):
@@ -1166,42 +1170,50 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self._update_step_plates()
def update_status_step_label(self):
if self.sud_step_descr:
# +1: sud_step_index is the 0-based index Sud.index uses, but
# StepPlate (the Progress tab) labels steps 1-based - match it
# here so the status bar doesn't announce a step one number
# below what the Progress tab shows for the same step.
text = "Step {}: {}".format(self.sud_step_index + 1, self.sud_step_descr)
if self.sud_step_type == 'hold':
remaining = max(self.sud_hold_remaining, 0.0)
text += " ({:.0f}:{:02.0f} remaining)".format(remaining // 60, remaining % 60)
# sud_step_index is the same 0-based index Sud.index uses into
# its own schedule list (see components/sud.py) - self.
# sud_schedule is built from the very same doc, so it lines up
# directly; grain_mass/water_mass are already resolved against
# default.step there (see components/sud.py's _build_step()).
if 0 <= self.sud_step_index < len(self.sud_schedule):
step = self.sud_schedule[self.sud_step_index]
step_pot = step.get('pot', {})
grain, water = step_pot.get('grain_mass', 0), step_pot.get('water_mass', 0)
else:
grain, water = self.sud_grain_mass, self.sud_water_mass
elif self.sud_schedule:
# Loaded but not started yet (no real Step message has
text = ""
# Before any schedule is loaded, fall back to config.json's Pot
# section (self.pot_config, captured in on_system_changed()) so the
# status bar already shows pot mass/water/volume/energy as soon as
# the server connects, rather than a blank status bar until Load -
# mirrors web/app.js's updateStatusLine(). Step description/
# remaining-time only exist once a schedule is actually loaded, so
# they stay inside the "not empty" branch below.
if self.sud_empty:
pot = self.pot_config.get('mass', 0)
water = self.pot_config.get('water_mass', 0)
volumen = self.pot_config.get('volumen', 0)
grain = 0
else:
pot = self.sud_pot_mass
volumen = self.sud_volumen
grain, water = self.sud_grain_mass, self.sud_water_mass
if self.sud_step_descr:
# +1: sud_step_index is the 0-based index Sud.index uses, but
# StepPlate (the Progress tab) labels steps 1-based - match it
# here so the status bar doesn't announce a step one number
# below what the Progress tab shows for the same step.
text = "Step {}: {}".format(self.sud_step_index + 1, self.sud_step_descr)
if self.sud_step_type == 'hold':
remaining = max(self.sud_hold_remaining, 0.0)
text += " ({:.0f}:{:02.0f} remaining)".format(remaining // 60, remaining % 60)
# sud_step_index is the same 0-based index Sud.index uses into
# its own schedule list (see components/sud.py) - self.
# sud_schedule is built from the very same doc, so it lines up
# directly; grain_mass/water_mass are already resolved against
# default.step there (see components/sud.py's _build_step()).
if 0 <= self.sud_step_index < len(self.sud_schedule):
step = self.sud_schedule[self.sud_step_index]
step_pot = step.get('pot', {})
grain, water = step_pot.get('grain_mass', 0), step_pot.get('water_mass', 0)
# else: loaded but not started yet (no real Step message has
# arrived) - preview the doc's own initial grain_mass/
# water_mass right away instead of leaving the status line
# blank until Start, mirroring tasks/sud.py's SudTask.
# apply_plant_params() applying it to the real plant/
# controller immediately on Load too.
text = ""
grain, water = self.sud_grain_mass, self.sud_water_mass
else:
self.statusBar().clearMessage()
return
pot = self.sud_pot_mass
mass_text = "Pot: {:.2f} kg, Water: {:.2f} kg, Grain {:.2f} kg, total {:.2f} kg".format(
pot, water, grain, pot + water + grain)
mass_text = "Pot: {:.2f} kg, Water: {:.2f} kg, Grain {:.2f} kg, total {:.2f} kg, Volume {:.1f} L".format(
pot, water, grain, pot + water + grain, volumen)
text = text + " " + mass_text if text else mass_text
# Sums, not just the active step's own figures: total process time
# is just self.sud_elapsed_last (Sud's own tick-counted total -
@@ -1251,6 +1263,12 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.sud_pot_mass = pot_mass
self.sud_grain_mass = grain_mass
self.sud_water_mass = water_mass
# Sud._parse_data() has no notion of 'volumen' (unlike mass/L/Td,
# nothing downstream needs it for the actual physics) - read it
# straight off the doc, falling back to config.json's Pot.volumen
# same as _parse_data() does for mass, mirroring web/app.js's
# parseSudDoc().
self.sud_volumen = doc.get('pot', {}).get('volumen', self.pot_config.get('volumen', 0))
self.sud_empty = len(schedule) == 0
if is_new_schedule:
self.sud_step_descr = None