PWM Fan Controller

Just clarifying it a little bit about what @fr8tra1n said about the 12V:

The OP said he was using a 10KΩ resistor from the 12V to the fan tachometer pin. This pin is also connected to the ESP8266, which he assumed, correctly, won’t survive to be exposed to 12V very long.

Quick clarification: the tachometer is not “sending pulses”. The line is always UP (12V), and the tachometer connects it to ground (GND) 2 times per revolution. Yeah, it’s “sending pulses” in the sense that the line is always at 12V (pulled up by the pull-up 10KΩ resistor) and those “pulses” are 0V (GND).

The tachometer may not work correctly with a lower voltage, let’s say, 3.3V, because, as the OP said before, the RPM readings were not accurate.

I’ve seen people trying to use a voltage divider (other 2 resistors) to bring the 12V line down to 3.3V, a voltage that the ESP8266 can stand, before reaching the ESP8266 pin. I didn’t test it yet but, in principle, it should work. These voltage dividers can be configured in many ways and there are many calculators on the web that you can use for helping with that. For example:

Voltage Divider Conversion Calculator | DigiKey

You can use, let’s say, a 27KΩ resistor for R1 and a 10KΩ resistor for R2, bringing the 12V input to 3.2V.

The formula is simple:
Vin / (R1 + R2) * R2 or, in our case, 12V / (27KΩ + 10KΩ) * 10KΩ which gives us 3.24V

Notice that Ohm’s Law (I = V / R) units are still obeyed in this formula. So, when we divide V / (R1 + R2), we have the current (I). But then we multiply it by R2, and I * R = V, so having our result in volts (V) is correct.

2 Likes

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 ?

Thank you for the great code. It was extremely helpful, not only for managing my fan but also for clarifying many things in ESPhome.

In my system it spins almost at a maximum speed of 1700 rpm, whereas the specification is 1800 rpm. I’m using an Arctic 120mm PWM fan with a 560R resistor at 3.3v.

This is the way was realized in Arduino and I directly used it in ESPhome."

Hi,
i have a problem with the Fan control. If i start the ESP8266, the Controller won’t work. The only thing who works is the function, when i turnend on and off the overridet function.

Can anyone help me?

  - platform: bmp280
    temperature:
      name: "Temperature"
      id: rack_fan_temperature
      oversampling: 16x
      accuracy_decimals: 1
      on_value_range:
        - above: 40.0
          then:
            if:
              condition:
                fan.is_off: rack_fan_toggle
              then:
              - logger.log: "Set fan level 100 over 40C"
              - output.set_level:
                  id: rack_fan_speed
                  level: 100%
        - above: 30.0
          then:
            if:
              condition:
                fan.is_off: rack_fan_toggle
              then:
              - logger.log: "Set fan level 66 over 30C"
              - output.set_level:
                  id: rack_fan_speed
                  level: 66%
        - above: 20.0
          then:
            if:
              condition:
                fan.is_off: rack_fan_toggle
              then:
              - logger.log: "Set fan level 33 over 20C"
              - output.set_level:
                  id: rack_fan_speed
                  level: 33%
        - below: 20.0
          then:
            if:
              condition:
                fan.is_off: rack_fan_toggle
              then:
              - logger.log: "Set fan level 15 under 20C"
              - output.set_level:
                  id: rack_fan_speed
                  level: 15%

And when the temperature decreases. E.g. from 30 to 25 °C, the fan doesn’t reduce the speed in accordance with the given % values.

I found this thread (and many others) very helpful, so I wanted to share my current solution for a 4-Pin PWM Fan controller with speed monitoring and a temperature sensor. This is to go into a cupboard where I want to put a NAS and mini-server but need to increase the airflow for cooling.

ESPHome YAML Code
esphome:
  name: fancontroller01
  friendly_name: fancontroller01

esp8266:
  board: esp01_1m

dallas:
  - pin: GPIO5 #D1
    update_interval: 10s #Low Interval for DEBUGGING

# Enable logging
logger:
  
# Enable Home Assistant API
api:
  encryption:
    key: "VeryLongAndVeryRandomisedMagicEncryptionKey="

ota:
  password: "SuperSecureHighlySecretPassword1"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  # Static IP
  manual_ip:
    static_ip: 192.168.0.11
    gateway: 192.168.0.1
    subnet: 255.255.255.0

captive_portal:

# Notes on Pins
# FanPin1 | "Black" | Gnd                      | 
# FanPin2 | "Red"   | +12v                     | 
# FanPin3 | "Green" | RPM Signal/Sense/Tach    | Pin D7 = GPIO13
# FanPin4 | "Blue"  | PWM Control Signal (+5v) | Pin D6 = GPIO12

sensor:
  # Send WiFi signal strength & uptime to HA                                                                                                                                                                                             
  - platform: wifi_signal
    name: WiFi Strength
    update_interval: 10s #Low Interval for DEBUGGING

  # RPM Signal from Fan                                                                                                                                                                                                                  
  - platform: pulse_counter
    pin: GPIO13 #D7
    name: RPM Signal
    id: fan_RPM_pulse
    unit_of_measurement: 'RPM'
    filters:
      - multiply: 0.5
    count_mode:
      rising_edge: INCREMENT
      falling_edge: DISABLE
    update_interval: 10s #Low Interval for DEBUGGING

  - platform: dallas
    address: 0x9400000000000000
    name: Temp01

