PWM Fan control with ESP32

For anyone who was beating their head against this like I was, don’t forget to link the ground wire from your esp32 and the fan power supply together.

Wasted a good hour scratching my head trying to figure out why this wasn’t working :sweat_smile:

1 Like

I can confirm I’m driving a Noctua NF-S12B off of 3.3V logic right now

newbies mistake :wink:

Just tested the Noctua NF-S12B redux-1200 PWM 12V fan with an ESP32 where the PWM signal is just 3,3V without any issues. The tacho signal works also great and can be easily read via one of the input pins of the ESP32.

1 Like

I’ve read previously that the tacho signal can be 12V pulses. Also read the input pins on ESP32 read 0-5V. Without a step-down, I guess you haven’t fried anything, but I’m curious how the board reacts to the 12V.

Hi all, I’m just popping by to say thanks, following some of the info in here I managed to set up a 5V Noctua NF-A14 on an ESP32 with an RPM counter.

esphome:
  name: pwm-fan
esp32:
  board: esp32dev
  framework:
    type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
  encryption:
    key: "###############################"
ota:
  password: "######################"
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Pwm-Fan Fallback Hotspot"
    password: "#########"
captive_portal:

output:
  - platform: ledc
    pin:
      number: GPIO23
      inverted: false
      mode: OUTPUT
    id: oid1
    frequency: 25000 Hz

fan:
  - platform: speed
    output: oid1
    name: fan_140mm
    id: fan_140mm
    speed_count: 100

sensor:
  - platform: pulse_counter
    pin: 12
    name: "NAS Fan RPM"

The fan 5V is connected to the 5V on the ESP32
Fan GND is on the Board GND
Tacho from the fan is on Pin 12
And the PWM signal to the fan is from Pin 23

I set up an automation to monitor HDD temps from my OMV server and spin the fan up in 4 different increments.

3 Likes

What’s the circuit? You’re not powering the PWM fan directly from the GPIO pin, are you?

I am, shouldn’t I be?

What’s the amperage (current) on the leads? I really want to know. You are allowed to draw max 16 mA from GPIO pins. If your fan consumes more, you will fry your ESP device. This is why most people use transistors with an independent power supply — and the GPIO is used to connect to the base in the transistor so that current activates the transistor.

The fan is 260 mA max so way over the spec.

I haven’t had any issues (yet), and I’m fairly confident it will be OK especially as the fan never goes above 20% anyway and I have run it at 100% during testing.

Looking at this thread on Reddit:

Seems that other users are pulling a lot more current than I am just fine.

I’m not saying its a good idea though, if you do it like I have then its at your own risk, seems the limiting factor is the trace on the board so be careful!

I’m gonna do a similar project but I will definitely be using a FET or other type transistor for power, instead of the GPIO directly hooked to power the fan.

This looks like an interesting project:

No PWM control, but I don’t think it would be too difficult to add it.

Adding the temperature sensor and moving the control logic from HA to the microcontroller would make a more fault tolerant solution to the OP’s problem.

Not sure that having the temperature sensor enclosed in the case is a good idea though.

Same works for me! On a Noctua PPC and a Phanteks!

I’m still messing around with this. I initially had my automation using a mess of embedded IF/THEN/ELSE to switch the fan in steps. I never really liked it but I didn’t know what else I could do, but then I found this post:

It shows how to use a data template to control the fan percentage based on CPU temperature.

I have recreated that in my fan control automation and come up with this:

alias: Datastore Fan Curve
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.datastore_temp
condition: []
action:
  - service: fan.set_percentage
    data_template:
      percentage: >
        {% set temperature = states('sensor.datastore_temp') | int %}  {% if
        temperature > 59 %}
          100
        {% elif temperature > 40 and temperature < 60 %}
          {{ 4.5*temperature-170 }}
        {% else %}
          0
        {% endif %}
    target:
      entity_id: fan.fan_140mm
mode: single

What this does is:

  • If Temperature <41°C, Fan is off
  • If Temperature is between 40°C and 60°C, Fan is on at 14.5% and speed increases 4.5% for every 1°C above 41°C
  • If Temperature >60°C, Fan is 100%

This seems more like what I was setting out to achieve rather than stepped control as I had done before.

1 Like

I’m building something to cool my (passive) inverters to force air over the radiator. I found this to be a more excellent solution:

It’s running on one inverter now controlling three fans in parallel just via breadboard etc. I’ve got two inverters so will scale this up to cover both and make the solution less temporary but the whole thing took only a few minutes to get going and it’s just one yaml file for esphome. I want to add tachometer support though as this will give me a fan failure indication which is important as this is not something I want to have overheating.

2 Likes

Ok, I found a problem with this config. I have been having some wifi issues lately and last night, my Datastore controller dropped its connection while the fan was powered off. This caused a pretty dramatic increase in the HDD temperatures on my janky NAS:

Luckily I was checking something else at the time and spotted it.

To solve this I realised I needed to move some of the control logic on to the ESP board itself, rather than rely on Home Assistant and a suddenly un-reliable wifi connection.

I wanted the fan to turn on and run at 100% in the event of a connection loss. So I added an automation to the wifi section:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip: 
    static_ip: XX.XX.XX.XX
    gateway: XX.XX.XX.XX
    subnet: 255.255.255.0
    dns1: XX.XX.XX.XX
  on_disconnect:
    then:
    - fan.turn_on:
        id: fan_140mm
    - output.set_level:
        id: oid1
        level: 100%

This seems to have solved the issue (for now). It is difficult to test without taking out the entire Wi-Fi network

Dear friends, I have assembled two Noctua NF-A8 PWM fans and apparently everything works as expected. I can turn the fans on and off and change the speed all with an ESP32 without a TTL converter board.
I have connected them directly, 12V power supply for the fans and the 2 control signals directly from the fans to the ESP32. I use 2 different power supplies, 5v for the esp32 and 12v for the fans. I have joined the gnd of both feeders together with that of the esp32 so that everything works ( It works more or less well, from 0% to 9% the fans are stopped and from 10% to 100% the speed varied perfectly, I don’t understand this error range from 1% to 100% but it more or less meets my expectations )

I have found a bug. While the fans are spinning, if I disconnect the power from the esp32 and reconnect it, the esp32 protects itself and does not start, the esp32 feeder making noise. I have to turn off the power to the fans, wait for the esp32 to start and then plug in the power to the esp32 and everything works fine again. Another option to solve the problem is to disconnect the Output pwm pin of the esp32, then the esp32 boots correctly. It seems that some noise is sneaking through the output control pin.

It’s not a big problem but it makes it impossible for me to use a single 12v power supply for the fans with a 12v to 5v converter to power the esp32. Has anyone had this problem and how to solve it?
I would greatly appreciate the help. I have tried with some filtering capacitors connected from the output pwm to gnd pin but the operation of the fans varies although the esp32 starts correctly depending of the capacity of capacitors. Thanks everyone for your help. Kind regards