Bastelix-Lab
IoT Projects
All Projects
ESPHome / Home Assistant

ESP32 Smoker Controller

ESP32-S3 with PID control, adaptive power limiting and damper control
ESP32-S3ESPHomeHome AssistantPID-ReglerDS18B20PT1000BME280PZEM-004TModbusServo
ESP32 Smoker Controller
Main image coming soon

Description

Fully automatic smoker controller based on an ESP32-S3-N16R8 running ESPHome. A PID controller drives the heater via PWM to an SSR relay and keeps the chamber temperature precisely at the setpoint. Two DS18B20 sensors at the top and bottom of the chamber provide the input values, which are combined into a weighted average for the PID loop. A BME280 on the outside of the cabinet measures ambient temperature and humidity, which feeds into the heat-loss model. A separate PT1000 via MAX31865 is mounted on the outside of a stainless-steel cold smoke generator, right at the burn zone — the measured temperature there is used to regulate the generator's air pump so the chips smoulder cleanly without overheating. An adaptive power limiter calculates the maximum permissible heating power every 30 seconds based on ambient temperature, setpoint and computed heat loss — effectively preventing overshoot above the setpoint. A stable-state detector running every 5 minutes adapts the heat-loss coefficient; depending on the detected operating regime, different PID parameter sets (hot/cold) are switched in. An MS24 servo (270°) drives the exhaust damper, a PZEM-004T v4.0 over Modbus measures voltage/current/power/energy. The whole system integrates into Home Assistant via native ESPHome entities: Climate, Sensor, Number, Switch, Button.

Want something like this built?
This is exactly what my "ESPHome Sensor Configuration" package covers — from 59€.
I deliver software only (firmware, configuration, code) — no assembled hardware. The components used are only linked for reference, you buy them yourself. Enclosures on request.

Features

  • PID temperature control with deadband
  • Adaptive max-power calculation from heat-loss model
  • Automatic switching between "hot" and "cold" PID parameter sets
  • Multiple sensors: 2x DS18B20 (chamber), PT1000 via MAX31865 (smoke generator), BME280 (ambient climate)
  • Servo-controlled exhaust damper (MS24, 270°)
  • Energy monitoring via PZEM-004T v4.0 over Modbus
  • Home Assistant climate entity, natively integrated
  • Safe boot sequence: control OFF, fan 0%, damper closed

Techstack

Hardware
  • ESP32-S3-N16R8
  • DS18B20 (x2)
  • BME280
  • PT1000 + MAX31865
  • PZEM-004T v4.0
  • MS24 Servo 270°
  • SSR-40DA
  • Heizelement
Software
  • ESPHome
  • PID Climate
  • One-Wire / SPI / UART-Modbus
  • Lambda-Automationen
Integration
  • Home Assistant Native
  • ESPHome Dashboard
  • MQTT optional

Code snippets

PID controller with deadbandyaml
climate:
  - platform: pid
    id: pid_controller
    name: "PID Temperatur-Regelung"
    sensor: temp_garraum_mittel
    default_target_temperature: 25°C
    heat_output: heizung_pwm

    control_parameters:
      kp: 0.12
      ki: 0.0008
      kd: 1.0
      output_averaging_samples: 5
      derivative_averaging_samples: 5
      min_integral: -0.3
      max_integral: 0.3

    deadband_parameters:
      threshold_high: 0.3°C
      threshold_low: -0.3°C
      kp_multiplier: 0.0
      ki_multiplier: 0.0
      kd_multiplier: 0.0
      deadband_output_averaging_samples: 15

    visual:
      min_temperature: 15°C
      max_temperature: 120°C
      temperature_step: 0.5°C
Adaptive max-power limiteryaml
interval:
  - interval: 30s
    then:
      - lambda: |-
          if (!id(auto_start_enabled)) return;
          if (!id(temp_garraum_mittel).has_state()) return;
          if (!id(temp_aussen).has_state()) return;

          float temp_ist  = id(temp_garraum_mittel).state;
          float temp_soll = id(pid_controller).target_temperature;
          float temp_aus  = id(temp_aussen).state;

          float delta_T          = temp_soll - temp_aus;
          float heat_loss_watts  = id(heat_loss_coefficient) * delta_T;
          float error_abs        = abs(temp_ist - temp_soll);
          float max_power        = 0.15;

          if      (error_abs > 5.0) max_power = 1.00;
          else if (error_abs > 2.0) max_power = 0.50;
          else if (error_abs > 1.0) max_power = 0.30;
          else {
            float base_power = heat_loss_watts / 2000.0;
            max_power = clamp(base_power * 1.5f, 0.10f, 0.30f);
          }

          id(calculated_max_power) = max_power;
          id(max_heater_power)     = max_power;

Screenshots

Smoker setup
Image coming soon
Smoker setup
Home Assistant dashboard
Image coming soon
Home Assistant dashboard
Temperature history
Image coming soon
Temperature history
PID control details
Image coming soon
PID control details
Damper control
Image coming soon
Damper control
Fan & heating
Image coming soon
Fan & heating
Automations
Image coming soon
Automations

More about this project