Commit Graph
14 Commits
Author SHA1 Message Date
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 88357b31f6 Remove PyQt5.Qwt dependency from the GUI client
PyQt5.Qwt isn't pip-installable; it only existed via the apt package
python3-pyqt5.qwt, so pip-installing client/requirements.txt's plain
PyPI PyQt5 always crashed with "No module named 'PyQt5.Qwt'".

Qwt was only used for 3 QwtSlider widgets (Slider_temp_soll,
Slider_pwr_soll, Slider_speed_soll). Swap them for stock QSlider in
brewpi.ui, regenerate brewpi_win.py via pyuic5, and update
brewpi_gui.py's setLowerBound/setUpperBound calls to QSlider's
integer-only setMinimum/setMaximum. The GUI now runs from a plain
`pip install -r client/requirements.txt` venv with no system PyQt5
packages required.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 21:24:09 +02:00
jensandClaude Sonnet 4.6 df23840f6a Restructure into brewpi/client/ws packages and add README
Splits the server, GUI client, and websocket layer into their own
packages with dedicated requirements.txt files, and adds a README
documenting the project's architecture and usage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 20:05:08 +02:00