diff --git a/README.md b/README.md index 7c08003..22b1ebd 100644 --- a/README.md +++ b/README.md @@ -347,9 +347,15 @@ in closed-loop mode (the default) and disabled in open-loop mode. This is wired up in `server/brewpi.py` via `heater_task.set_on_closed_loop_changed(tc.set_enabled)`, and fired once at startup from `HeaterTask.on_process()` so the TC is live immediately. -`SudTask` no longer manages the TC's enabled state — its -`on_state_changed()` only stops the stirrer when a run ends. See "Heater -control modes" below. +`SudTask` no longer manages the TC's enabled state directly; instead, when +a run ends (state reaches `DONE` or `IDLE` — whether the schedule completed +or Stop was pressed), it fires an `_on_end` callback that calls +`HeaterTask.shutdown()`: this zeros `power_soll`, disables the TC, switches +`closed_loop` to `False`, and broadcasts `{ClosedLoop: false}` to all clients +so their checkboxes uncheck immediately. Re-enabling for manual use after a +stop requires the user to check the Closed-loop checkbox again (or the +next `Start` press does it automatically — see "Heater control modes"). See +"Heater control modes" below. ### Heater control modes @@ -380,7 +386,11 @@ browser tab is immediately reflected in every other connected client. On every resume from pause, `SudTask.recv()` restores the current step's schedule parameters (temperature setpoint, heat rate, stirrer) before the run continues, overwriting any manual adjustments the user made while -paused. +paused. Steps that carry no `temperature` of their own (`temperature=None` +— they inherit whatever the previous step left the TC targeting) are +handled via `_paused_temp_soll`: the setpoint is saved the moment Pause is +pressed and restored as a fallback on resume, so the TC always snaps back +to the correct target even for inherited-temperature steps. ### Forecast vs. actual duration @@ -614,10 +624,21 @@ Additional features beyond the initial port: Sud is paused or stopped; auto-reset to Closed-loop on play. Slider enable/disable follows the mode: temperature setpoint and heat rate active in Closed-loop + not running; heater power active in Open-loop + - not running. -- **Header countdown**: step remaining and total remaining timers, - displayed in accent-coloured monospace next to the transport buttons, - derived from `forecast_step_starts`/`StepStarts`. + not running. When a run ends (DONE or Stop), `HeaterTask.shutdown()` + fires automatically — the checkbox unchecks, power goes to 0, TC is + disabled (see "Heater control modes" above). +- **Header countdown**: three monospace rows next to the transport buttons, + always in `h:mm:ss` format: *total* (time until the schedule finishes), + *ramp* (ramp phase remaining for the current step — total step span minus + the configured hold duration), and *hold* (`Sud.hold_remaining` pushed + live from the server). All three derive from `forecast_step_starts`/ + `StepStarts`; "ramp" shows `0:00:00` once the hold phase begins. +- **Step-plate countdowns**: each plate's top-right shows the remaining + ramp time in green digits. The active step overrides this with a "Ramp + h:mm:ss" or "Hold h:mm:ss" prefix (same element reused for both phases). + Configured hold duration (`hold.duration` formatted as `h:mm:ss`) is + shown as a static field on each plate; steps with no hold phase show + "Hold —". - **Controls always reflect server values**: sliders and readouts track every server push unconditionally — there are no "initial sync only" guards that could leave a control stale after a reconnect or while