Controlling Heating Elements

How to safely control heating elements with ESP32 using relays and MOSFETs

Heating elements -- including nichrome wire, Peltier modules, heating pads, and cartridge heaters -- convert electrical energy into heat. They appear in projects like egg incubators, 3D printer heated beds, fermentation controllers, and reflow ovens. You cannot drive a heating element directly from an ESP32 GPIO pin. The GPIO can only supply about $12\,\text{mA}$ at $3.3\,\text{V}$, while heating elements typically need several amps at $12\,\text{V}$ or more. Instead, you use a MOSFET or relay as a switch that the ESP32 controls.

In this guide, you will learn how to safely switch a heating element on and off using an N-channel MOSFET, and how to regulate temperature using PWM and a temperature sensor for feedback.

This guide uses the ESP32-WROOM-32 DevKit. Pin labels and GPIO numbers may differ on your board -- always check your board's pinout diagram.

SAFETY WARNING: Heating elements can cause burns and fires. Always use a power supply rated for your element. Never leave a heating element running unattended during development. Implement a thermal cutoff (hardware fuse or thermal switch) as a failsafe in any real application. Test in a fire-safe environment.

MOSFET or relay? This guide focuses on MOSFET-based PWM control for DC heating elements. For a detailed comparison of when to use a MOSFET vs. a relay (including AC loads), see our relay vs. MOSFET guide.

🔗Key Concepts

TopicDescription
Switching methodMOSFET (for DC loads with PWM) or relay (for on/off)
MOSFET choiceLogic-level N-channel (e.g., IRLZ44N, IRL540N)
Why "logic-level"?Standard MOSFETs need $10\,\text{V}$ on the gate. Logic-level MOSFETs fully turn on at $3.3$ to $5\,\text{V}$, matching the ESP32's GPIO output.
Flyback diodeRequired for inductive loads; protects the MOSFET from voltage spikes
Thermal cutoffA hardware safety device that cuts power if temperature exceeds a safe limit

🔗MOSFET Specs (IRLZ44N)

ParameterValue
TypeN-channel, logic level
Gate threshold voltage$1.0$ to $2.0\,\text{V}$
Drain-source voltage$55\,\text{V}$ max
Continuous drain current$47\,\text{A}$ max
On-resistance ($R_{DS(on)}$)$0.022\,\Omega$ at $V_{GS} = 5\,\text{V}$

Note: The IRLZ44N works well with the ESP32's $3.3\,\text{V}$ GPIO. Some other "logic-level" MOSFETs have a gate threshold up to $2.5\,\text{V}$, which leaves very little margin at $3.3\,\text{V}$. Check the datasheet and ensure $R_{DS(on)}$ is specified at $V_{GS} = 2.5\,\text{V}$ or lower.

🔗What You'll Need

ComponentQtyNotesBuy
ESP32 dev board1AliExpress | Amazon.de .co.uk .com
Heating element1AliExpress | Amazon.de .co.uk .com
MOSFET (IRLZ44N or similar)1AliExpress | Amazon.de .co.uk .com
100 ohm resistor1Gate resistorAliExpress | Amazon.de .co.uk .com
10k ohm resistor1Pull-down resistorAliExpress | Amazon.de .co.uk .com
5V power supply1Or 12V, rated for your elementAmazon.de .co.uk .com
Breadboard1AliExpress | Amazon.de .co.uk .com
Jumper wires6AliExpress | Amazon.de .co.uk .com

Links marked Amazon/AliExpress are affiliate links. We may earn a small commission at no extra cost to you.

🔗Wiring (MOSFET Method)

This configuration uses a low-side switch -- the MOSFET sits between the heating element and ground.

ConnectionDetails
MOSFET Gate (G)GPIO 25 through $100\,\Omega$ resistor
MOSFET Source (S)GND (shared with ESP32)
MOSFET Drain (D)Heating element negative terminal
Heating element positive terminalExternal power supply positive (+)
External power supply GNDESP32 GND (shared ground)

Additionally:

  • Add a $10\,\text{k}\Omega$ pull-down resistor between the gate and source (GND). This ensures the MOSFET stays off when the ESP32 is booting or resetting (when GPIO pins may float).
  • If your heating element is inductive (coiled nichrome wire, Peltier module), add a flyback diode (such as 1N5819 Schottky diode) across the element with the cathode toward the positive terminal.

Why a gate resistor? The $100\,\Omega$ resistor on the gate limits the inrush current when charging the MOSFET's gate capacitance. It also dampens high-frequency oscillations. It is not strictly required for a simple circuit, but it is good practice.

🔗Power Calculation

The power dissipated by a resistive heating element follows:

$$P = \frac{V^2}{R}$$

For example, a $10\,\Omega$ nichrome wire element on a $12\,\text{V}$ supply:

$$P = \frac{12^2}{10} = 14.4\,\text{W}$$

The current draw:

$$I = \frac{V}{R} = \frac{12}{10} = 1.2\,\text{A}$$

Make sure your power supply can handle this current, and that the MOSFET is rated well above it.

🔗Code Example: Simple On/Off Control

This sketch turns the heating element on and off at fixed intervals. Useful for testing.

#define HEATER_PIN 25

void setup() {
    Serial.begin(115200);
    pinMode(HEATER_PIN, OUTPUT);
    digitalWrite(HEATER_PIN, LOW);  // Start with heater off
    Serial.println("Heater control ready.");
}

void loop() {
    Serial.println("Heater ON");
    digitalWrite(HEATER_PIN, HIGH);
    delay(5000);   // On for 5 seconds

    Serial.println("Heater OFF");
    digitalWrite(HEATER_PIN, LOW);
    delay(5000);   // Off for 5 seconds
}

🔗Code Example: PWM Temperature Regulation