output:
  - platform: esp8266_pwm
    id: fan_speed
    pin: GPIO12 #D6
    frequency: "25000 Hz"
    min_power: 10%
    max_power: 100%

fan:
  - platform: speed
    output: fan_speed
    speed_count: 10
    name: fan speed control
    id: fan_speed_toggle


The 2nd fan piggy-backs off the first with an included daisy-chain cable and I don’t need independent control of them.

I used a power module like this (Similar AliExpress Link) so I could pull both 12v and 3.3V/5V off a single power supply.

I still have a few things I want to do to it before installing:

  • Add 2nd temperature sensor (2 shelves/zones)
  • Code temp>speed (need to get in place and monitor to work out the right levels first) rather than HA Manual Control
  • Add code to send data into InfluxDB

Hi,

You might like to look at the post I wrote at 4-pin fan with d1mini and esphome: how to read current rpm of the fan? - #18 by MrFusion

I go over the spec for 4-wire fans and how to connect an ESP.

The Tacho output of the fan is (according to the spec meant to be) open collector/open drain. This means that the output is switched between being tied to ground and floating - which in turn means that you then need a pull-up resistor in order to reliably read the output (ie Tacho out ↔ GPIO input has a resistor to a positive supply).

Unfortunately, tying this to 12v can be problematic. Espressif’s official position is never feed any pin with more than 3.3V (see, for instance this post by ESP_Sprite).

The only reason that tying it to 12V hasn’t fried your ESP is generally more down to good luck than good planning. You’re actually relying on the ESP’s built-in ESD protection diodes (plus any other parasitic loads on the pin in questions) to carry the load whenever the Tacho output is ‘high’ (ie output floats so power going to the GPIO pin is coming via the pull-up resistor). This is generally not a great idea as the protection diodes generally can only carry a very small current, plus you don’t really know or have any control of what protection is in place per GPIO (and with ESPs there’s sometimes less than you would like on some pins…).

The way it works in this case (assuming a 10k pull-up) is that, when output is high:

  • Power flows from 12V rail through the pull-up resistor to the GPIO pin
  • Internally the voltage is seen by the input as well as the anode of the protection diode which then shunts the angry pixies through to the ESP’s internal positive supply rail
  • This looks like 12V → 10kOhm → junction of chip input and >diode> → 3.3v
  • Chip input is ‘high-Z’ (unless you’ve set internal pull-up or pull-down)
  • Forward bias voltage of the diode is approximately 0.7V

So

  • the voltage at the junction of chip input and diode is approximately 3.3-0.7 = 2.6V
  • therefore the voltage drop across the pull-up resistor is 12 - 2.6V = 9.4V
  • therefore the current flowing through the resistor & diode is 9.4V / 10,000 Ohms = is about 9.4mA… let’s call it 10mA

And 10mA is right at the limit of what many on-die ESD diodes can carry for any sustained period of time.

These numbers are just approximate but easy enough to be more precise - measure with a multimeter:

  • Power up the ESP & fan, and then stall the fan at a point where the Tacho output is high (or you could just connect the resistor directly between 12v and GPIO and leave the fan out of it - but I recommend involving the fan as well because you then have a chance to discover how well the fan actually implements the spec, or if it maybe has it’s own pull-up resistor, etc, etc)
  • Measure the voltage present at the ESP GPIO pin (guesstimate is 2.6V but could be quite a bit higher or lower)
  • Measure the pull-up resistor’s actual resistance
  • Re-do the calcs

Suggestions:

  • The ‘best’ (and recommended by Espressif as well as, tangentially, by Intel) - simply power the 10k pull-up resistor via the 3.3V line instead of 12V. Downsides - for many & varied reasons (usually related to the fan tacho’s implementation) the ESP may not see a clear enough signal & this might require a scope to diagnose & resolve
  • Alternative ‘best’ - feed direct from Tacho to GPIO (with no other components) and set GPIO mode to INPUT_PULLUP
  • Second ‘best’ - implement additional components at the GPIO input to guarantee voltage never goes above 3.3V (along with the 10k pull-up resistor, a 3V zener to ground & a schottky to positive should do it)
  • Third ‘best’ - increase the pull-up resistor value. Try, for instance, 100k or more to bring the current through the built-in ESD diode right down

Hope this all makes sense & that someone finds it helpful!

3 Likes

Hi,

I would like to recreate this. The temperature and humidity are good and when I connect a Cooler Master fan the control is perfect.

But I need a bigger fan. I have an Arctic F12 PWN. But if I want to control this fan, I can’t do that. The fan is always on.

Can someone help me?

Thanks

I’m using the schemtic for my pwm fan controller with a mofset, I think it’s a good idea to add a transistor between the mofset and the esp since when starting/programming the esp the pins are high so having a transistor will prevent the fan from spining when not configured. Also I use a levelshifter on the input/output pins of the fan and it works so well.
This also allows you to completely turn of power to the fan, adding a shutdown fan. In this case you can set the fun to turn off whem duty cycle is 0