jensandClaude Sonnet 4.6 1bf3929b60 Drop model_params from base, enable Smith predictor delay correction
TempControllerBase no longer threads model_params through (only the
Smith subclass needs it, for its own Pot model and Kalman filters).

Enable the Smith predictor's actual delay-compensated error term
(theta_err now uses theta_ist_plant - theta_ist_model_delay +
theta_ist_model instead of the plain plant reading), which is the
correction this controller is named for.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 21:06:35 +02:00
2021-10-13 18:35:58 +02:00
2020-11-24 20:42:27 +01:00
2022-06-30 18:31:05 +02:00
2021-10-19 11:42:52 +02:00
2020-12-17 16:28:50 +01:00
2021-08-10 15:05:57 +01:00
2021-10-12 09:20:30 +02:00
2021-10-18 19:15:11 +02:00
2021-10-18 18:08:41 +02:00
2021-10-19 06:32:45 +01:00

BrewPi

A Python-based controller for automating the mash/brewing process of beer: it holds a pot of liquid at target temperatures (or ramps it at a target heating rate) according to a configurable mash schedule, drives a heater and stirrer, and exposes live control/telemetry over a WebSocket so a desktop GUI (or any other client) can monitor and steer the brew.

The project began as a simulation/control-theory playground (Kalman filter + Smith-predictor temperature control, pot heat-diffusion model, see docs/NonLinMPC.pdf) and has grown real-hardware backends for an induction hob and an RTD temperature probe.

Architecture

brewpi/brewpi.py            Server entry point: wires sensor, pot/plant,
                             heater, temperature controller and stirrer
                             together, runs them as asyncio tasks, and
                             serves state/commands over a WebSocket.

client/brewpi_gui.py        PyQt5 desktop client (brewpi.ui) that connects
                             to the server's WebSocket, displays live
                             temperature/power/state, and lets the user set
                             target temperature, heat rate, stirrer speed,
                             and switch the heater/stirrer on or off.

components/                 Pluggable building blocks behind factories:
  pid/                         temperature controllers (PID, Smith
                                predictor + Kalman filter) and the math
                                model used for prediction
  plant/                       pot heat-diffusion model used in simulation
  sensor/                      temperature sensors: simulated, or a real
                                MAX31865 RTD amplifier over SPI
  actor/                       heater and stirrer drivers: simulated, a
                                Hendi induction hob (serial protocol), or a
                                Pololu 1376 stirrer motor controller

tasks/                       Async tasks (one per component) that poll
                             hardware/sim state at a fixed interval and
                             publish changes through the message dispatcher.

ws/                          Minimal WebSocket pub/sub layer: server
                             (single- and multi-user), client, and a
                             keyed message dispatcher (e.g. "Sensor",
                             "Heater", "TempCtrl", "Stirrer", "Pot").

tracer.py                    Logs traced variables to .mat files (for
                             offline analysis/tuning in MATLAB/Octave,
                             see results.m / results_tc.m).

sude/                        Mash schedules ("Sud" = brew/wort), each a
                             JSON list of temperature rests ("Rasten")
                             with target temperature, heat rate, and
                             optional pause for user confirmation.

config.json.templ            Configuration template (real hardware).
config.json.sim               Configuration template for simulation mode.

Data flow

The server (brewpi/brewpi.py) loads config.json, builds the configured sensor/heater/stirrer/controller via factories (*Factory.create(name, ...)) based on the Controller section (sensor_name, heater_name, stirrer_name, pid_type, or "sim" for any of them), and connects their outputs to each other's inputs via set_on_changed callbacks, e.g.:

  • sensor temperature → temperature controller's theta_ist
  • temperature controller output y → heater power
  • heater effective power → pot model power (simulation only)

Each component runs inside its own ATask at a configurable interval (Controller.dt, scaled by sim_warp_factor) and pushes state changes onto a keyed WebSocket channel that any connected client can subscribe to and send commands back on (e.g. {"TempCtrl": {"Soll": {"Temp": 65}}}).

Requirements

  • Python 3.8+
  • Server (brewpi/requirements.txt): numpy, scipy, websockets, dpath, and pyserial/spidev if using real hardware backends.
  • Client (client/requirements.txt): PyQt5 (and PyQt5.Qwt for plotting).

Install with:

pip install -r brewpi/requirements.txt
pip install -r client/requirements.txt

Running

  1. Copy a config template to config.json next to brewpi.py and adjust it. Use config.json.sim to run entirely in simulation (no hardware needed), or config.json.templ as a starting point for real hardware (set the heater/stirrer serial ports and sensor type).

  2. Start the server:

    cd brewpi
    ./brewpi.py
    

    This serves the WebSocket on ws://0.0.0.0:8765.

  3. Start the GUI client and connect to the server's URI:

    cd client
    ./brewpi_gui.py
    

brewpi/brewpi.sh shows how this is wired up to run under a virtualenvwrapper environment ($WORKON_HOME/$BREWPI_HOME) on a Raspberry Pi-style deployment.

Mash schedules

Files under sude/ describe a brew's mash schedule: pot weight, malt/water weights, stirrer speed/duty, and a list of temperature rests, each with a target temperature, heating rate, and whether to pause for user confirmation before continuing (e.g. to add malt or check gravity).

Logging & analysis

tracer.py (and tasks/tracer.py) periodically dump traced signals (temperatures, heat rates, heater power) to logs/*.mat files, which can be loaded in MATLAB/Octave — see results.m and results_tc.m — to evaluate and tune the controller.

S
Description
No description provided
Readme
14 MiB
Languages
Python 84%
JavaScript 9.4%
HTML 3.1%
CSS 2.4%
M 0.6%
Other 0.5%