Consolidate config.json.sim into config.json.templ

config.json.templ's component names already default to "sim" for every
backend (sensor/heater/stirrer/plant), making the separate .sim template
mostly redundant - it only differed in dt/sim_warp_factor/PID gain tuning,
which .templ now adopts directly. Removes config.json.sim, updates
brewpi.py's CLI args (-m/--logdir replaces the unused -d/--model/--sim
flags), and refreshes the README/TODO references that pointed at the now-
removed file.

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 21:27:58 +02:00
co-authored by Claude Sonnet 4.6
parent 1f146dbc0d
commit 4d98dacb49
6 changed files with 41 additions and 68 deletions
+20 -6
View File
@@ -91,8 +91,10 @@ sude/ Mash schedules ("Sud" = brew/wort), each a
per-step stirrer timing, and optional pause
for user confirmation.
config.json.templ Configuration template (real hardware).
config.json.sim Configuration template for simulation mode.
config.json.templ Configuration template - the "sim" component
names (sensor/heater/stirrer/plant) already
default to simulation; point Heater/Stirrer
at real serial ports to switch to hardware.
```
### Data flow
@@ -168,10 +170,11 @@ 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).
1. Copy `config.json.templ` to `config.json` next to `brewpi.py` - it
already runs entirely in simulation (no hardware needed) as-is; switch
any of the `sensor_name`/`heater_name`/`stirrer_name`/`plant_name`
`"sim"` values to a real backend, and set the corresponding serial
port, to use real hardware.
2. Start the server:
```bash
@@ -311,6 +314,17 @@ re-anchoring itself to match whatever's actually happening would no longer
be a meaningful baseline to compare reality against. It's computed once,
up front, and left alone.
`SudTask._send_forecast()` thins the curve to at most `MAX_FORECAST_POINTS`
(1000) before broadcasting it - a fine enough `dt` over a multi-hour brew
can otherwise produce a single `Forecast` message of several MB, large
enough to exceed the `websockets` library's default 1 MiB `max_size` and
get the connection closed outright (code 1009). `SudTask.forecast_t`/
`forecast_theta` themselves stay at full simulated resolution (used for
the exact-match truncation in `_continue_forecast_after_confirm()` below,
and for `SudLogTask`'s full-fidelity `logs/forecast_*.json` - see "Logging
& analysis") - only the copy actually sent to clients is thinned, which
the GUI's few-hundred-pixel-wide plot can't show the difference from anyway.
The one wrinkle is a step with `user_wait_for_continue`: a human's response
time genuinely can't be forecast. Rather than stall the whole estimate
there, `SudForecastEstimator.estimate()` models it as a zero-delay