Controlling Noctua PWM fan with ESP8266

I have a noctua NF-A20 fan that I would like to control with a D1 mini and ESPHome. Using this topic as a reference: PWM Fan Controller

I created this configuration:

esphome:
  name: pwm-fan-controller
  friendly_name: pwm fan controller

esp8266:
  board: d1_mini

# Enable logging
logger:

# Enable Home Assistant API
api:

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-Controller"
    password: 

captive_portal:
    

sensor:
  - platform: pulse_counter
    pin:
      number: D2
    name: Fan Speed
    id: fan_pulse
    unit_of_measurement: 'RPM'
    filters:
      - multiply: 0.5
    count_mode:
      rising_edge: INCREMENT
      falling_edge: DISABLE
    update_interval: 5s

output:                                                                                                                                                                         
  - platform: esp8266_pwm
    id: fan_speed
    pin: D1
                                                                                                                                                                  
    frequency: "25000 Hz"
                                                                                                                                                                  
    min_power: 13%
    max_power: 100%

fan:
  - platform: speed
    output: fan_speed
    name: fan speed
    id: fan_toggle

Controlling the fan seems to work, when I move the slider up, the fan increases it’s speed, when I move it down, it decreases it’s speed. I am however facing 2 issues:

The reported RPM is incorrect, the fan has a minimum rpm of 350 and a max of 800, I get RPM values between 1500 and 3392. According to the documentation (https://noctua.at/pub/media/wysiwyg/Noctua_PWM_specifications_white_paper.pdf) the current code should be ok:

All Noctua fans provide a tachometer output signal of the following characteristics:
• two cycles per revolution

When I have a look at the log when the fan is running at full speed, I see that the pulse counter is all over te place:

[D][pulse_counter:174]: 'Fan Speed': Retrieved counter: 3348.00 pulses/min
[D][sensor:126]: 'Fan Speed': Sending state 1674.00000 RPM with 2 decimals of accuracy
[D][pulse_counter:174]: 'Fan Speed': Retrieved counter: 3779.24 pulses/min
[D][sensor:126]: 'Fan Speed': Sending state 1889.62207 RPM with 2 decimals of accuracy
[D][pulse_counter:174]: 'Fan Speed': Retrieved counter: 4132.13 pulses/min
[D][sensor:126]: 'Fan Speed': Sending state 2066.06616 RPM with 2 decimals of accuracy
[D][pulse_counter:174]: 'Fan Speed': Retrieved counter: 3894.55 pulses/min
[D][sensor:126]: 'Fan Speed': Sending state 1947.27380 RPM with 2 decimals of accuracy
[D][pulse_counter:174]: 'Fan Speed': Retrieved counter: 3649.46 pulses/min
[D][sensor:126]: 'Fan Speed': Sending state 1824.72986 RPM with 2 decimals of accuracy
[D][pulse_counter:174]: 'Fan Speed': Retrieved counter: 4120.12 pulses/min
[D][sensor:126]: 'Fan Speed': Sending state 2060.06006 RPM with 2 decimals of accuracy
[D][pulse_counter:174]: 'Fan Speed': Retrieved counter: 3888.00 pulses/min
[D][sensor:126]: 'Fan Speed': Sending state 1944.00000 RPM with 2 decimals of accuracy
[D][pulse_counter:174]: 'Fan Speed': Retrieved counter: 4700.24 pulses/min
[D][sensor:126]: 'Fan Speed': Sending state 2350.11987 RPM with 2 decimals of accuracy
[D][pulse_counter:174]: 'Fan Speed': Retrieved counter: 5704.56 pulses/min
[D][sensor:126]: 'Fan Speed': Sending state 2852.28174 RPM with 2 decimals of accuracy
[D][pulse_counter:174]: 'Fan Speed': Retrieved counter: 12396.00 pulses/min
[D][sensor:126]: 'Fan Speed': Sending state 6198.00000 RPM with 2 decimals of accuracy
[D][pulse_counter:174]: 'Fan Speed': Retrieved counter: 11397.72 pulses/min
[D][sensor:126]: 'Fan Speed': Sending state 5698.86035 RPM with 2 decimals of accuracy
[D][pulse_counter:174]: 'Fan Speed': Retrieved counter: 11978.40 pulses/min
[D][sensor:126]: 'Fan Speed': Sending state 5989.19775 RPM with 2 decimals of accuracy
[D][pulse_counter:174]: 'Fan Speed': Retrieved counter: 11604.00 pulses/min
[D][sensor:126]: 'Fan Speed': Sending state 5802.00000 RPM with 2 decimals of accuracy

The other issue I have is that when I set the fan to off / 0, it still keeps spinning. Any idea what the issue could be? I tried playing around with the “min_power”, but that doesn’t seem to help.

I have the fan connected to a 12v power supply, while the D1 mini gets it’s power via USB. I have the GND’s of the 2 power sources wired to eachother.

I think I’ve figured it out. The rpm’s where not right, because I did not add the resistor between the rpm pin and the 12v line, like in the schematic in PWM Fan Controller.

The problem with not being able to stop the fan completely seems to be that these Noctua fan’s don’t support anything below 20%, I fount this in a datasheet:

Operation below 20% PWM duty-cycle is not officially supported in the Intel specification
(undefined behaviour). However, most Noctua PWM fans can be operated at below 20%
and will stop at 0% duty-cycle. Only the following models keep running at their specified
minimum speed when the input is below 20%: NF-A20 PWM, NF-S12B redux 1200 PWM
and NF-B9 redux 1600 PWM

So I’ve now added a relay to be able to stop the fan. Now just got to clean this mess up befor I install it in my cabinet

Already drew up this board:

1 Like

Hi @ErikNL, would it be possible to control multiple (6) of these fans with this setup?

With a ESP8266, it might be hard to work with 6 fans, since you need 2 pins per fan (1 for control, 1 to measure speed). The ESP8266 does have 17 GPIO pins, but not all are usable I believe. More info here: ESP8266 Pinout Reference: Which GPIO pins should you use? | Random Nerd Tutorials

You might be better of using a ESP32, since that does have more pins: ESP32 Pinout Reference: Which GPIO pins should you use? | Random Nerd Tutorials
You could for instance use something like a D1 mini esp32

I wasn’t able to get the board I drew up in the post above working, it’s now gathering dust until I feel the need to pick it up again :sweat_smile:

Hello. I try now, as you to control Noctua NF-P12 redux-1700.
Made quick test, without resistance.
What value of resistance you used and it is connected to tachometer

Then someone have try to use two resistors? Do you have exact value and schematic?
I am newbie

Is right this schematic, vin as output of tachimeter fan, and vout to D1 mini ?

update. I use 4k resisto pull up and +3.3v on, tachometer fan pin, and it return right rpm, only with fan at 100% power. To low power, values, are not relly.
I will try 1k resistor.

I managed to make this work without needing a resistor, using the pullup resistor on the pin, see code below.
I had issues at first because I was powering the esp with a separate usb wall ps and without having a common ground the Noctua wasn’t powering off, but now that I’ve used a buck converter from 12V to 3.3v for the esp everything works.

sensor:
  - platform: pulse_counter
    pin:
      number: D2
      mode:
        input: true
        pullup: true
    name: Fan Speed
    id: d1_fan_pulse
    unit_of_measurement: 'RPM'
    filters:
      - multiply: 0.5
    count_mode:
      rising_edge: INCREMENT
      falling_edge: DISABLE
    update_interval: 5s

output:                                                                                                                                                                         
  - platform: esp8266_pwm
    id: fan_speed
    pin: D1
    frequency: "25000 Hz"

fan:
  - platform: speed
    output: fan_speed
    name: fan speed
    id: d1_fan_toggle

I can confirm RPM speeds are accurate, within reason. Only difference is I am using ESP32.

sensor:
  - platform: pulse_counter
    pin:
      number: GPIO14
      mode:
        input: true
        pullup: true
    name: Fan Speed
    id: fan_rpm
    unit_of_measurement: 'RPM'
    filters:
      - multiply: 0.5
    count_mode:
      rising_edge: INCREMENT
      falling_edge: DISABLE
    update_interval: 5s

output:                                                                                                                                                                         
  - platform: ledc
    id: fan_pwm
    pin: GPIO15
    frequency: "25000 Hz"

fan:
  - platform: speed
    output: fan_pwm
    name: fan speed
    id: fan_toggle
1 Like

That’s great, thanks for confirming that. I want to also try with an ESP32 and see if it makes a difference in the noise level of the fan.

The ESP8266 Software PWM Output doesn’t state the hz range in the docs, but I’ve read multiple times that it maxes out at 1000hz as it’s only software while the ESP32 is hardware.

By Noctua specs which follow Intel specification, PWM Target frequency: 25kHz, acceptable range 21kHz to 28kHz. From my test it works perfectly with the ESP8266 Software PWM set to 25000 hz, I don’t know of a way to actually test the frequency, but if it actually goes at 1000 hz I would expect to have a worse noise level or pitch. Maybe the Noctua fan I tested was fine but others might differ.

It would be great if there was a way of actually measuring the pwm signal, otherwise I guess it’s just safer to use and ESP32.

I’ve built a custom PCB breakout that supports both the D1 mini and the 20 pin variant in the same form factor like here. If anyone is interested I can upload the PCB build files to git. It’s kinda nice with about 8 JST breakout headers for analog, 2x I2C headers with 2 different formats, jumpers to select 3.3v or 5v. A logic level shifter with 2 outputs supporting up to 3A @ 5v for NeoPixels and a Mosfet header to switch loads on/off and a few other generic headers for whatever you want. Input voltage can be as high as 35v if you choose the LM7805. Otherwise 12v input using the AM11173.3v.

Yeah I know there is a lot of debate with 7805 and ams1117, but they are simple, reliable and easy to solder.

I am generally moving to ESP32 for everything as the $1 difference is more than reasonable but having flexibility for ESP8266 for super simple stuff is nice.

My testing was with a Noctua NF-A14x25. Zero hissing/whining or any other noises. The end goal is 2 NF-A6x25. The NF-A6’s are on order and I can give feedback when they arrive. PS: I used 25000Hz

The last step here will be getting HA to adjust fan speed dynamically based on temperature readings in the AV cabinet.

1 Like

Sounds interesting, I was working on a simple pcb too a few months ago with a ESP8266, but didn’t get it to work properly (didn’t boot into programming mode, so I probably made a mistake somewhere in the board)

It had just one header for the fan and a relay to completely shut it off.

The fan now still lives in my cabinet with a breadboard and a lot of wires.
Do you have a image of what your board looks like?

I have build just about the same, but with a different approach. I just soldrn an existing D1 on the PCB I created.

I also have a switch on it that can drive multiple fans. Up to about 5 amps. Everything is build in EasyEda. I can share Gerber files if you are interested.

More details, including ESPhome config on my GitHub:

Things are pretty well labeled but with one error on the diode direction for the Mosfet.

Two inputs, either JST-VH or JST-XH. same for the NEO Pixel outputs.

You’ll also see voltage jumper pads for GPIO39 (analog input) and both I2C headers

Additional Input jumper pad. This allows you to select the VCC input voltage or use the 5v output from the LM7805

A few Caps and the ams1117 3.3v are on the bottom

PCB is 60mm x 60mm

Nice design PCB, would you mind to share schematich and/or PCB layout?
thanks for the hard work!

I absolutely will. I made a couple of changes mainly to simplify the power input. I won’t be able to test the new PCB’s until the first week of March. I’ll add to my github and share that link here. thx

Hey did you got around to test the pcb?

Yes, running flawless now for some months!

Yes. sorry for the delay. I made a post in the hardware section.

Hardware Channel Link