Commit Graph
19 Commits
Author SHA1 Message Date
jensandClaude Sonnet 5 f20e617d81 feat: add connect/disconnect status for real heater/stirrer hardware
Heater and Stirrer can be real serial hardware (hendi, Pololu1376), but
there was no connection concept at all - the constructors opened the
port and crashed the whole server if the device was missing, with no
way to see connection status or firmware version and no way to
reconnect without a restart.

Adds an observable Connectable mixin (components/connectable.py) shared
by AHeater/AStirrer; real devices defer opening the serial port to an
explicit connect(), auto-connect on server startup, and surface
Connected/FirmwareVersion/Simulated plus manual Connect/Disconnect over
the web GUI. Heating/stirring and Sud Start are all gated on connection
state, and a disconnect mid-brew force-stops the run via the same path
as a manual Stop.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YaPLuRPpyjWcwhMvCvpHCL
2026-07-03 19:18:59 +02:00
jensandClaude Sonnet 4.6 9f221c5d19 fix: re-enable closed-loop on Sud start regardless of client
HeaterTask.shutdown() switched the heater to open-loop when a brew
ended, but nothing switched it back when a new Sud was started.  The
browser happened to send {ClosedLoop: true} as part of its UI setup,
so its connect-and-start path worked; PyQt (and any other client that
doesn't send that message) left the heater in open-loop and the TC
never drove it.

Add SudTask._on_start / set_on_start() hook, HeaterTask.start_closed_loop()
(mirror of shutdown()), and wire them in brewpi.py so the server
switches to closed-loop and broadcasts the new state to all clients the
moment any client starts a brew.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-01 00:43:55 +02:00
jensandClaude Sonnet 4.6 6d481d7764 Shut heater off on brew end (DONE) and stop (IDLE)
Adds HeaterTask.shutdown() which switches to open-loop at power 0,
disables TC, and broadcasts ClosedLoop=false to clients so the browser
checkbox unchecks immediately. SudTask fires it via a new set_on_end()
callback whenever state reaches DONE or IDLE, giving both a completed
schedule and a manual Stop the same safe behaviour: stirrer and heater
both off, no heater left running unattended.

Re-enabling after shutdown: check the closed-loop checkbox (sends
ClosedLoop=true → TC re-enabled) or adjust the power slider directly;
the next brew's Play press already sends ClosedLoop=true automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SH2D4LRuCnhLSzoYerAfJX
2026-06-28 12:07:21 +02:00
jensandClaude Sonnet 4.6 f55d085ae4 Add Closed-loop/Open-loop heater control mode
Closed-loop (default, checkbox checked): TC has exclusive control over
the heater; temp-soll and heatrate-soll sliders are active; direct
heater power entry is disabled. TC now stays enabled at server startup
and whenever closed-loop mode is active — SudTask no longer disables it
on IDLE/DONE, so adjusting temp-soll manually with no sud running
immediately drives the heater via the TC.

Open-loop (checkbox unchecked, only selectable when paused/stopped):
TC is disconnected from the heater; only the heater-power slider is
active. Switching back to closed-loop resets power_soll to 0 and
re-enables the TC.

On play, the mode is automatically reset to closed-loop.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SH2D4LRuCnhLSzoYerAfJX
2026-06-28 10:29:30 +02:00
jensandClaude Sonnet 4.6 0316cfd33b Remove server-side Activate/Enable residues from heater and tempctrl tasks
HeaterTask.on_changed_active() was never registered as a callback so
never fired; TcTask.recv() no longer needs to handle {Enable: ...}
since no client sends it after the override checkbox removal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DF16nV2ispNw1C9SbvqbRQ
2026-06-27 21:13:49 +02:00
jensandClaude Sonnet 4.6 47fb09aa06 Move set_on_changed registrations from on_process() to __init__()
Callbacks were registered inside the async on_process() coroutine,
meaning they weren't active until the event loop started ticking.
Moving them to __init__ ensures they're wired up at construction time.
Also removes remaining debug prints from the affected task files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tqxrk8uj4M3w3d3eXm3xK8
2026-06-25 20:39:06 +02:00
jens 93b5667a64 Add a real-time Plot tab to brewpi_gui, mirroring demo_sud figure 1
Embeds a dark-themed matplotlib canvas (3 stacked strip charts: theta
ist/soll, heatrate ist/soll, heater power_set/power_eff) in a new Plot
tab, sampled once per second from the latest websocket-received values.

HeaterTask now also emits a PowerSet message (the pre-discretization
target power) alongside the existing Power (effective) message, since
the GUI had no way to see the set-point side of figure 1's bottom plot
otherwise.
2026-06-20 22:31:07 +02:00
jens 9b997b8348 - generalized heaters 2021-10-18 14:32:56 +02:00
jens 6dc5e90956 - permit heater to override power 2021-10-12 11:37:24 +01:00
jens 33fd6fa5ab - fixed heater 2021-10-09 12:45:01 +02:00
jens ac6139cae7 - fixed heater 2021-10-09 11:40:29 +01:00
jens fb71f9554c - fixed heater 2021-10-09 12:35:39 +02:00
jens c50f02510c - fixed heater 2021-10-09 12:33:21 +02:00
jens 1e80b02216 - redefine pulse period 2020-12-18 17:33:26 +01:00
jens c8660ca60e - fixed hendi power 2020-12-18 17:03:17 +01:00
jens 4e508c86c5 - redefine activate method
- for task introduced open() conext method
2020-12-18 15:58:02 +01:00
jens adf664ca08 - create bool expression 2020-12-17 18:25:34 +01:00
jens 87cb265faf - reduce debug log
- wired stirrer to emit messages
2020-12-17 16:58:03 +01:00
jens fb37750ec7 - refactored tasks 2020-12-17 14:45:43 +01:00