Wire Pause/Stop to the Sud state machine, with a resumable pause

components/sud.py: adds SudState.PAUSED. pause() freezes RAMPING/
HOLDING (the hold countdown and ramp-reached checks both no-op while
PAUSED, since they're gated on the exact state they froze); start()
now doubles as resume when paused. stop() aborts back to IDLE from
any in-progress state, reusing the same reset logic as __init__/
upload() (factored into _reset_run_state()).

tasks/sud.py: maps 'Pause'/'Stop' messages to the new methods, and
turns the stirrer off on IDLE (not just DONE) so stop() actually
silences it instead of leaving the last step's stirring running.

client/brewpi_gui.py: wires the Pause/Stop toolbar actions, extends
update_sud_actions() so Start doubles as Resume and Stop stays usable
while paused, and freezes the forecast plot's progress line for the
duration of a pause (tracked via accumulated paused time) instead of
letting it drift ahead of actual progress.
This commit is contained in:
2026-06-20 23:48:03 +02:00
parent 4a824d09cc
commit 5d884ca3da
3 changed files with 74 additions and 18 deletions
+5 -1
View File
@@ -53,7 +53,7 @@ class SudTask(ATask):
def on_state_changed(self, value):
asyncio.create_task(self.send({'State': str(value)}))
if value == SudState.DONE:
if value in (SudState.DONE, SudState.IDLE):
self.stirrer.set_duty_cycle(1.0)
self.stirrer.set_speed(0)
@@ -69,6 +69,10 @@ class SudTask(ATask):
self.sud.start()
elif 'Confirm' in pair[0]:
self.sud.confirm()
elif 'Pause' in pair[0]:
self.sud.pause()
elif 'Stop' in pair[0]:
self.sud.stop()
elif 'Download' in pair[0]:
await self.send({'Json': self.sud.download()})
elif 'Upload' in pair[0]: