17 Commits
Author SHA1 Message Date
jensandClaude Sonnet 4.6 dd6193fa46 Remove manual tab override/enable checkboxes from browser and PyQt clients
Drops the tc-enable, heater-activate and stirrer-activate checkboxes
and all associated state, signal connections, initial-sync flags, and
channel-handler logic. Regenerates main_window.py from the updated .ui.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DF16nV2ispNw1C9SbvqbRQ
2026-06-27 20:37:14 +02:00
jens a8ae6f2a65 GUI: rename Pot reset button to "Set" and move it next to its spinbox
Now that doubleSpinBox_pot_temp carries the target temperature, the
old "Pot reset to ambient temperature" label no longer described what
the button does and reserved far more width than a short label needs.
Shortened to "Set" and repositioned immediately to the right of the
Pot [°C] label/spinbox it applies, with both shifted left to fill the
space the long label used to need.
2026-06-23 19:37:33 +02:00
jens f035e1decd GUI: add a spinbox to pre-dial the simulated Pot's reset temperature
btn_pot_reset always reset the simulated Pot to the ambient
temperature. Add doubleSpinBox_pot_temp next to it (shown/hidden
together, same as the button) so the user can dial in a different
starting temperature before committing it - it seeds from the same
remembered ambient value on startup but is otherwise independent and
not persisted.

tasks/pot.py's PotTask.recv() now resets the plant to whatever
temperature the 'Reset' message carries, falling back to ambient for
the bare True a caller might still send.
2026-06-23 19:34:33 +02:00
jens deb370257d GUI: widen ambient-temp spinbox range and persist it client-side
doubleSpinBox_ambient now allows -999..999 in whole degrees (was
0..50 with 1 decimal), and main_window.py is regenerated to match.

The ambient temperature is also now a properly client-owned setting:
it's written to the user config on shutdown (not on every spinbox
tick), restored into the spinbox immediately on GUI start, resent to
the server on every (re)connect using the spinbox's live value, and
no longer reset to the spinbox minimum on disconnect.
2026-06-23 19:11:02 +02:00
jensandClaude Sonnet 4.6 8726b0a62d GUI: use a spinbox for ambient temperature instead of a text entry
Replaces lineEdit_ambient (QLineEdit) with doubleSpinBox_ambient
(QDoubleSpinBox, 0-50 degC, 0.5 deg steps) in brewpi.ui, regenerated
main_window.py via pyuic5 (same generator version, verified minimal diff).

brewpi_gui.py wires valueChanged instead of returnPressed - no more
manual float()/ValueError parsing of typed text, the signal already
hands over a valid float - with blockSignals guards around server-driven
updates (mirroring the existing doubleSpinBox_heatrate_soll pattern) so
applying a server echo doesn't immediately re-send the same value back.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DkkuG48uHFCGKe6dPSERFk
2026-06-22 22:52:36 +02:00
jens 3fea29cc58 Add an enable/disable switch for the temperature controller
New TempControllerBase.enabled (default False) forces y=0 in
process_pid() when off, same mechanism as the existing cooling
override - the controller tries not to drive the heater at all.

tasks/tempctrl.py: new 'Enable' recv command and 'Enabled' broadcast
on the TempCtrl channel. tasks/sud.py: SudTask now enables the
controller on any non-IDLE/DONE Sud state and disables it (forcing
power back to 0) on IDLE/DONE, so automatic mode owns it for the
duration of a run and hands back manual control once it stops/finishes.

gui: new "Enabled" checkbox on the Manual tab's Controller group,
synced from the server; the temp/heatrate setpoint controls are
disabled whenever the controller itself is disabled.
2026-06-21 12:54:09 +02:00
jens 19be2a7670 Add a "Pot reset to ambient temperature" button, sim-only
New btn_pot_reset next to the ambient entry, sends {"Pot": {"Reset":
true}}; tasks/pot.py's PotTask.recv() (previously a no-op) now resets
the plant to its current ambient temperature (Pot.initial()) on that
command.

The button only appears when the server reports its Pot is simulated
(new "PlantSim" field on the System channel, derived from
config.json's previously-unused Controller.plant_name) - resetting a
simulated plant's temperature is meaningless for a real one.
2026-06-21 12:15:35 +02:00
jens 40cf4b69cc Add a GUI text entry to set the ambient temperature live
New lineEdit_ambient next to the host/connect row - type a value and
press Enter to send {"System": {"AmbientTemp": ...}}. The server now
has a recv handler for the System channel (previously send-only):
updates the real Pot's ambient temperature and, where the controller
has an internal model (Smith), its model Pots too (new
set_ambient_temperature() on TempControllerSmith), then echoes the new
value back so the status bar label and entry itself stay in sync.
2026-06-21 11:53:45 +02:00
jens c659fcee37 gui: add "New Sud" menu action, disable Start/Pause/Stop for an empty sud
File > New Sud loads an empty schedule (zero steps) onto the server,
same mechanism as Load but with a built-in empty document. Tracks
whether the loaded schedule actually has steps (sud_empty) separately
from whether a Sud is configured at all (sud_loaded) - Start/Pause/Stop
now require both, and the Automatic tab's forecast shows "No sud
loaded" instead of an empty plot while sud_empty.
2026-06-21 10:01:26 +02:00
jens 13e507e2b5 Rename Sud's Download/Upload to Save/Load throughout
Renames everywhere the concept appears: Sud.download()/upload() ->
save()/load(), the 'Download'/'Upload' websocket messages ->
'Save'/'Load', the brewpi_gui menu actions, handlers and
sud_download_path -> sud_save_path, and the demo script. Behavior is
unchanged - this is naming only, from the client's perspective (save
to / load from a local file) rather than the server's.
2026-06-20 23:58:21 +02:00
jens 9c3ec1dfdf Add a Connect button next to the host field; unwire it from Start
Start/Pause/Stop on the toolbar were never about the websocket
connection - Start now does nothing until that's wired to its own
purpose, and connecting is its own explicit action next to the host
text entry.
2026-06-20 23:01:18 +02:00
jens 62dcd6b541 Default the GUI's websocket URI to localhost instead of brewpi 2026-06-20 22:56:54 +02:00
jens 3289288488 Pre-visualize the estimated Sud course in the Automatic tab
Adds a static forecast plot to the (previously empty) Automatic tab,
showing the planned temperature course derived from a schedule's
declared ramp rates and hold durations alone (no plant/controller
model - just how long the schedule itself says each step takes).

The client now requests the schedule via Download right after
connecting, routing the reply to the forecast instead of a save
dialog since sud_download_path is only set for the user-initiated
download. SudTask also echoes the just-applied document back after a
successful Upload, so editing the schedule refreshes the forecast
without an extra round trip.
2026-06-20 22:54:34 +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 bb94e065f4 Wire Sud upload/download into the brewpi_gui client
Adds File menu actions to save the running Sud's schedule to a local
sud.json and to replace it from one, via the Sud websocket channel's
new Download/Upload messages. File dialogs are opened up front on the
GUI thread; the actual read/write happens off the websocket recv
callback, which runs on a worker thread and must not touch Qt itself.

main_window.py is regenerated from brewpi.ui via pyuic5 5.15.11, which
also picks up an unrelated pre-existing drift (the default URI had
fallen out of sync with the .ui source).
2026-06-20 22:18:49 +02:00
jensandClaude Sonnet 4.6 d02b7cbe72 Clean up after Smith predictor rewrite and drop unused/stale config
[brewpi] - drop trace vars for the dtheta_ist_* attributes removed
when temp_controller_smith.py dropped Kalman filtering
[Pot] - drop unused kn field (never read since the noise-injection
code that used it was dropped)
[GUI] - default WS connection to ws://localhost:8765

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 15:09:36 +02:00
jensandClaude Sonnet 4.6 44372364c4 Rename brewpi_win.py to main_window.py
Pure rename of the pyuic5-generated UI module plus its one import
site in brewpi_gui.py; regenerated from brewpi.ui, no content changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 21:28:22 +02:00