For finer control, use PWM to modulate the heating power. Combined with a temperature sensor, you can maintain a target temperature. This example implements a simple proportional control loop.

#include <OneWire.h>
#include <DallasTemperature.h>

#define HEATER_PIN 25
#define TEMP_SENSOR_PIN 4

#define TARGET_TEMP 37.0   // Target temperature in degrees C
#define TOLERANCE   0.5    // Acceptable range around target

OneWire oneWire(TEMP_SENSOR_PIN);
DallasTemperature sensors(&oneWire);

void setup() {
    Serial.begin(115200);

    // Set up heater PWM (low frequency is fine for heating elements)
    ledcAttach(HEATER_PIN, 1000, 8);  // 1 kHz, 8-bit resolution

    sensors.begin();
    Serial.println("Temperature control system ready.");
    Serial.print("Target: ");
    Serial.print(TARGET_TEMP);
    Serial.println(" C");
}

void loop() {
    sensors.requestTemperatures();
    float currentTemp = sensors.getTempCByIndex(0);

    if (currentTemp == DEVICE_DISCONNECTED_C) {
        Serial.println("ERROR: Temperature sensor disconnected! Shutting off heater.");
        ledcWrite(HEATER_PIN, 0);
        delay(1000);
        return;
    }

    // Simple proportional control
    float error = TARGET_TEMP - currentTemp;
    int pwmValue = 0;

    if (error > TOLERANCE) {
        // Below target: scale PWM proportionally
        // Clamp to 0-255 range
        pwmValue = constrain((int)(error * 50), 0, 255);
    } else if (error < -TOLERANCE) {
        // Above target: heater off
        pwmValue = 0;
    } else {
        // Within tolerance: low maintenance power
        pwmValue = 30;
    }

    ledcWrite(HEATER_PIN, pwmValue);

    Serial.print("Temp: ");
    Serial.print(currentTemp, 1);
    Serial.print(" C | Target: ");
    Serial.print(TARGET_TEMP, 1);
    Serial.print(" C | PWM: ");
    Serial.print(pwmValue);
    Serial.print("/255 (");
    Serial.print((pwmValue / 255.0) * 100, 0);
    Serial.println("%)");

    delay(1000);
}

Important: This is a simplified proportional controller for learning purposes. A real temperature control system should implement PID control (Proportional-Integral-Derivative) for stable, accurate temperature regulation without overshooting. The Arduino PID library makes this straightforward.

🔗How It Works

🔗MOSFET as a Switch

A MOSFET (Metal-Oxide-Semiconductor Field-Effect Transistor) acts as a voltage-controlled switch. When you apply a voltage to the gate that exceeds the threshold voltage, the MOSFET creates a low-resistance path between drain and source, allowing current to flow through the heating element.

The beauty of a MOSFET is that the gate draws virtually no current -- the ESP32 only needs to provide a voltage, not a significant current. This is unlike a bipolar transistor (BJT), which requires continuous base current.

🔗PWM for Temperature Control

Instead of simply switching the heater fully on or fully off, PWM lets you control the average power delivered to the element:

$$P_{avg} = P_{max} \times \frac{\text{dutyCycle}}{255}$$

At a duty cycle of 128 (50%), the heater receives half its maximum power on average. Because heating elements have thermal mass (they heat and cool slowly), they smooth out the rapid switching naturally. A PWM frequency of $1\,\text{kHz}$ or even lower is perfectly adequate for thermal control.

🔗Why a Temperature Feedback Loop?

Without feedback, you cannot know the actual temperature. The heater might overshoot your target (risking damage or fire) or undershoot (not reaching the desired temperature). By reading a temperature sensor on every loop iteration and adjusting the PWM accordingly, the system self-corrects.

🔗Alternative: Relay Method

For simple on/off heating control (no PWM), you can use a relay module instead of a MOSFET. This is appropriate when:

  • You do not need fine-grained temperature control (a few degrees of oscillation is acceptable)
  • You are switching AC-powered heaters
  • You want full electrical isolation

Use the relay to switch the heater on when temperature drops below the threshold and off when it rises above. This is called bang-bang control (or hysteresis control).

🔗Troubleshooting

ProblemPossible CauseSolution
Heater does not turn onMOSFET not fully on at $3.3\,\text{V}$Verify you are using a logic-level MOSFET (IRLZ44N, not IRF540N)
Heater stays on even when GPIO is LOWNo pull-down resistor on MOSFET gateAdd a $10\,\text{k}\Omega$ resistor from gate to GND
MOSFET gets very hotOn-resistance too high or current too highUse a MOSFET rated for your current; add a heatsink
Temperature overshoots badlyControl loop too aggressiveReduce the proportional gain; implement PID control
Temperature sensor reads wrongSensor too far from heating elementPlace the sensor close to (but not touching) the element
ESP32 resets when heater turns onPower supply noise or shared powerUse separate supplies for ESP32 and heater; add decoupling capacitors
Heater runs at startupGPIO floats during bootAdd the $10\,\text{k}\Omega$ gate pull-down resistor

🔗Safety Checklist

Before running any heating project, verify the following:

  • Power supply is rated for the heating element's current draw
  • MOSFET (or relay) is rated above the element's current and voltage
  • A hardware thermal cutoff or thermal fuse is installed as a failsafe
  • The heating element is mounted on a heat-resistant, non-flammable surface
  • The code includes a sensor-disconnected check that shuts off the heater immediately
  • You have tested the shutdown behavior (what happens if the ESP32 crashes or resets?)

🔗Next Steps

  • Implement a full PID controller for precise temperature regulation
  • Log temperature data to an OLED display or send it over WiFi
  • Build an egg incubator, fermentation chamber, or filament dryer
  • Add over-temperature alerts using a buzzer