Redesign Sud schedule format: separate ramp/hold keys with defaults
Steps now declare a "ramp" or "hold" key instead of a flat "type", and unspecified fields (including nested stirrer settings) fall back to a new top-level default.step structure. Stirrer config is now interval_time/on_ratio, mapping directly onto AStirrer's cycle time/duty cycle instead of separate on/off durations. Update components/sud.py, tasks/sud.py, the Sud demo, sude/sud_0010.json, and the README to match. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CgR9tPaSzFkAwRAUyeaaCD
This commit is contained in:
@@ -131,33 +131,43 @@ environment (`$WORKON_HOME`/`$BREWPI_HOME`) on a Raspberry Pi-style deployment.
|
||||
Files under `sude/` describe a brew's mash schedule ("Sud"): `pot_mass`,
|
||||
`pot_material`, `grain_mass`, `water_mass` (used by `Sud.derive_plant_params()`
|
||||
to compute a lumped thermal mass/specific-heat pair for `Pot`'s `M`/`C`, e.g.
|
||||
in `scripts/demos/sud/demo_sud.py`, instead of hand-tuning them), and a flat
|
||||
`schedule` list of steps, each either:
|
||||
in `scripts/demos/sud/demo_sud.py`, instead of hand-tuning them), and a
|
||||
`steps` list, each either:
|
||||
|
||||
- `"type": "heat"` — ramp to `temp` at `rate` (°C/min), or
|
||||
- `"type": "hold"` — hold the current target for `duration` seconds (omit
|
||||
for an immediate, zero-duration step).
|
||||
- a ramp — `"ramp": {"rate": ..., "temp": ...}` — ramp to `temp` at `rate`
|
||||
(°C/min), or
|
||||
- a hold — `"hold": {"duration": ...}` — hold the current target for
|
||||
`duration` seconds (omit/`0` for an immediate 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
|
||||
Both `ramp` and `hold` carry a `stirrer` block (`speed`, `interval_time`,
|
||||
`on_ratio`): `interval_time: 0` runs the stirrer continuously at `speed`;
|
||||
`interval_time > 0` pulses it on a period of `interval_time` seconds, on for
|
||||
`on_ratio * interval_time` of it. A step may also set
|
||||
`user_wait_for_continue: true` (with an optional `user_message` to prompt
|
||||
the user with) to pause for confirmation once the step completes, e.g. to
|
||||
add malt or check gravity, instead of advancing immediately.
|
||||
|
||||
The top-level `default.step` object gives every field above (including the
|
||||
nested `ramp`/`hold`/`stirrer` blocks) a default value; a step in `steps`
|
||||
only needs to specify the fields it overrides — anything it omits is filled
|
||||
in from `default.step`, recursively. A step is a ramp or a hold depending on
|
||||
which of those two keys it specifies; the other is not defaulted in.
|
||||
|
||||
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 step and
|
||||
automatically: `components/sud.py`'s `Sud` resolves each raw step against
|
||||
`default.step` and tracks the current (resolved) step, while
|
||||
`tasks/sud.py`'s `SudTask` drives the temperature controller's
|
||||
`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).
|
||||
`theta_soll`/`heatrate_soll` from ramp steps (advancing once `theta_ist`
|
||||
settles close to the target), counts down hold steps' `duration`, and
|
||||
applies each step's `stirrer` block (`interval_time`/`on_ratio` map directly
|
||||
onto the stirrer's cycle time/duty cycle). 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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user