The unconditional p_loss/theta_amb/temp prints (left over from the
heat-loss-units fix) ran every tick, spamming stdout in both the
server and every demo script. Drop them and check off the matching
TODO.md item.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both TODO.md backlogs and the README's architecture section still
described the Kalman-filter/heat-diffusion design that's since been
replaced by the delay-line Pot model and Kalman-free Smith predictor.
Check off the items that rewrite already fixed (heat-loss units,
transport delay vs. single-pole lag, three-Kalman-tuning), note how
the kn/sensor-noise item was resolved differently than proposed, and
add newly-spotted issues: brewpi.py wiring set_model_power
unconditionally (breaks pid_type "Normal"), kalman.py being dead code
in production, stale Kalman/kn keys in the config templates, and
debug print()s left in Pot.process().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tc_constants.py only held States and DEFAULT_THRESHOLDS, both used
exclusively by temp_controller_base.py and its subclasses; fold them
into temp_controller_base.py directly and drop the now-empty module.
Also drop heat_diffusion.py, unused since pot.py switched to the
delay-line model, and the matching dead import in pot.py.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
[Sensor] - replace TempSensorSim's hardcoded k_noise with configurable
temp_offset/variance, accept **kwargs on Max31865 too so both sensors
share a constructor signature usable from TempSensorFactory.create()
[Temp Controller] - low-pass filter the backward-difference heat-rate
estimate (alpha=0.1) in both temp_controller.py and
temp_controller_smith.py instead of using the raw, noisy derivative
[Pot] - drop kn from demo_pot.py's params, matching the unused-field
removal already made to pot.py itself
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
[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>
temp_controller_smith.py still relied on Kalman filtering and Pot's old
get_temperature_intermediate(), both removed by the recent Pot/Kalman
simplification. Rebuild it using two Pot model copies (zero-delay and
delayed) and the same backward-difference heat rate as temp_controller.py,
combined into the classic Smith correction:
theta_ist = theta_model_fast + (theta_plant - theta_model_delay).
Also fix set_model_power() never being called, so the internal model
actually receives the controller's power output, and fill in
demo_temp_controller_smith.py to exercise it end-to-end with an extra
plot of plant vs. fast-model vs. delayed-model temperature.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
temp_controller.py, temp_controller_smith.py, and kalman.py imported
matplotlib at module level just to support eyeballed-plot __main__
blocks, coupling the live server's import graph to a GUI plotting lib
it never uses at runtime. Relocate those demos (and kalman_eval.py) to
scripts/demos/pid/ and strip the now-unused imports/__main__ blocks
from the production files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Review of pot.py found a likely root cause for sim-vs-real control
mismatches: the heat-loss term carries the wrong units, masking
ambient cooling in simulation. Also notes the dropped sensor-noise
term, hardcoded ambient temp, and lag-vs-dead-time modeling gap.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
THRESH_HOLD_IDLE/HOLD_HEAT/IDLE_HEAT/IDLE_HOLD/HEAT_HOLD/HEAT_IDLE in
tc_constants.py were hardcoded module-level constants shared by every
controller instance, so tuning the IDLE/HOLD/HEAT hysteresis required
a code change.
Replace them with DEFAULT_THRESHOLDS plus an optional
TempCtrl.Thresholds config section, merged at construction time in
TempControllerBase.__init__ so configs that omit the section keep
behaving exactly as before. Documented the new section in
config.json.templ; left config.json.sim without it to exercise the
default-fallback path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tracks open issues from a review that weren't fixed as part of this
branch's Smith-predictor and dedup work: non-configurable FSM
thresholds, Pid.scale()'s gain-scheduling hack, shared Kalman tuning
across the Smith controller's 3 filters, matplotlib imported at
module level in production code, no automated tests, and unchecked
config access.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
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>
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>
Both controllers had nearly identical process_fsm(), process_pid(),
and all getters/setters; only Kalman/model setup and process()
genuinely differed, and the duplication had already drifted (the
Smith variant resets model state on entering HEAT, the plain one
didn't).
Add TempControllerBase with the shared logic and three small hooks
(init_kalman, on_state_entered, post_pid) subclasses use to plug in
their own Kalman/model behavior. Each subclass now contains only what
makes it different.
Also fixes a latent crash: TempController's constructor only accepted
(dt, params), but PidFactory/brewpi.py always call it with a third
model_params arg, so pid_type "Normal" would have raised TypeError.
The shared base's model_params=None default fixes this. Also
initializes the Smith controller's trace attributes in __init__
instead of leaving them undefined until the first process() call.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ws/client/ws_client.py calls websockets.connect(uri, loop=self.loop),
which the current websockets release (16.0) no longer accepts. Pin to
the same version already used server-side. PyQt5.Qwt, also required
by client/brewpi_win.py, isn't pip-installable and must come from the
python3-pyqt5.qwt system package.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ws/message.py, ws/server/ws_server_multi_user.py: drop the loop= kwarg
and replace asyncio.wait(coroutines) with asyncio.gather(), both of
which were removed/forbidden in Python 3.10+.
- brewpi/requirements.txt: pin websockets==10.4, the latest version that
still supports this code's serve()/handler API.
- config.json.sim: move Model to the top level and add the missing gain
field so it matches the schema brewpi.py and config.json.templ expect.
- brewpi/brewpi.py: add -c/-m/-s/-d CLI args for selecting config/model
files, simulation mode, and debug.
- .gitignore: exclude __pycache__, logs, the local config.json, and
editor/venv directories.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>