Keep plant/temp control inert until a Sud is actually loaded

server/brewpi.py no longer pre-configures the real Pot's or Smith's model's
plant params at startup - there's no longer any generic baseline at all,
since the only source of truth is now a loaded Sud's own doc (applied via
tasks/sud.py's SudTask.apply_plant_params(), on Load and on every step).
Ambient temperature and PID gains stay configured at startup, since
they're independent of any Sud (global setting / hardware tuning, not
doc-derived).

Add Pot.is_configured() (already existed)/TempControllerBase.is_configured()/
TempController(Smith).is_configured(), and have tasks/pot.py's PotTask and
tasks/tempctrl.py's TcTask skip process() while not yet configured instead
of letting it raise - so plant and temp control are genuinely inert (not
crashing) until a Sud is loaded. "Normal" has no plant-model dependency,
so it stays active regardless.

Also refreshes README.md: removes stale tracer.py/.mat references (already
removed in an earlier commit), documents SudLogTask's JSON logs, the doc's
L/Td fields, and this inert-until-loaded behavior.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DkkuG48uHFCGKe6dPSERFk
This commit is contained in:
2026-06-22 20:05:33 +02:00
co-authored by Claude Sonnet 4.6
parent 51add6fd56
commit 77e68afef1
6 changed files with 84 additions and 38 deletions
+15 -15
View File
@@ -62,24 +62,23 @@ if __name__ == '__main__':
plant_sim = "sim" in config['Controller']['plant_name']
# Mash schedule - starts out empty; a client loads one of sude/*.json's
# several schedules onto it later (see components/sud.py's Sud). Also
# doubles as the source of baseline plant params for the Plant/
# Temperature Controller below, before any real schedule is loaded -
# derive_plant_params() falls back to Sud's own (generic) defaults
# while unloaded (see components/sud.py's EMPTY_SUD); water_mass=25
# is just a placeholder thermal mass standing in for "some water in
# the pot," not a literal recipe.
# several schedules onto it later (see components/sud.py's Sud).
sud = Sud()
baseline_plant_params = sud.derive_plant_params(0, 25)
# Sensor
sensor = TempSensorFactory.create(config['Controller']['sensor_name'], temp_offset=-0.15, variance=0.01)
sensor_task = TempSensorTask(sensor, DT_TASK, dispatcher.msgio_get("Sensor"))
taskmgr.add(sensor_task)
# Plant
# Plant - deliberately left without plant params (M/C/L/Td) here: a
# Sud's own doc is the only source for those now (see
# tasks/sud.py's SudTask.apply_plant_params(), called immediately on
# Load), so the plant stays inert (Pot.is_configured() is False,
# PotTask skips process() - see there) until one actually is. Ambient
# is independent of any Sud (a global setting, changeable live via
# the System channel - see on_system_recv() below), so it's set
# right away regardless.
pot = Pot(DT)
pot.set_plant_params(baseline_plant_params)
pot.set_ambient_temperature(theta_amb)
taskmgr.add(PotTask(pot, DT_TASK, dispatcher.msgio_get("Pot")))
@@ -89,13 +88,14 @@ if __name__ == '__main__':
heater_task = HeaterTask(heater, DT_TASK, dispatcher.msgio_get("Heater"))
taskmgr.add(heater_task)
# Temperature Controller
# Temperature Controller - PID gains are server/hardware-level
# config, independent of any Sud, so they're set right away; "Normal"
# has no internal model/ambient at all (see temp_controller.py vs.
# temp_controller_smith.py.), and Smith's model plant params are -
# like the real Pot's above - deliberately left unset here, only
# ever coming from a Sud's own doc.
tc = PidFactory.create(config['Controller']['pid_type'], DT)
tc.set_params(config['TempCtrl'])
# "Normal" has no internal model/ambient - see temp_controller.py vs.
# temp_controller_smith.py.
if hasattr(tc, 'set_model_plant_params'):
tc.set_model_plant_params(baseline_plant_params)
if hasattr(tc, 'set_ambient_temperature'):
tc.set_ambient_temperature(theta_amb)
tc_task = TcTask(tc, DT_TASK, dispatcher.msgio_get("TempCtrl"))