• iot
  • knowlege-backup
  • home improvement
  • heating
  • esphome
  • home assistant
  • electronics
  • esp32

ESPHome Controlled Fireplace Blower


Our home had a gas fireplace in our living room when we moved in. Though the radiant heat from it felt good when winter came, there was no blower installed so a lot of the heat was wasted. After one winter of wasted heat, I purchased a blower designed for gas fireplaces. It gets inserted into the base of the unit and turns on based on the temperature. The fan pulls air from under the unit, which is exposed to the room, and blows it through a vent in the back of the unit which heats the air and ejects it through the vent at the top.

This worked great for years, but this winter I was being driven insane by the noise. The fan was loud enough to require cranking up the volume when watching TV. The only way to stop it was to unplug it and we would inevitably forget to plug it back in.

I considered a few options:

  1. Just use a smart plug and be able to control it if needed, with automatic on overnight.
  2. Buy a new, more expensive fan and hope it would be quieter
  3. Do it myself.

I like do it myself as an option, so I dug into the possibilities. I was sure I could use ESPHome to accomplish my goals and after some research I learned that yes, ESPHome could handle this problem. I listed these as my goals.

Goals

  • [ x ] - Quiet operation
  • [ x ] - Able to control the fan from Home Assistant
  • [ x ] - Use standard components, so I can fix it if something fails
  • [ x ] - Monitor Temperature from Home Assistant
  • [ x ] - Original remote must still work(spousal approval)

Stretch Goals

I done some preliminary research on how to achieve these, but have yet to spend a ton of time working on them.

  • [ ] - Control Fireplace burner state from Home Assistant
  • [ ] - Determine Fireplace burner state in Home Assistant
  • [ ] - Climate Control

Build Details

I ended up with the following components:

  • Three 120mm PWM fans
  • esp32
  • DHT11 Temperature and Humidity Sensor
  • 12v Buck Converter

Fireplace Blower Fritzing Diagram

The fans are wired in series, 12v from the DC transformer, PWM signals, and ground are all wired together.

The buck converter receives 12v from the transformer, drops the voltage and sends 5v to the dht11, and the vin pin on the esp32. Ground from both the dht11 and esp32 is wired to output ground on the buck converter, along with the ground from the fans.

PWM from the fans is wired to a PWM output pin on the esp32 and the DHT11 signal pin is wired into a GPIO.

Once I validated everything worked well, I soldered things together and stuck them into a plastic case. The fans were mounted to a 3d printed case that allows air to flow from underneath and push up through the vents. I also stuck a case around the DHT11 and attached it to the top of the lower compartment with a magnet, which improves temperature pickup.

Software Notes

The important bits of my esphome configuration file are at the bottom of this post.

My primary goal was to ensure this would continue to function even if Home Assistant or the network went down. Home Assistant’s only role is as a dashboard and allowing for setting thresholds remotely. The actual decisions to turn the fan on, speed, and turning it off is fully handled by the esp32 device.

I am extremely happy with the result. The fans are significantly quieter when running at lower speeds and if I bump their speed up a bit beyond silent they move a ton more air than the purpose build blower did.

Image of Home Assistant Dashboard


# Allows setting thresholds within Home Assistant but storing them on the device. 
number:
  - platform: template
    name: "$friendly_name Low Temp Threshold"
    id: low_temp_threshold
    optimistic: true
    min_value: 50
    max_value: 80
    step: 1
    initial_value: 70
    unit_of_measurement: "°F"
    mode: box
    restore_value: true

  - platform: template
    name: "$friendly_name High Temp Threshold"
    id: high_temp_threshold
    optimistic: true
    min_value: 80
    max_value: 120
    step: 1
    initial_value: 98
    unit_of_measurement: "°F"
    mode: box
    restore_value: true

  - platform: template
    name: "$friendly_name Max Fan Speed"
    id: max_fan_speed
    optimistic: true
    min_value: 13
    max_value: 100
    step: 1
    initial_value: 65
    unit_of_measurement: "%"
    mode: slider
    restore_value: true

# the lamda here does most of the work. It triggers the fans on based on the temperature thresholds above and ramps up the fan
# as the temperature increases. 
sensor:
  - platform: dht
    pin: GPIO21
    model: DHT11
    temperature:
      id: "fireplace_temperature"
      name: "$friendly_name Temperature"
      accuracy_decimals: 1
      filters:
         - exponential_moving_average:
             alpha: 0.1
             send_every: 1
         - lambda: return x * (9.0/5.0) + 32.0;
      unit_of_measurement: "°F"
      on_value:
        then:
          - lambda: |-
              float temp = id(fireplace_temperature).state;
              float low_temp = id(low_temp_threshold).state;
              float high_temp = id(high_temp_threshold).state;
              float max_speed = id(max_fan_speed).state;
              bool manual_mode = id(manual_control).state;

              if (temp <= low_temp) {
                // Below low threshold - turn off
                id(fireplace_fan).turn_off().perform();
              } else if (manual_mode) {
                // Manual mode is on - do nothing, let user control
                return;
              } else if (temp >= high_temp * 0.95) {
                // At or above 95% of high temp - max speed
                id(fireplace_fan).turn_on().set_speed(max_speed).perform();
              } else {
                // Between low and 95% of high - linear ramp
                float temp_range = (high_temp * 0.95) - low_temp;
                float temp_position = temp - low_temp;
                float speed_percent = (temp_position / temp_range) * max_speed;
                speed_percent = max(1.0f, min(max_speed, speed_percent));

                id(fireplace_fan).turn_on().set_speed((int)speed_percent).perform();
              }
    
# Some fun wiring up of output and fan to allow fan monitoring in home assistant
output:
  - platform: ledc
    pin: GPIO25
    id: fireplace_fan_pwm
    frequency: 25000 Hz  # Above audible range
    min_power: 13%
    zero_means_zero: true

fan:
  - platform: speed
    output: fireplace_fan_pwm
    id: fireplace_fan
    name: "$friendly_name Fan"
    speed_count: 100  # Gives you 0-100% control

# Allows full manual control of the fan.   
switch:
  - platform: template
    name: "$friendly_name Manual Control"
    id: manual_control
    optimistic: true
    restore_mode: RESTORE_DEFAULT_OFF

Note:

I ran into a really frustrating issue throughout this project where Home Assistant would stop communicating with the device. I could get data from the device to HA, but not consistently send updates. I managed to track it down and wrote a post mortem.


Feedback:
💙 Likes 📅 Now ⚙️ Defaults 🖥️ Self Hosted