Adapt Sud/SudTask/demo to the new flat heat/hold schedule schema

sude/sud_0010.json moved from a list of combined ramp+hold+wait
"Rasten" with global stirrer constants to a flat "schedule" list of
explicit {"type": "heat"|"hold", ...} steps, each carrying its own
stirrer_speed/stirrer_time_on/stirrer_time_off and an optional
user_wait_for_continue (+ user_message).

- components/sud.py: Sud now tracks the current `step` instead of
  `rast`; "heat" steps enter RAMPING (advanced externally via
  temp_reached()), "hold" steps enter HOLDING and count down
  `duration` minutes (0 if omitted). Either step type can pause in
  WAIT_USER via user_wait_for_continue, surfaced through the new
  user_message attribute.
- tasks/sud.py: SudTask only pushes theta_soll/heatrate_soll on
  "heat" steps, converts each step's stirrer_time_on/off into a
  duty_cycle/cycle_time on every step change (replacing the old
  state-based RAMPING/HOLDING stirrer switching), and broadcasts
  user_message changes. Stirring is now fully schedule-driven instead
  of implicitly stopped on WAIT_USER/DONE (DONE still stops it, since
  there's no step left to read settings from).
- scripts/demos/sud/demo_sud.py: mirrors the same step-driven wiring.
- README's Mash schedules section rewritten for the new schema.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 19:09:43 +02:00
co-authored by Claude Sonnet 4.6
parent 2845051350
commit b33f89a569
5 changed files with 176 additions and 96 deletions
+26 -19
View File
@@ -62,9 +62,10 @@ scripts/demos/ Standalone, eyeballed-plot demos (matplotlib)
`python -m scripts.demos.sud.demo_sud`.
sude/ Mash schedules ("Sud" = brew/wort), each a
JSON list of temperature rests ("Rasten")
with target temperature, heat rate, and
optional pause for user confirmation.
JSON list of "heat"/"hold" steps with target
temperature/heat rate or hold duration,
per-step stirrer timing, and optional pause
for user confirmation.
config.json.templ Configuration template (real hardware).
config.json.sim Configuration template for simulation mode.
@@ -128,26 +129,32 @@ environment (`$WORKON_HOME`/`$BREWPI_HOME`) on a Raspberry Pi-style deployment.
## Mash schedules
Files under `sude/` describe a brew's mash schedule ("Sud"): pot weight,
malt/water weights, stirrer speed/duty, and a list of temperature rests
("Rasten"), each with a target `temp`, `heatRate`, hold `time` (minutes), and
whether to `waitForUser` before continuing (e.g. to add malt or check
gravity).
malt/water weights, and a flat `schedule` list of steps, each either:
- `"type": "heat"` — ramp to `temp` at `rate` (°C/min), or
- `"type": "hold"` — hold the current target for `duration` minutes (omit
for an immediate, zero-duration step).
Every step also carries its own stirrer timing (`stirrer_speed`,
`stirrer_time_on`/`stirrer_time_off` in seconds — `time_off: 0` means
continuous), and may set `user_wait_for_continue: true` (with an optional
`user_message`) to pause for confirmation once the step completes, e.g. to
add malt or check gravity, instead of advancing immediately.
Set the top-level `sud` config key to a path under `sude/` (see
`config.json.sim`/`config.json.templ`) to have the server step through it
automatically: `components/sud.py`'s `Sud` tracks the current rest and
automatically: `components/sud.py`'s `Sud` tracks the current step and
`tasks/sud.py`'s `SudTask` drives the temperature controller's
`theta_soll`/`heatrate_soll` from it, advancing once `theta_ist` settles
close to the target and the rest's hold time has elapsed. It also switches
the stirrer between the schedule's `stirrSpeedHeat` (continuous, while
ramping) and `stirrSpeedRast`/`stirrDutyRast`/`stirrCycleTime` (intermittent,
while holding), stopping it entirely during a `waitForUser` pause. It
exposes progress (current rest, remaining hold time, state) on the `"Sud"`
WebSocket channel and accepts `{"Sud": {"Start": true}}` to begin the
schedule and `{"Sud": {"Confirm": true}}` to acknowledge a `waitForUser`
pause and move to the next rest. Omit `sud` from the config to
run without schedule automation (manual `theta_soll`/`heatrate_soll` control
via the GUI, as before).
`theta_soll`/`heatrate_soll` from `"heat"` steps (advancing once `theta_ist`
settles close to the target) and counts down `"hold"` steps' `duration`,
applying each step's stirrer timing as it goes (converting
`stirrer_time_on`/`stirrer_time_off` into a duty cycle/cycle time). It
exposes progress (current step, remaining hold time, state, any
`user_message`) on the `"Sud"` WebSocket channel and accepts
`{"Sud": {"Start": true}}` to begin the schedule and `{"Sud": {"Confirm":
true}}` to acknowledge a pause and move to the next step. Omit `sud` from
the config to run without schedule automation (manual
`theta_soll`/`heatrate_soll` control via the GUI, as before).
## Logging & analysis