Add a browser client (web/) alongside the desktop GUI
A new HTML/CSS/JS client, added next to client/brewpi_gui.py rather than replacing it, speaking the exact same WebSocket pub/sub protocol - no server-side protocol changes needed. server/brewpi.py gains a --http-port (default 8080) stdlib http.server.ThreadingHTTPServer, in its own daemon thread and deliberately decoupled from the existing asyncio WebSocket server, serving web/ statically. v1 covers the Manual tab (direct heater/stirrer/controller control) and the new Progress tab - the two most actionable surfaces, neither needing a charting library. web/app.js ports the relevant logic from brewpi_gui.py directly: components/sud.py's _build_step()/ _merge_defaults() for resolving the raw schedule doc, and the StepPlate/_update_step_plates()/update_status_step_label() logic behind the Progress tab and status line. Deliberately deferred rather than stubbed (see web/TODO.md for the full parity backlog against the Qt GUI): Sud control actions (Start/ Pause/Stop/Confirm), the Automatic tab's forecast plot and the Plot tab's live strip charts, Sud file management, and auth (matching the WebSocket server's own existing lack of it). No new Python dependencies - functools/threading/http.server are all stdlib. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019qvu5giu7gvRCyEWzf2Vpx
This commit is contained in:
@@ -98,6 +98,14 @@ config.json.templ Configuration template - the "sim" component
|
||||
simulation; point Stirrer/Heater at real
|
||||
serial ports and plant_name at a real
|
||||
backend to switch to hardware.
|
||||
|
||||
web/ Browser client - static HTML/CSS/JS (no build
|
||||
step, no dependencies), speaking the exact
|
||||
same WebSocket protocol as client/brewpi_gui.py
|
||||
(see "Browser client" below). Served by
|
||||
server/brewpi.py itself over plain HTTP, so a
|
||||
browser anywhere on the network can reach the
|
||||
rig with nothing installed beyond the browser.
|
||||
```
|
||||
|
||||
### Data flow
|
||||
@@ -165,7 +173,9 @@ no-op rather than an empty dialog.
|
||||
- Server (`server/requirements.txt`): `numpy`, `scipy`, `matplotlib` (only
|
||||
for `scripts/demos/*`, not the running server itself), `websockets`,
|
||||
`dpath`, and `pyserial`/`spidev` if using real hardware backends.
|
||||
- Client (`client/requirements.txt`): `PyQt5`.
|
||||
- Desktop client (`client/requirements.txt`): `PyQt5`.
|
||||
- Browser client (`web/`): nothing - just a browser. Served by
|
||||
`server/brewpi.py` itself.
|
||||
|
||||
Install with:
|
||||
|
||||
@@ -190,23 +200,28 @@ pip install -r client/requirements.txt
|
||||
./brewpi.py
|
||||
```
|
||||
|
||||
This serves the WebSocket on `ws://0.0.0.0:8765`, ticking in real time
|
||||
(1 simulated second per tick, no speedup) by default. `--dt` (simulated
|
||||
seconds/tick) and `--sim-warp-factor` (how many of those fit into one
|
||||
real second) are run-mode knobs, not `config.json` material - a
|
||||
plant/hardware description shouldn't change just because of how a
|
||||
This serves the WebSocket on `ws://0.0.0.0:8765` and the browser client
|
||||
(see "Browser client" below) on `http://0.0.0.0:8080`, ticking in real
|
||||
time (1 simulated second per tick, no speedup) by default. `--dt`
|
||||
(simulated seconds/tick) and `--sim-warp-factor` (how many of those fit
|
||||
into one real second) are run-mode knobs, not `config.json` material -
|
||||
a plant/hardware description shouldn't change just because of how a
|
||||
particular run happens to be invoked - so they're CLI-only:
|
||||
|
||||
```bash
|
||||
./brewpi.py --sim-warp-factor 50 # 50x speedup, e.g. for dev/testing
|
||||
./brewpi.py --http-port 8888 # change the browser client's port
|
||||
```
|
||||
3. Start the GUI client and connect to the server's URI:
|
||||
3. Either connect with the desktop GUI:
|
||||
|
||||
```bash
|
||||
cd client
|
||||
./brewpi_gui.py
|
||||
```
|
||||
|
||||
or open `http://<server-host>:8080/` in any browser (same machine or
|
||||
anywhere else on the network) for the browser client.
|
||||
|
||||
`server/brewpi.sh` shows how this is wired up to run under a `virtualenvwrapper`
|
||||
environment (`$WORKON_HOME`/`$BREWPI_HOME`) on a Raspberry Pi-style deployment.
|
||||
|
||||
@@ -502,6 +517,40 @@ one, since energy is banked per step rather than accumulated as a grand
|
||||
total - summed client-side instead, from every finished step's own Wh
|
||||
total plus whatever the active one has used so far).
|
||||
|
||||
### Browser client
|
||||
|
||||
`web/` is a second, independent client - plain HTML/CSS/JS, no build step,
|
||||
no dependencies - for the same server, added so the rig is reachable from
|
||||
any browser on the network rather than only from a machine with the PyQt5
|
||||
desktop app installed. It speaks the exact same WebSocket pub/sub protocol
|
||||
`client/brewpi_gui.py` does (same subscribe-on-connect handshake, same
|
||||
message shapes on every channel), so nothing about the protocol or
|
||||
`server/brewpi.py`'s data flow needed to change for it to exist - only a
|
||||
plain static-file HTTP server (`http.server.ThreadingHTTPServer`, stdlib,
|
||||
in its own daemon thread, `--http-port`, default `8080`) needed adding,
|
||||
deliberately independent of the existing `websockets`-based asyncio server
|
||||
so neither can affect the other's behavior or availability.
|
||||
|
||||
v1 covers only the Manual tab (direct heater/stirrer/controller control)
|
||||
and the Progress tab (above) - the two most actionable surfaces, and
|
||||
neither needs a charting library. `web/app.js` ports the relevant logic
|
||||
from `client/brewpi_gui.py` directly: `components/sud.py`'s
|
||||
`_build_step()`/`_merge_defaults()` (the raw doc from `Sud.Json` is
|
||||
unresolved - every step still needs `default.step` merged in), and the
|
||||
`StepPlate`/`_update_step_plates()`/`update_status_step_label()` logic
|
||||
behind the Progress tab and status line. Deliberately deferred rather than
|
||||
stubbed: the Automatic tab's forecast-vs-actual plot and the live Plot
|
||||
tab's strip charts (both need a charting approach - revisit once Manual +
|
||||
Progress are validated), and Sud file management (New/Load/Save dialogs -
|
||||
v1 only *displays* whatever schedule the server already has loaded, fetched
|
||||
via the same `{"Sud": {"Save": true}}` request `Window.connect()` sends).
|
||||
|
||||
No authentication - matching the existing WebSocket server's own complete
|
||||
lack of it, not a new gap. Worth keeping in mind regardless: "browser,
|
||||
reachable from anywhere on the network" is a meaningfully wider exposure
|
||||
than "desktop app, reachable from wherever its process happens to be
|
||||
running" if this is ever reachable off a trusted LAN.
|
||||
|
||||
## Logging & analysis
|
||||
|
||||
`tasks/sud_log.py`'s `SudLogTask` records every Sud run's measured data -
|
||||
|
||||
Reference in New Issue
Block a user