- C 63.7%
- Python 13.6%
- C++ 7.9%
- TypeScript 4.6%
- JavaScript 4.1%
- Other 6.1%
|
|
||
|---|---|---|
| boil_controller | ||
| brewery_common | ||
| homeassistant | ||
| old | ||
| recipes | ||
| stand_alone_temp_probe | ||
| tilt_sensor | ||
| 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), homeassistant/ (operator dashboard,
brew phases and the fermenter dose controller), recipes/ (BeerXML exports),
tilt_sensor/ (BLE hydrometer — nRF52840, Arduino toolchain, in progress).
┌──────────────────────┐
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 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.
3. tilt_sensor/ — BLE hydrometer (in progress)
Seeed XIAO nRF52840 Sense. A homebrew Tilt clone: a sealed float in the fermenter that derives specific gravity from its inclination (LSM6DS3TR-C IMU) and BLE-broadcasts gravity plus temperature.
The odd one out in this repo — Arduino / arduino-cli, not ESP-IDF, and
BLE, not WiFi/MQTT, so it does not use brewery_common. Bridging its beacon
into MQTT/HA is a later job for the HA side. Right now it holds one bring-up
sketch, battery_test, for validating the cell and the BQ25101 charge path.
See tilt_sensor/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 OUT6) GPIO26 SSR — Boil (ULN OUT7) GPIO27 Spare ULN outputs (OUT3–5) GPIO32/33/25 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. The unit as built wires the SSRs to OUT6/OUT7 (GPIO26/27); any of DO3..DO7 would do. 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.