Sud: server always starts empty; sude/*.json is purely a client concern

Several sude/*.json schedules can exist on disk; only one runs at a
time, chosen by a client Load. Sud no longer takes a path at all - it
starts empty (EMPTY_SUD) and the server config no longer names a
specific schedule file, removing the implicit link to sud_0010.json
in particular. Reading/writing sude/*.json is now entirely the
client's job (e.g. the GUI's Load/Save file dialogs); the server's Sud
only ever holds whatever was last Load()ed, in memory, until replaced
or the server restarts.

Updates demo_sud.py/demo_sud_save_load.py to construct an empty Sud()
and load() a schedule explicitly, matching the new constructor.
This commit is contained in:
2026-06-21 10:24:45 +02:00
parent 3ed2961dce
commit 2c25b8be50
7 changed files with 84 additions and 74 deletions
+23 -18
View File
@@ -38,9 +38,10 @@ components/ Pluggable building blocks behind factories:
actor/ heater and stirrer drivers: simulated, a
Hendi induction hob (serial protocol), or a
Pololu 1376 stirrer motor controller
sud.py optional mash-schedule sequencer that steps
through a sude/*.json schedule and drives
the temperature controller from it
sud.py mash-schedule sequencer; starts out empty,
a client loads one of several sude/*.json
schedules onto it and it drives the
temperature controller from it
tasks/ Async tasks (one per component) that poll
hardware/sim state at a fixed interval and
@@ -168,21 +169,25 @@ 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` 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 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).
The server always runs a `Sud` (`components/sud.py`), starting out empty (no
schedule) - `sude/` can hold several schedule files, and a client loads one
of them onto the running `Sud` (`{"Sud": {"Load": <sud.json contents>}}`),
kept purely in memory until replaced by another Load or the server
restarts; nothing is ever read from or written to `sude/*.json` by the
server itself, that's on the client (e.g. the GUI's File menu). `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 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. With no schedule loaded (or all its steps run), it just sits idle -
manual `theta_soll`/`heatrate_soll` control via the GUI works the same as
ever.
## Logging & analysis