Firmware for an ESP32-based controller that manages two independent 3D printer enclosures. It provides local web control for enclosure lights, PWM fans, DS18B20 temperature sensors, automatic fan behavior, and direct Tasmota smart plug control without Home Assistant.
Current firmware version: 1.4.1
The controller is designed as a standalone local appliance. The ESP32 connects to WiFi, hosts its own web UI, stores configuration in ESP32 Preferences/NVS, and talks directly to each configured Tasmota plug over HTTP.
Each enclosure has its own state:
- Friendly name.
- LED relay state.
- Fan speed percentage.
- Temperature and sensor-valid flag.
- Tasmota plug IP address.
- Manual shutdown permission.
- Controller idle auto-shutdown permission.
- Idle power threshold and delay.
- Automatic fan settings.
- Last plug command/status message.
The two enclosures share one ESP32 but remain separately configurable.
| Function | GPIO | Notes |
|---|---|---|
| Enclosure 1 LED relay | 16 | Relay output |
| Enclosure 2 LED relay | 17 | Relay output |
| Enclosure 1 fan PWM | 25 | MOSFET low-side PWM |
| Enclosure 2 fan PWM | 26 | MOSFET low-side PWM |
| Enclosure 1 DS18B20 | 32 | 4.7k pullup to 3.3V |
| Enclosure 2 DS18B20 | 33 | 4.7k pullup to 3.3V |
| Status LED | 23 | Boot/WiFi/status indication |
Fans are driven through low-side IRL540N MOSFETs.
DS18B20 wiring:
DS18B20 VCC -> 3.3V
DS18B20 GND -> GND
DS18B20 DATA -> GPIO32 or GPIO33
4.7k resistor from DATA to 3.3V
Fan MOSFET wiring:
12V+ -------------- Fan +
Fan - ------------- IRL540N Drain
IRL540N Source ---- GND
ESP32 GPIO -------- 100R to 220R resistor ---- IRL540N Gate
Gate -------------- 10k pulldown ---- GND
ESP32 GND --------- 12V supply GND
- WiFi setup using WiFiManager captive portal.
- Local ESP32-hosted web UI.
- Two independent enclosure control panels.
- Per-enclosure friendly names.
- Manual LED relay ON/OFF.
- Manual fan speed sliders from 0 to 100%.
- DS18B20 temperature display for each enclosure.
- Automatic fan mode with configurable ON/OFF temperature thresholds.
- Filament presets for common materials.
- Direct Tasmota plug ON/OFF control over HTTP.
- Controller-side idle auto-shutdown based on Tasmota power telemetry.
- Web UI feedback for setup save, light ON/OFF, and plug ON/OFF commands.
- Optional MQTT status publishing and command control.
- Optional Home Assistant MQTT discovery with rediscovery support.
- WiFi SSID/IP display.
- Web UI action to clear WiFi settings and restart setup mode.
- JSON status endpoint for integration or debugging.
- Status LED modes for boot, WiFi setup, heartbeat, and error states.
Open the controller in a browser at:
http://<esp32-ip>/
Each enclosure card shows:
- Current temperature.
- Light ON/OFF buttons with a visible light-state symbol and command feedback.
- Fan speed slider.
- Automatic fan mode status.
- Selected filament.
- Plug online/offline state.
- Plug power state.
- Current plug watts from Tasmota
Status 8. - Controller auto-shutdown status.
- Idle timer progress.
- Plug ON/OFF controls.
- Last action or error message.
The setup section allows editing:
- Enclosure friendly name.
- Tasmota plug IP.
- Manual shutdown enable checkbox.
- Controller idle auto-shutdown enable checkbox.
- Idle power threshold in watts.
- Idle delay in seconds.
- Automatic fan enable checkbox.
- Filament preset.
- Automatic fan ON temperature.
- Automatic fan OFF temperature.
- Automatic fan speed.
The Save button shows in-page feedback for unsaved changes, saving, success, and failure. Light and plug buttons temporarily disable and show command progress while HTTP requests are running.
MQTT is optional. The controller continues to work locally when MQTT or Home Assistant is unavailable.
MQTT settings in the web UI:
- Enable MQTT.
- Broker host/IP.
- Broker port, default
1883. - Username and password.
- Base topic, default
enclosure-controller. - Home Assistant discovery enable checkbox.
- Home Assistant discovery prefix, default
homeassistant.
MQTT publishes:
<base-topic>/availability
<base-topic>/status
<base-topic>/enclosure1/state/light
<base-topic>/enclosure1/state/fan
<base-topic>/enclosure1/state/temperature
<base-topic>/enclosure1/state/plug_power
<base-topic>/enclosure1/state/plug_state
The same enclosure2 state topics are published for the second enclosure.
MQTT commands:
<base-topic>/enclosure1/cmd/light ON/OFF
<base-topic>/enclosure1/cmd/fan 0-100
<base-topic>/enclosure1/cmd/plug on/off
<base-topic>/cmd/discovery any payload republishes discovery
Home Assistant MQTT discovery is published on MQTT connect when enabled. The web UI also has a Republish Home Assistant Discovery button for recovery after Home Assistant restarts or entity cleanup.
Each enclosure can use a separate Tasmota smart plug. Configure the plug IP address in the web UI.
Manual plug control uses:
http://<plug-ip>/cm?cmnd=Power%20On
http://<plug-ip>/cm?cmnd=Power%20Off
Manual Plug OFF requires the enclosure's Enable shutdown checkbox. When a plug OFF command succeeds, the controller also turns off that enclosure's fan and LED light. Fan and light can still be manually turned back on afterward.
Idle shutdown is handled by the ESP32 controller, not by Tasmota rules.
The controller polls each configured plug periodically using:
http://<plug-ip>/cm?cmnd=Status%208
It reads:
StatusSNS.ENERGY.Power
If plug power stays at or below the configured threshold for the configured delay, the ESP32 sends Power Off to the plug and turns off that enclosure's fan and light.
Auto-shutdown requires both safety controls to be enabled:
Enable shutdownEnable controller idle auto shutdown
Defaults:
| Setting | Default |
|---|---|
| Idle power threshold | 12 W |
| Idle delay | 900 seconds |
These values are editable per enclosure and saved in NVS.
Each enclosure can run its fan automatically from temperature:
- Fan turns on when temperature is at or above the configured ON temperature.
- Fan turns off when temperature is at or below the configured OFF temperature.
- Automatic fan speed is configurable as a percentage.
- Manual fan slider disables automatic fan mode for that enclosure.
Filament presets prefill typical fan settings for:
- PLA
- PETG
- TPU
- ABS
- ASA
- NYLON
- CUSTOM
On first boot, WiFiManager starts this setup access point:
EnclosureControllerSetup
Join that network, configure WiFi, then use the serial monitor or router DHCP list to find the ESP32 address.
Hostname:
enclosure-controller
The web UI also includes a Reset WiFi Settings button. It clears saved WiFi credentials and restarts the controller into setup mode.
The firmware uses a status LED on GPIO 23.
Status modes include:
- Fast boot indication.
- WiFiManager setup/captive portal indication.
- Normal heartbeat after WiFi connects.
- Error indication if WiFiManager fails.
Enclosure numbers are one-based: enc=1 or enc=2.
GET /
GET /status
GET /set?enc=1&light=1
GET /set?enc=1&light=0
GET /set?enc=1&fan=50
POST /config
GET /plug?enc=1&power=on
GET /plug?enc=1&power=off
POST /wifi-reset
POST /mqtt-discovery
The /status endpoint returns WiFi state plus an enclosures array containing light, fan, temperature, plug, idle timer, automatic fan, and last-message fields.
/status also includes MQTT configuration and connection status for the web UI.
Power On
Power Off
Status 8
No Tasmota rules or Mem variables are required for idle shutdown in the current firmware.
src/
main.cpp
fans.cpp
relays.cpp
sensors.cpp
storage.cpp
tasmota.cpp
web_ui.cpp
led_status.cpp
include/
config.h
enclosure_state.h
fans.h
relays.h
sensors.h
storage.h
tasmota.h
web_ui.h
led_status.h
platformio.ini
README.md
CHANGELOG.md
This project uses PlatformIO with the Arduino framework for ESP32.
pio runUseful serial monitor command:
pio device monitorConfigured in platformio.ini:
lib_deps =
tzapu/WiFiManager
bblanchon/ArduinoJson
paulstoffregen/OneWire
milesburton/DallasTemperatureThe controller infers printer idle state from plug power telemetry. Different printers, heaters, boards, and plugs report different standby and active wattage, so test the threshold and delay carefully before relying on automatic shutdown.
Use conservative values first. Confirm the printer does not dip below the idle threshold during normal printing, heat soak, pauses, filament changes, or bed temperature cycling.
Automatic shutdown should only be enabled after testing with the actual printer and plug combination.