Add explicit initial grain_mass/water_mass to the Sud doc

Sud now parses top-level grain_mass/water_mass (sibling to pot_mass/
pot_material/L/Td, defaulting to 0/0) - what's actually in the pot before
the brew starts, as opposed to default.step's grain_mass/water_mass, which
is just inert template filler. All sude/*.json docs gain explicit values
matching what their first step already resolved to.

tasks/sud.py's apply_plant_params() now takes grain_mass/water_mass
directly instead of a step dict: on_step_changed() still passes the active
step's own (these vary as malt goes in/water boils off), but the Load
handler now reads Sud.grain_mass/water_mass directly instead of parsing
schedule[0]. The GUI's status-line mass preview (shown immediately on
Load, before Start) does the same.

Also fixes a latent bug found along the way: _continue_forecast_after_confirm()'s
reconstructed sub-doc was missing L/Td/grain_mass/water_mass entirely,
silently falling back to generic defaults instead of the real Sud's own
values - invisible only because every current sude/*.json happens to use
those same defaults.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DkkuG48uHFCGKe6dPSERFk
This commit is contained in:
2026-06-22 20:19:25 +02:00
co-authored by Claude Sonnet 4.6
parent b925934e57
commit 5ccfcef679
8 changed files with 96 additions and 36 deletions
+19 -6
View File
@@ -66,6 +66,14 @@ EMPTY_SUD = {
# values brewpi.py used to hardcode for every brew alike.
'L': 0.2,
'Td': 30,
# Initial grain_mass/water_mass - what's actually in the pot before
# the brew starts (e.g. water added but no malt yet), as opposed to
# default.step's grain_mass/water_mass, which is just inert template
# filler for steps that don't override it. Lets a caller derive
# starting plant params directly (see SudTask.recv()'s Load handler)
# without having to parse the first step out of the schedule.
'grain_mass': 0,
'water_mass': 0,
'steps': [],
}
@@ -80,7 +88,8 @@ class Sud(AttributeChange):
self._data = EMPTY_SUD
(self.name, self.description, self.schedule, self.pot_mass,
self.pot_material, self.L, self.Td) = self._parse_data(self._data)
self.pot_material, self.L, self.Td, self.grain_mass,
self.water_mass) = self._parse_data(self._data)
self._paused_from = None
self._reset_run_state()
@@ -88,9 +97,10 @@ class Sud(AttributeChange):
@staticmethod
def _parse_data(data):
"""Parses a sud.json document into the (name, description, schedule,
pot_mass, pot_material, L, Td) tuple Sud needs. Computed up front
rather than assigned straight onto self, so a malformed load()
can't leave a half-applied schedule in place."""
pot_mass, pot_material, L, Td, grain_mass, water_mass) tuple Sud
needs. Computed up front rather than assigned straight onto self,
so a malformed load() can't leave a half-applied schedule in
place."""
name = data.get('Name', '')
description = data.get('Description', '')
@@ -101,8 +111,10 @@ class Sud(AttributeChange):
pot_material = data.get('pot_material')
L = data.get('L', EMPTY_SUD['L'])
Td = data.get('Td', EMPTY_SUD['Td'])
grain_mass = data.get('grain_mass', EMPTY_SUD['grain_mass'])
water_mass = data.get('water_mass', EMPTY_SUD['water_mass'])
return name, description, schedule, pot_mass, pot_material, L, Td
return name, description, schedule, pot_mass, pot_material, L, Td, grain_mass, water_mass
def _reset_run_state(self):
"""Resets run-time progress back to a freshly-loaded, not-yet-started
@@ -136,7 +148,8 @@ class Sud(AttributeChange):
return False
(self.name, self.description, self.schedule, self.pot_mass,
self.pot_material, self.L, self.Td) = parsed
self.pot_material, self.L, self.Td, self.grain_mass,
self.water_mass) = parsed
self._data = data
self._reset_run_state()