PWM Fan Controller

For my first esphome project I’m creating a fan controller for my rack with an D1 Mini (8266). So far everything seems to work. Any tips or suggestions are welcome.

substitutions:
  friendly_name: Rack Fan

esphome:
  name: rack-fan

globals:
  - id: dhttemp
    type: float
    restore_value: yes
    initial_value: '0'

#########################                                                                                                                                                                                                                
# ESP32 AND NETWORK SETUP                                                                                                                                                                                                                

esp8266:
  board: d1_mini

# pid climate log update is noisy, dial it back to warn                                                                                                                                                                                  
logger:
  level: DEBUG
  logs:
    dht: DEBUG

# default HA integration, OTA updater and backup http web portal                                                                                                                                                                         
api:
  password: !secret ota_password
ota:
  password: !secret ota_password
  on_begin:
    then:
      - logger.log: "OTA start"
  on_progress:
    then:
      - logger.log:
          format: "OTA progress %0.1f%%"
          args: ["x"]
  on_end:
    then:
      - logger.log: "OTA end"
captive_portal:

wifi:

  # Read the wifi/pass from secrets.yaml:                                                                                                                                                                                                
  # wifi_ssid: "My Wifi XX"                                                                                                                                                                                                              
  # wifi_password: "XXXXXXX"                                                                                                                                                                                                             
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  fast_connect: true

  # Enable fallback hotspot (captive portal) in case wifi connection fails                                                                                                                                                               
  ap:
    ssid: !secret wifi_ssid_backup
    password: !secret wifi_password


text_sensor:

  # Send IP Address                                                                                                                                                                                                                      
  - platform: wifi_info
    ip_address:
      name: $friendly_name IP Address

  # Send Uptime in raw seconds                                                                                                                                                                                                           
  - platform: template
    name: $friendly_name Uptime
    id: uptime_human
    icon: mdi:clock-start

sensor:

  # Send WiFi signal strength & uptime to HA                                                                                                                                                                                             
  - platform: wifi_signal
    name: $friendly_name WiFi Strength
    update_interval: 60s

  # RPM Signal from Fan                                                                                                                                                                                                                  
  - platform: pulse_counter
    pin:
      number: D2
      mode: INPUT_PULLUP
    name: ${friendly_name} Fan Speed
    id: fan_pulse
    unit_of_measurement: 'RPM'
    filters:
      - multiply: 0.5
    count_mode:
      rising_edge: INCREMENT
      falling_edge: DISABLE
    update_interval: 30s

  # This is a bit of overkill. It sends a human readable                                                                                                                                                                                 
  # uptime string                                                                                                                                                                                                                        
  # 1h 41m 32s instead of 6092 seconds                                                                                                                                                                                                   
  - platform: uptime
    name: $friendly_name Uptime
    id: uptime_sensor
    update_interval: 60s
    on_raw_value:
      then:
        - text_sensor.template.publish:
            id: uptime_human
            # Custom C++ code to generate the result                                                                                                                                                                                     
            state: !lambda |-
              int seconds = round(id(uptime_sensor).raw_state);
              int days = seconds / (24 * 3600);                                                                                                                                                                                          
              seconds = seconds % (24 * 3600);                                                                                                                                                                                           
              int hours = seconds / 3600;                                                                                                                                                                                                
              seconds = seconds % 3600;                                                                                                                                                                                                  
              int minutes = seconds /  60;                                                                                                                                                                                               
              seconds = seconds % 60;                                                                                                                                                                                                    
              return (                                                                                                                                                                                                                   
                (days ? to_string(days) + "d " : "") +
                (hours ? to_string(hours) + "h " : "") +
                (minutes ? to_string(minutes) + "m " : "") +
                (to_string(seconds) + "s")
              ).c_str();                                                                                                                                                                                                                 

########################################################                                                                                                                                                                                 
# START THE FAN CONTROLLER SETUP


  # GET TEMP/HUMIDITY FROM DHT11                                                                                                                                                                                                         
  - platform: dht
    pin: D0
    model: DHT11
    temperature:
      name: "Temperature"
      id: rack_fan_temperature
      accuracy_decimals: 3
      on_value_range:
        - above: 50.0
          then:
            if:
              condition:
                fan.is_off: rack_fan_toggle
              then:
              - logger.log: "Set fan level 100 over 50C"
              - output.set_level:
                  id: rack_fan_speed
                  level: 100%
        - above: 40.0
          then:
            if:
              condition:
                fan.is_off: rack_fan_toggle
              then:
              - logger.log: "Set fan level 66 over 40C"
              - output.set_level:
                  id: rack_fan_speed
                  level: 66%
        - above: 30.0
          then:
            if:
              condition:
                fan.is_off: rack_fan_toggle
              then:
              - logger.log: "Set fan level 33 over 30C"
              - output.set_level:
                  id: rack_fan_speed
                  level: 33%
        - below: 30.0
          then:
            if:
              condition:
                fan.is_off: rack_fan_toggle
              then:
              - logger.log: "Set fan level 0 under 30C"
              - output.set_level:
                  id: rack_fan_speed
                  level: 0%


    humidity:
      name: "Humidity"
      id: rack_fan_humidity
                                                                                                                                                                                                          
    update_interval: 2s


output:
  # Wire this pin (15) into the PWM pin of your 12v fan                                                                                                                                                                                  
  # ledc is the name of the pwm output system on an esp32                                                                                                                                                                                
  - platform: esp8266_pwm
    id: rack_fan_speed
    pin: D1

    # 25KHz is standard PC fan frequency, minimises buzzing                                                                                                                                                                              
    frequency: "25000 Hz"

    # my fans stop working below 13% powerful.                                                                                                                                                                                           
    # also they're  powerful and loud, cap their max speed to 80%                                                                                                                                                                        
    min_power: 1%
    max_power: 100%


fan:
  - platform: speed
    output: rack_fan_speed
    name: ${friendly_name} Override Enable
    id: rack_fan_toggle
    on_turn_on:
     - output.set_level:
          id: rack_fan_speed
          level: !lambda |-
             return id(fan_speed_override).state/100.0;
    on_turn_off:
      - logger.log: "Power of Fan turned OFF"
      - delay: 1s
      - output.set_level:
          id: rack_fan_speed
          level: !lambda |-
            if (id(rack_fan_temperature).raw_state > 50){
              return 1;}
            else if (id(rack_fan_temperature).raw_state > 40){
              return 0.66;}
            else if (id(rack_fan_temperature).raw_state > 30){
              return 0.33;}
            else
              return 0;
        
        
          
number:
  - platform: template
    name: "Fan Speed Override"
    id: fan_speed_override
    internal: false
    max_value: 100.0
    min_value: 0.0
    step: 33.3
    optimistic: true
    mode: slider
    on_value:
      then:
        if:
          condition:
            fan.is_on: rack_fan_toggle
          then:
          - output.set_level:
              id: rack_fan_speed
              level: !lambda "return x/100;"

switch:
  # Expose an ESP32 restart button to HA                                                                                                                                                                                                 
  - platform: restart
    name: "Rack Fan D1 Pro Mini Restart"

Screenshots from HA reading temp:

Override Enabled:

Circuit diagam:

1 Like