- C 77.3%
- TypeScript 7.2%
- JavaScript 6.3%
- Python 4.3%
- Shell 2.4%
- Other 2.5%
Add per-pump input_select (brewery_hlt/mlt_pump_relay) listing "none" + every available switch, seeded from the current set and refreshed every 30 min by a brewery automation (input_select.set_options). Mirror automations command the selected switch from each pump's input_boolean; reassigning releases the old switch and syncs the new one to the current pump state. Dashboard gains a "Pump relays" card on Setup & Tuning. Scope: only brewery_* entities/automations are added in the brewery package and dashboard. Other systems' switches are merely listed as options and commanded — never reconfigured. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015TZvMeBZ55diAmoDiJRvfg |
||
|---|---|---|
| boil_controller | ||
| brewery_common | ||
| homeassistant | ||
| old | ||
| stand_alone_temp_probe | ||
| tools | ||
| .gitignore | ||
| CLAUDE.md | ||
| README.md | ||
Brewery control system
Monorepo of firmware and hardware for an automated HERMS brewery, built around a small fleet of networked temperature probes feeding a central heating controller — all coordinated over MQTT (with Home Assistant discovery, so the whole rig shows up in HA automatically).
Layout: stand_alone_temp_probe/ (RTD probe firmware), boil_controller/
(HERMS/boil controller firmware), brewery_common/ (shared ESP-IDF component:
OTA, firmware version-check, network log tap — used by both firmwares via a
component-manager path dependency), old/ (reference designs + the original
KiCad schematic), tools/ (build helper).
┌──────────────────────┐
HLT ───▶│ temp probe (RTD) │──┐
mash ───▶│ temp probe (RTD) │──┤ mechination/<id>/temperature
boil ───▶│ temp probe (RTD) │──┤ (WiFi, retained, >=1 Hz)
… ───▶│ temp probe (RTD) │──┤
└──────────────────────┘ │
▼
┌─────────────────┐
│ MQTT broker │ (+ Home Assistant)
└─────────────────┘
│ subscribes to the probe temps
▼
┌────────────────────────────┐
│ boil / HERMS controller │ ESP32-WROVER
│ PID ──▶ ULN2003A ──▶ SSRs │
└────────────────────────────┘
│ │
HLT element Boil-kettle
(heats HERMS) element
The two firmwares we host here
1. stand_alone_temp_probe/ — temperature probe
Seeed XIAO ESP32-C6 + Adafruit MAX31865 RTD amplifier. Reads a PT100/PT1000
RTD, joins WiFi, and publishes its temperature to MQTT (retained, ≥ 1 Hz)
with Home Assistant discovery and RTD-fault reporting. One probe per measured
point — give each a distinct device id (hlt, herms_out, boil_kettle, …)
so they share the MQTT tree without colliding.
Note: the firmware is WiFi + MQTT (see
main/temp_probe.h,idf_component.yml). The probe's ownREADME.mdstill describes an earlier Zigbee revision and is being updated — trust the WiFi/MQTT build.
2. boil_controller/ — boil / HERMS controller
ESP32-WROVER + ULN2003A + 2× mains SSR. Subscribes to the probes' MQTT temperatures, runs a PID loop per heated vessel, and drives the SSRs with time-proportional output:
- HERMS channel — modulates the HLT element to hold the mash temperature (wort recirculating out of the HERMS coil), with an HLT over-temp cutout.
- Boil channel — drives the boil-kettle element to a setpoint.
The first two ULN2003A channels drive the SSRs; the other five are broken out
for future use (pumps, alarm, …). It supports OTA updates over MQTT so we
can iterate without touching the hardware. See boil_controller/README.md.
Temperature sensors
Each is an independent standalone probe publishing to MQTT. Planned points:
| Probe device id | Measures | Used by the controller for |
|---|---|---|
hlt |
Hot Liquor Tank | HERMS over-temp cutout |
herms_out |
MLT output / mash temp off the HERMS coil | HERMS PID process variable |
boil_kettle |
Boil kettle | Boil PID process variable |
| (more) | e.g. mash-in, ambient | future channels / logging |
Topic convention (shared prefix): mechination/<device_id>/temperature, with
availability at mechination/<device_id>/status and a per-reading
…/temperature/status that goes offline on an RTD fault (so the controller
can fail-safe).
old/ — previous designs (reference only)
The earlier brewery was Bluetooth-based and is superseded by the WiFi/MQTT design above. Kept for reference:
old/brewery-circuit/— the original controller schematic + PCB (Brewery.kicad_pcb, KiCad/2019): ESP32-WROVER + ULN2003A + LTC2986. This is where the boil-controller pinout came from.old/ssr/— BLE-central SSR firmware (an ESP-IDF BLE example, not the real app)old/hw/SSR/— single-channel SSR PCB (PN2222A driver + opto) — still useful HWold/hw/Temp_probe/— temp-probe PCBold/temp_sensor/— MicroPython MAX31865 driverold/zephyr_temp/— Zephyr RTOS temperature appold/web/— the old Web-Bluetooth brewery dashboard
The old boil-controller firmware was not recovered (nothing referencing the LTC2986 exists under
~/dev, and the old system was Bluetooth-based), soboil_controller/is a clean rebuild. The hardware schematic survives inold/brewery-circuit/, and the controller pinout is taken from it:
Function GPIO SSR — HERMS/HLT (ULN OUT3) GPIO32 SSR — Boil (ULN OUT4) GPIO33 Spare ULN outputs (OUT5–7) GPIO25/26/27 LTC2986 SPI (unused) MOSI 23, MISO 19, SCLK 18, CS 5, DRDY 4 ⚠️ The board's first two ULN channels (DO1/DO2) land on GPIO34/35, which are input-only — they can't drive outputs, so the SSRs use the first output-capable channels (DO3/DO4 → OUT3/OUT4). The LTC2986 is dropped from the design (temps come over MQTT) but is held quiescent in firmware since it's still populated on the board. Details in
boil_controller/README.md.
Building
Both firmwares are independent ESP-IDF projects (ESP-IDF ≥ 5.3; tested with
the installed ~/esp/esp-idf). Build each from its own directory:
. ~/esp/esp-idf/export.sh
# Temperature probe (XIAO ESP32-C6)
cd stand_alone_temp_probe
idf.py set-target esp32c6
idf.py menuconfig # WiFi, MQTT, device id, RTD type/pins
idf.py -p <PORT> flash monitor
# Boil controller (ESP32-WROVER)
cd ../boil_controller
idf.py set-target esp32
idf.py menuconfig # WiFi, MQTT, sensor topics, ULN GPIOs, PID gains
idf.py -p <PORT> flash monitor
The two boards target different chips (esp32c6 vs esp32), so keep their
build trees separate (each has its own sdkconfig). A convenience script is at
tools/build.sh:
./tools/build.sh both # build both
./tools/build.sh probe # just the temp probe
./tools/build.sh boil flash # build + flash the controller (auto-detects port)
After the controller's first USB flash, subsequent updates can go over the
air — see boil_controller/README.md.