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>
3.8 KiB
components/pid design backlog
Findings from a design review, refreshed against the current state of
master after the Kalman-filter removal and Smith-predictor rewrite (see
git history for temp_controller.py/temp_controller_smith.py).
-
FSM thresholds aren't configurable. Moved into an optional
TempCtrl.Thresholdsconfig section (HoldIdle,HoldHeat,IdleHeat,IdleHold,HeatHold,HeatIdle), merged overDEFAULT_THRESHOLDS(now intemp_controller_base.py, formerlytc_constants.py) so existing configs without the section keep working unchanged. -
matplotlib imported at module level in production code.
temp_controller.py,temp_controller_smith.py, andkalman.pyused tofrom matplotlib.pyplot import ...just to support their__main__self-test plots. The plotting demos (andkalman_eval.py) moved toscripts/demos/pid/demo_*.py; production modules no longer import matplotlib. -
Three Kalman filters share one tuning. No longer applicable:
temp_controller_smith.pywas rewritten to drop Kalman filtering entirely (see below), so there's no shared tuning to split anymore. -
Pid.scale()is a gain-scheduling hack, not anti-windup.pid.py'sscale(k)multiplies every gain by1/heatrate_soll_set(called fromtemp_controller*.py'sprocess()), but it's framed as overshoot compensation, conflated with the real anti-windup logic a few lines below.self.kalso never resets inreset(), so a stale scale factor can survive a state-transition reset. Consider moving this scheduling logic out of the genericPidclass and into the temp controller, and resettingkinreset(). Still present. -
No automated tests.
tests/components/pid/was added once (stdlibunittest, no pytest) covering FSM transitions, anti-windup clamping, and Kalman convergence, but was removed again before the Kalman-filter removal/Smith rewrite, so none of the currenttemp_controller*.pybehavior (backward-difference + low-pass filtered heat rate, the two-model Smith correction) has test coverage. This drives a physical heater — worth re-adding. -
set_model_powerisn't defined on every controller, butbrewpi.pywires it unconditionally.brewpi.pyalways doesheater.set_on_changed("power_set", tc.set_model_power)regardless ofController.pid_type. Onlytemp_controller_smith.py(the Smith predictor) definesset_model_power;temp_controller.py("Normal") does not, so starting the server with"pid_type": "Normal"crashes at wiring time withAttributeError: 'TempController' object has no attribute 'set_model_power'. Either add a no-opset_model_powertoTempControllerBase, or only wire it when the configured controller actually exposes a model to feed. -
Config access is unchecked
dict[key]everywhere.params['Hold'],model_params['gain'], etc., throughout, with no schema validation at load time. We already hit this bug class once (config.json.sim'sgain/Modelnesting mismatch). A small schema/dataclass validation layer at config-load would surface errors immediately instead of mid-__init__— and would have caught the deadTempCtrl.Kalman/Model.kn/Plant.knkeys still sitting inconfig.json.templandconfig.json.sim(harmless today since extra keys are just ignored, but nothing reads them anymore after the Kalman/knremoval — seecomponents/plant/TODO.md). -
kalman.pyis now dead code in production. Neithertemp_controller.pynortemp_controller_smith.pyusesKalmananymore; the only remaining references arescripts/demos/pid/demo_kalman.pyanddemo_kalman_eval.py. Decide whether to keep it as a documented standalone filtering example or delete it along with the demos.