Giter Site home page Giter Site logo

esphome-fan-controller's Introduction

ESPHome Fan Controller

This project describes how to build a quiet thermostat controlled fan for cooling your media console, gaming cupboard or anything else.

The software is ESPHome and Home Assistant. The hardware is an ESP32 with a regular 12v 120mm Computer Fan (PWM) and a Temperature Sensor (DHT11).

Cost

The electronic parts are $29 USD including the ESP32.

Motivation

My sons's Playstation 5 sits in our TV Console which runs hotter than Sol. Also in that Media Console is a Macmini, a Raspberry Pi and a few other devices. My wife likes to keep the door neat and closed, so it needs some cooling!

I previously had a thermostat which simply toggled the fan when the temperature crossed a threshold. That didn't work for me because the fans were loud and toggling on/off. Very wife-unfriendly and annoying when you're watching a movie to hear the fan buzzing every other minute. The process led me to this smart thermostat which intelligently controls the speed of the 12v-fan to maintain a perfect temperature in your cabinet. It will find and hold the fan at the necessary power level (like 22% power) to keep a cupboard cool and adjust as necessary.

"closed cabinet"

Features

The main features are:

  • the fan dynamically adjusts it's speed based on the temperature sensor using a Process Control mechanism called PID
  • adjustable target temperature. I currently target 30degC but maybe in winter I'll reduce it to 27.
  • uses ESP32's Wifi to connect to Home Assistant for control and reporting
  • the ESP32 is standalone and so the cooling function will continue to operate without Wifi. Doesn't need HomeAssistant or Wifi to operate. Wifi is only needed for setup, manual control and reporting.
  • no screen is needed on the device itself, all management is done via Home Assistant
  • my system uses two fans for extra cooling. Depending on how much air you need to draw through your enclosed space you could use 1 or 2 fans
  • it is easily extendable to control up to 10 separate enclosed spaces with separate temperature sensors as well. You're only limited by the Amps of your 12v Power Brick and the pins on your ESP32.
  • manual speed control over ride if you don't want to use PID Control
  • no coding is needed. Just some configuration in YAML files. In fact this repo only contains 1 file config-fan.yaml.
  • No resistors, capacitors or difficult soldering needed. The fan and the temperature sensor plug straight onto the pins of the ESP32. Although I did mount mine on a perfboard for cleanliness and put it in a case.

"graphs"

This is a screenshot from Home Assistant. I'll show you how to setup this dashboard.

Visuals

"inside cabinet" "controller" "fans"

Parts (~$29 USD)

  • DHT11 - temperature and humidity sensor. I'm using the one on a board with 3-pins. Cost $1.50 USD

  • 12v PWM 4-pin Computer Fan - I'm using 2 x 120mm Corsair fans. Any 12v PWM-controllable fan should work. Cost $8-$15 USD. I recommend getting high quality fans if you care about noise and need to move a lot of air
    .

  • 12v Power Adapter - 1A or 2A should be fine depending on your fan's current draw. Cost $7

  • 12v DC Female Jack - with wire outlets. You can normally buy these with the Power Adapter
    or

  • LM2596 Buck Converter - to convert 12v down to 3.3v. Cost $1.50 each (normally in packs of 6-10)

  • ESP32. You can use any ESP32. I'm using a NodeMCU compatible board. Mine cost $4 from Aliexpress

Choosing a Good Fan

You need a 4-pin fan which has PWM. 3-pin fans aren't acceptable, they are just on/off with tachometer sensor.

As you'll see below, our fans are being powered by the PWM pin. Our expectation is that the fans stop spinning at 0% power. Some people have reported that some fans don't stop running at 0% power (or worse that they stop completely at 100% power which is weird).

It appears that Corsair and Noctua fans behave as expected so you might want to stick with them.

However, if your fan does behave this way, you can use a MOSFET to turn it off. There are (instructions here for how to do this). Please post your progress to that issue.

Wiring Diagram

Some important notes:

  • connect the fan PWM pin to a PWM GPIO
  • turn the knob on the buck converter with a screwdriver to make it output exactly 3.3v. You'll need a multimeter to measure that output.
  • ensure the 12v and 3.3v grounds are connected together.
  • the Blue line is the tachometer ("Tach") input pin. It is optional to connect this. You can connect this to a PWM input pin of your choice (GPIO25 in the example config) and it will send 1-2 pulses per full turn (depending on the fan). You can use this to monitor actual RPM of the fan and detect a fan defect, blocked rotor, etc. You will need one PWM input for each tach on each fan.
  • you could easily skip the Buck converter and use two separate power sources 3.3v and 12v.
  • the fritzing diagram shows a 4-pin DHT-11, when in fact I have the simpler 3-pin version as shown in the parts list. The 4-pin version might need a pullup resistor, haven't tried it.

Installing the software onto the ESP32

Get this repo

Clone this github repository. From the command line and then cd into the directory

git clone https://github.com/patrickcollins12/esphome-fan-controller.git
cd esphome-fan-controller

Review the YAML and read the ESPHome docs.

Review the YAML file.

Ensure the pins are set correctly for the PWM Fan (ledc) and the DHT-11.

Review the instructions for the ESPHome Climate Thermostat, ESPHome PID Climate Thermostat and the DHT-11 sensor.

Change the device name from console-fan to whatever seems appropriate. You might want to change the yaml filename as well.

Setup your temperature sensor

Set the correct pin for your temp sensor. Note that the DHT11 sensor is setup to use an exponential moving average. Without this filter the PID controller reacts to every minor sensor movement. If you have a faster sensor like the BME260 you might need to tweak this filter.

  # GET TEMP/HUMIDITY FROM DHT11
  - platform: dht
    pin: GPIO33
    temperature:
      name: "Temperature"
      id: console_fan_temperature
      accuracy_decimals: 3

      # If you don't smooth the temperature readings 
      # the PID controller over reacts to small changes.
      filters:
         - exponential_moving_average:  
             alpha: 0.1
             send_every: 1

(Some people take an average of two temperature sensors.)

Setup your PWM fan

Make sure you connect your fan to a PWM capable GPIO. All ESP32 pins that can act as outputs can be used as PWM pins but GPIOs 34-39 can’t generate PWM.

Also note that my fans stop spinning below 13% power, so I set that as the minimum. I have a max power of 80% applied to the fans to make them wife-friendly. You might want to remove this minimum or maximum.

  - platform: ledc
    id: console_heat_speed
    pin: GPIO27

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

    min_power: 13%
    max_power: 80%

Setup your wifi details

mv secrets-sample.yaml secrets.yaml

Edit your wifi credentials in secrets.yaml. The .gitignore will prevent you accidentally uploading your wifi credentials to github.

Install ESPHome

Install ESPHome according to the instructions on the ESPHome website.

I prefer command-line on Mac: pip3 install esphome

Most people use the ESPHome that runs inside Home Assistant. You can use that too.

Install to ESP32

Connect your ESP32 via USB to your computer, then upload the Firmware to the ESP32.

esphome run console-fan.yaml

At this time if you've set the pins right, the sensor should be spitting out values and the PID can control the fan.

Success!

% esphome logs console-fan.yaml
INFO Reading configuration console-fan.yaml...
INFO Starting log output from console-fan.local using esphome API
INFO Successfully connected to console-fan.local
...
[22:54:09][C][mdns:085]:   Hostname: console-fan
[22:54:09][C][homeassistant.text_sensor:023]: Homeassistant Text Sensor 'ha_kp'
[22:54:09][C][homeassistant.text_sensor:024]:   Entity ID: 'input_text.kp'
[22:54:10][C][homeassistant.text_sensor:023]: Homeassistant Text Sensor 'ha_ki'
[22:54:10][C][homeassistant.text_sensor:024]:   Entity ID: 'input_text.ki'
[22:54:10][C][homeassistant.text_sensor:023]: Homeassistant Text Sensor 'ha_kd'
[22:54:10][C][homeassistant.text_sensor:024]:   Entity ID: 'input_text.kd'
[22:54:10][D][dht:048]: Got Temperature=30.0°C Humidity=38.0%
[22:54:10][D][sensor:113]: 'Humidity': Sending state 38.00000 % with 0 decimals of accuracy
[22:54:11][D][dht:048]: Got Temperature=30.0°C Humidity=38.0%
[22:54:11][D][sensor:113]: 'Humidity': Sending state 38.00000 % with 0 decimals of accuracy
[22:54:12][D][dht:048]: Got Temperature=30.0°C Humidity=38.0%
[22:54:12][D][sensor:113]: 'Humidity': Sending state 38.00000 % with 0 decimals of accuracy

Setup Home Assistant

If the above steps worked correctly, the device will be auto-discovered by Home Assistant. You will need to add the device.

Multiple sensors and switches are exposed by the ESPHome software.

You also need to setup the dashboard. I'll explain those two steps below.

Setting up the Home Assistant Dashboard

dashboard

Here is my full dashboard in Home Assistant.

For this full dashboard configuration, checkout lovelace-dashboard.yaml

Let's go through this page section-by-section.

The Primary Controls

type: entities
entities:
  - entity: fan.manual_fan_speed
  - entity: sensor.fan_speed_pwm_voltage
  • You can turn on manual fan speed and use this fan control to adjust the speed manually.

  • The Fan Speed (PWM Voltage) is the % of voltage being sent out via PWM to the fan controller. At 100% it will be sending 12v, at 50% it will be sending 6v.

If manual fan speed is off, this next card stack will conditionally display.

type: conditional
conditions:
  - condition: state
    entity: fan.manual_fan_speed
    state_not: 'on'
card:
  type: vertical-stack
  cards:
    - type: entities
      title: Thermostat Fan (PID)
      entities:
        - entity: climate.console_fan_thermostat
        - entity: sensor.openweathermap_temperature
          name: open weather
        - entity: sensor.contact_sensor_1_device_temperature
          name: room temperature
    - type: vertical-stack
      cards:
        - type: glance
          entities:
            - entity: sensor.console_fan_is_in_deadband
              name: in_deadband?
            - entity: sensor.console_fan_error_value
              name: error
              icon: mdi:equal
        - type: glance
          show_icon: false
          entities:
            - entity: sensor.console_fan_output_value
              name: output
            - entity: sensor.console_fan_p_term
              name: p_term
            - entity: sensor.console_fan_i_term
              name: i_term
            - entity: sensor.console_fan_d_term
              name: d_term
  • The Console Fan Thermostat is a controllable thermostat, by clicking it you can alter the target temperature and turn the fan on/off. These changes will be persisted to flash on the ESP32.

  • The Open Weather and Room temperatures are from other sensors in my house for reference.

  • The kp, ki and kd inputs are exposed from the device. Your ESP32 will be automatically receiving changes to these values to control the behavior of the PID controller. While you could tune these from the config.yaml it requires a compile, upload and reboot cycle each time. This is inconvenient and best to tweak in real-time. We want to expose these 3 parameters to a Home Assistant dashboard.

The Graphs

Add the fan speed and the thermostat to two separate graphs. I've also added my room temperature from a separate device for comparison.

type: vertical-stack
title: 3 hr
cards:
  - type: history-graph
    entities:
      - entity: sensor.fan_speed_pwm_voltage
    hours_to_show: 3
    refresh_interval: 0
  - type: history-graph
    entities:
      - entity: climate.console_fan_thermostat
        name: ' '
      - entity: sensor.contact_sensor_1_temperature
        name: room
    hours_to_show: 3
    refresh_interval: 0

Helpful Details - More Sensors and Switches

This dashboard YAML exposes various sensors and switches from the ESP32.

type: entities
entities:
  - entity: sensor.console_fan_ip_address
  - entity: sensor.console_fan_wifi_strength
  - entity: sensor.console_fan_uptime
  - entity: sensor.humidity
    name: console fan humidity
  - entity: switch.console_fan_autotune
  - entity: switch.console_fan_esp32_restart
  • console_fan_autotune is a button which starts the PID tuning process. I ended up abandoning this approach and manually tuning the PID.

  • console_fan_esp32_restart restarts the ESP32 remotely.

PID Parameters - setting the PID parameters from the frontend

This dashboard allows you to configure the PID parameters. See the next section for how to set these parameters. This dashboard will conditionally disappear if manual fan speed control is on.

type: conditional
conditions:
  - condition: state
    entity: fan.manual_fan_speed
    state_not: 'on'
card:
  type: vertical-stack
  cards:
    - type: entities
      entities:
        - entity: number.kp
        - entity: number.ki
        - entity: number.kd
        - entity: button.pid_climate_autotune
      title: PID Controls Setup
    - type: entities
      entities:
        - entity: number.deadband_threshold_low
          name: Threshold Low
        - entity: number.deadband_threshold_high
          name: Threshold High
        - entity: number.deadband_ki_multiplier
          name: ki multiplier
      title: Deadband Parameters

Configuring the PID Parameters

The thermostat is controlled using a standard Process Control system called a PID.

In our system the goal of the PID control is to set the fan voltage (speed) to bring the temperature measured by the sensor to a target temperature (30degC).

Search the internet and you'll find many resources for setting up a PID Controller. There are a lot of resources for fast response systems like cruise control systems but not many for dealing with slow response cooling systems like this one.

The ESPHome PID Climate system that we're using here has some resources to explain how to tune the parameters. However, its autotune system didn't spit out useful results for me and I will explain how to manually get the right parameters. Your system will be different to mine and so your parameters will need to be slightly different. For instance, your cabinet will be a different size, I have two fans, you may only have one, etc.

There are only two parameters you will need to adjust: the kp and ki parameters. The kd parameter is not useful for us.

In my system the goal of tuning was to minimise aggressive changes to the fan (my wife complained she could hear the fan turning on and off). I don't mind the system drifting up to 2degC away from the target temporarily while it slowly reacts. A 7% drift (2degC/30degC) on some control systems could blow up a Nuclear plant or cause a Cruise Control system to crash into another car. But in our system a 7% short temperature drift is a fine tradeoff for quiet fans.

Setting the kp (gain) parameter - how aggressively to cool?

KP is the main Gain. How aggressively will the fan respond to a small change in temperarature? Do you want the fan to go to 100% power in response to a 0.1degC change in temperature? In general my goal was to have the fan at 50% in response to a 1degC change in temperature, thus could normally stave off any further temperature rises, but if it the temperature did keep rising the fan will then climb to 100% power.

Using lower gain (0.1) (my preferred setting):

  • takes longer to cool down
  • is more likely to under react to fast temperature changes.
  • 2deg sharp spikes can occur before the system reacts
  • It can takes up to 10 minutes to fully close a 0.5degC gap.
  • but, it is much less likely to oscillate around the target temperature and cause the fan to turn on and off constantly.

Using higher gain (1.0):

  • responds quickly to changes in temperature
  • but, is more likely to oscillate and make the fan swing from 0% to 100% and back again as it tries to control the temperature. This means you can hear the fan trying to adjust.

Setting the ki parameter - how long to adjust an offset?

ki: 0.0009

The ki parameter adjusts for temperature offset. Try setting ki to 0. Set your system initially with kp=0.1, ki=0 and kd=0. You'll find that the system operates with a constant delta/offset to the target temperature. The ki parameter adjusts for this.

1/ki is the seconds it should attempt to correct an offset. So 0.03 will adjust in 30seconds. 0.0009 will close a small temperature delta in 20 minutes. See a good description here https://blog.opticontrols.com/archives/344

Higher numbers like 0.03 will respond much quicker, but it also will cause a lot of noise and oscillation in the fan speed.

Setting the kd parameter - predicting a change

The kd (D in PID) is meant to pre-react and backoff early. Small parameters can help overshoot but does create some fan noise and oscillation. The interwebs says that most (70%) of process controllers don't use the D and just a PI controller.

Setting the deadband parameters - minimising changes once inside the zone

In my first contribution to ESPHome I added Deadband to PID Climate. Follow the instructions there to ensure that your fans stop oscillating once it reachs the correct target temperature.

Tell me

I'm keen to hear what PID parameters works for your fan.

esphome-fan-controller's People

Contributors

patrickcollins12 avatar thedk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

esphome-fan-controller's Issues

Reduce flash writes?

As far as I can tell the config you have writes a couple of parameters to flash every minute, amounting to ~0.5m writes per year. From what I've read the flash memory in ESP32 is expected to last 100k-1m write operations. I don't know if there's wear leveling in an ESP (guess not), so it might make sense to reduce writing the parameters to the ESP every 15min or so?

No Integration in Home Assistant

Hello,

I have followed your documentation ans installed the fan controller,
The controler and all other work perfekt, only my Home Assistant show no new integration.

Hope you have a solution for that.

LED strip control

Hi.

Really great project! It seems to be exactly what I'm looking for. I found it while searching for ways to make a 3D printer enclosure, like this: https://www.reddit.com/r/3Dprinting/comments/10io7st/how_the_ikea_platsa_3d_printer_enclosure_looks/

So, in the enclosure I would use your project to add a bit of active cooling / stabilize temperature. However, I would also like to add some lights in there - like the linked enclosure.

So, I figured the ESPHome would be able to control the lights, but to simplify the project I wanted to avoid also needing a 5V rail - So, I found these LED-strips: WS2815.

I was wondering if you knew whether it would be as simply as adding them to the 12V rail and adding them in the ESPHome component?

I realize this project isn't about lighting via ESPHome and it might not be needed in most peoples "media console housing", but I figured I would ask here since I consider my idea/thought an extension of your project.

Thank you for any input you could provide :)

Offline capability

Hi Patrick
cool project !
Is there a way to make the setup offline resilient ?

  • insure the fan regulates the temperature, even if there is no wifi connection, or homeassistant not available

mercimille
Christoph

Problems using Dallas sensor

I have this controller working well on my Solar battery heater application. I use it with a Pwm dimmer to control the heating pads and I use a temp sensor from the battery BMS software that is exposed via a homeassistant sensor. It's all detailed in this Solar forum:

https://diysolarforum.com/threads/new-battery-heater-controller-home-assistant-and-esphome.53665/#post-685275

however, I have noticed that there are dropouts of that sensor when home assistant becomes unavailable for any reason which results in the battery either not being heated or being heated too much. So I am trying to add a local Dallas temp probe that I can sandwich between the batteries and have a self contained system running completely in ESPHome on one chip.

03BDA0B4-7BF5-4066-91BD-4801E9695485

The problem is whenever the Pwm dimmer is ON (even at 1%), the Dallas temp sensor throws "Scratch pad checksum invalid!" errors and can't be read.

I'm no stranger to this approach in ESPHome or these sensors. I have several in use in my greenhouse and other areas. I've tried shielding the sensor wires, and even tried every available GPIO for the sensor and even watched the Dallas waveform on my scope when adjusting the pull-up resistor, all to no avail.

using a DHT type sensor isn't an option due to the way the batteries are mounted. It really needs to be a "probe" type sensor.

Any pointers or ideas to solve this are welcome!

Need advice: Still high temps. What RPM is good?

Thanks for this great project first of all.

Can I ask you all what RPM you are using?
My 6RU Server rack is at 40 degree celsius with 100% voltage and 1150 RPM.
Might have to use a stronger fan.

Also, what causes the fan to run at 1150 RPM even though it can do 1500?

Thanks for your hep

Two Sensors

Hey Patrick

I used yours as an example to build a fan temperature control for my network cabinet. Used a WT32-ETH01.

I was thinking of using two temperature sensors. One inside and another outside. Use the one outside + x °C as the set-point. Thus doesn't matter what the room temperature it will only be a few degrees more inside the cabinet. Any thoughts?

My config at the moment based on yours:

#https://github.com/patrickcollins12/esphome-fan-controller/blob/master/console-fan.yaml

substitutions:
device_name: networkcabinet
friendly_name: "Network Cabinet"
device_ip: !secret networkcabinet_ip

###############################################################################

esphome:
name: ${device_name}
platform: ESP32
board: esp-wrover-kit

###############################################################################

preferences:
flash_write_interval: 15min

###############################################################################

ethernet:
type: LAN8720
mdc_pin: GPIO23
mdio_pin: GPIO18
clk_mode: GPIO0_IN
phy_addr: 1
power_pin: GPIO16
manual_ip:
static_ip: ${device_ip}
gateway: !secret localgateway
subnet: !secret localsubnet
dns1: !secret localdns1
dns2: !secret localdns2

###############################################################################

Enable logging

logger:

###############################################################################

Enable Home Assistant API

api:
encryption:
key: !secret apikey
ota:
password: !secret otapass

###############################################################################

Time

time:

  • platform: homeassistant
    id: esptime

###############################################################################

i2c:
sda: 33
scl: 32
scan: true
frequency: 800kHz

###############################################################################

text_sensor:

Send Uptime in raw seconds

  • platform: template
    id: uptime_human
    icon: mdi:clock-start
    internal: true

###############################################################################

switch:

  • platform: restart
    name: "${friendly_name} Reboot"

###############################################################################

sensor:

  • platform: bme280
    temperature:
    name: "${friendly_name} Amb Temp"
    id: bme280_temperature
    oversampling: 1x
    pressure:
    name: "${friendly_name} Amb Press"
    id: bme280_pressure
    humidity:
    name: "${friendly_name} Amb Hum"
    id: bme280_humidity
    address: 0x76
    iir_filter: 16x
    update_interval: 5s

RPM Signal from Fan A

  • platform: pulse_counter
    pin:
    number: 36
    name: ${friendly_name} Fan A Speed
    id: fan_a_pulse
    unit_of_measurement: 'RPM'
    filters:
    • multiply: 0.5
      count_mode:
      rising_edge: INCREMENT
      falling_edge: DISABLE
      update_interval: 5s
      accuracy_decimals: 0

RPM Signal from Fan B

  • platform: pulse_counter
    pin:
    number: 39
    name: ${friendly_name} Fan B Speed
    id: fan_b_pulse
    unit_of_measurement: 'RPM'
    filters:
    • multiply: 0.5
      count_mode:
      rising_edge: INCREMENT
      falling_edge: DISABLE
      update_interval: 5s
      accuracy_decimals: 0

Uptime

  • 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();

  • platform: template
    name: $friendly_name p term
    id: p_term
    unit_of_measurement: "%"
    accuracy_decimals: 2

  • platform: template
    name: $friendly_name i term
    id: i_term
    unit_of_measurement: "%"
    accuracy_decimals: 2

  • platform: template
    name: $friendly_name d term
    id: d_term
    unit_of_measurement: "%"
    accuracy_decimals: 2

  • platform: template
    name: $friendly_name output value
    unit_of_measurement: "%"
    id: o_term
    accuracy_decimals: 2

  • platform: template
    name: $friendly_name error value
    id: e_term
    accuracy_decimals: 2

  • platform: template
    name: $friendly_name is in deadband
    id: in_deadband_term
    accuracy_decimals: 0

###############################################################################
output:

  • platform: ledc
    id: coolingfan
    pin: 15
    frequency: 25000 Hz
    min_power: 0.2
    max_power: 1.0

###############################################################################

number:

KP

  • platform: template
    name: "${friendly_name} kp"
    icon: mdi:chart-bell-curve
    restore_value: true
    initial_value: 0.3
    min_value: 0
    max_value: 50
    step: 0.001
    set_action:
    lambda: |-
    id(${device_name}_pid).set_kp( x );

KI

  • platform: template
    name: "${friendly_name} ki"
    icon: mdi:chart-bell-curve
    restore_value: true
    initial_value: 0.0015
    min_value: 0
    max_value: 50
    step: 0.0001
    set_action:
    lambda: id(${device_name}_pid).set_ki( x );

KD

  • platform: template
    name: "${friendly_name} kd"
    icon: mdi:chart-bell-curve
    restore_value: true
    initial_value: 0.0
    min_value: -50
    max_value: 50
    step: 0.001
    set_action:
    lambda: id(${device_name}_pid).set_kd( x );

Set threshold low

  • platform: template
    name: "${friendly_name} Deadband Threshold Low"
    icon: mdi:chart-bell-curve
    restore_value: true
    initial_value: -1.0
    min_value: -20
    max_value: 0
    step: 0.1
    set_action:
    lambda: id(${device_name}_pid).set_threshold_low( x );

Set threshold high

  • platform: template
    name: "${friendly_name} Deadband Threshold High"
    icon: mdi:chart-bell-curve
    restore_value: true
    initial_value: 0.4
    min_value: 0
    max_value: 20
    step: 0.1
    set_action:
    lambda: id(${device_name}_pid).set_threshold_high( x );

Set ki multiplier

  • platform: template
    name: "${friendly_name} Deadband ki Multiplier"
    icon: mdi:chart-bell-curve
    restore_value: true
    initial_value: 0.04
    min_value: 0
    max_value: .2
    step: 0.01
    set_action:
    lambda: id(${device_name}_pid).set_ki_multiplier( x );

###############################################################################

climate:

  • platform: pid
    id: ${device_name}_pid
    name: "${friendly_name} Temp Controller"
    visual:
    min_temperature: 20.00 °C
    max_temperature: 50.00 °C
    temperature_step: 0.1 °C
    sensor: bme280_temperature
    default_target_temperature: 28.00 °C
    cool_output: coolingfan
    control_parameters:
    kp: 0.3
    ki: 0.0015
    kd: 0.0
    max_integral: 0.0
    output_averaging_samples: 1
    derivative_averaging_samples: 5
    deadband_parameters:
    threshold_high: 0.4°C
    threshold_low: -1.0°C
    kp_multiplier: 0.0
    ki_multiplier: 0.04
    kd_multiplier: 0.0
    deadband_output_averaging_samples: 15
    on_state:
    • sensor.template.publish:
      id: p_term
      state: !lambda 'return -id(${device_name}_pid).get_proportional_term() * 100.0;'
    • sensor.template.publish:
      id: i_term
      state: !lambda 'return -id(${device_name}_pid).get_integral_term()* 100.0;'
    • sensor.template.publish:
      id: d_term
      state: !lambda 'return -id(${device_name}_pid).get_derivative_term()* 100.0;'
    • sensor.template.publish:
      id: o_term
      state: !lambda 'return -id(${device_name}_pid).get_output_value()* 100.0;'
    • sensor.template.publish:
      id: in_deadband_term
      state: !lambda 'return id(${device_name}_pid).in_deadband();'
    • sensor.template.publish:
      id: e_term
      state: !lambda 'return -id(${device_name}_pid).get_error_value();'

DHT11 temperature stops updating periodically

Thanks for sharing this project. I recently set this up for my new network cabinet, but found that DHT11 temperature sensor stops updating its temp values periodically for 30-45 minutes at a time:

image

Without the temperature input, the fan speed also stays steady, then kicks up to catch up once the temperature updates again.

image

The logs during these states display the DHT11 returns the exact same value repeatedly, without error.

[00:05:14][D][sensor:094]: 'Temperature': Sending state 31.80000 °C with 3 decimals of accuracy
[00:05:14][D][sensor:094]: 'Fan Speed (PWM Voltage)': Sending state 85.48193 % with 1 decimals of accuracy
[00:05:14][D][sensor:094]: 'Humidity': Sending state 32.00000 % with 0 decimals of accuracy
[00:05:15][D][sensor:094]: 'Temperature': Sending state 31.80000 °C with 3 decimals of accuracy
[00:05:15][D][sensor:094]: 'Fan Speed (PWM Voltage)': Sending state 85.47862 % with 1 decimals of accuracy
[00:05:15][D][sensor:094]: 'Humidity': Sending state 32.00000 % with 0 decimals of accuracy
[00:05:17][D][sensor:094]: 'Temperature': Sending state 31.80000 °C with 3 decimals of accuracy
[00:05:17][D][sensor:094]: 'Fan Speed (PWM Voltage)': Sending state 85.47533 % with 1 decimals of accuracy
[00:05:17][D][sensor:094]: 'Humidity': Sending state 32.00000 % with 0 decimals of accuracy
[00:05:18][D][sensor:094]: 'Temperature': Sending state 31.80000 °C with 3 decimals of accuracy
[00:05:18][D][sensor:094]: 'Fan Speed (PWM Voltage)': Sending state 85.47204 % with 1 decimals of accuracy
[00:05:18][D][sensor:094]: 'Humidity': Sending state 32.00000 % with 0 decimals of accuracy
[00:05:19][D][sensor:094]: 'Temperature': Sending state 31.80000 °C with 3 decimals of accuracy
[00:05:19][D][sensor:094]: 'Fan Speed (PWM Voltage)': Sending state 85.46874 % with 1 decimals of accuracy
[00:05:19][D][sensor:094]: 'Humidity': Sending state 32.00000 % with 0 decimals of accuracy
[00:05:21][D][sensor:094]: 'Temperature': Sending state 31.80000 °C with 3 decimals of accuracy
[00:05:21][D][sensor:094]: 'Fan Speed (PWM Voltage)': Sending state 85.46545 % with 1 decimals of accuracy
[00:05:21][D][sensor:094]: 'Humidity': Sending state 32.00000 % with 0 decimals of accuracy
[00:05:22][D][sensor:094]: 'Temperature': Sending state 31.80000 °C with 3 decimals of accuracy
[00:05:22][D][sensor:094]: 'Fan Speed (PWM Voltage)': Sending state 85.46216 % with 1 decimals of accuracy
[00:05:22][D][sensor:094]: 'Humidity': Sending state 32.00000 % with 0 decimals of accuracy
[00:05:23][D][sensor:094]: 'Temperature': Sending state 31.80000 °C with 3 decimals of accuracy
[00:05:23][D][sensor:094]: 'Fan Speed (PWM Voltage)': Sending state 85.45885 % with 1 decimals of accuracy
[00:05:23][D][sensor:094]: 'Humidity': Sending state 32.00000 % with 0 decimals of accuracy
[00:05:24][D][sensor:094]: 'Temperature': Sending state 31.80000 °C with 3 decimals of accuracy

I have yet to look into the signal integrity on the data line from the DHT11. But I have tried to swap sensors and got similar behavior. The only other things I could think of is connecting directly to the header on the ESP rather than the 3-pin JST header, or trying shorter wires to the sensor. Is a pullup resistor required on the data line?

Any other insights would be appreciated.

constantly reboots

Hello Patrick,

thanks for that repo. It is perfect for my need to cool the technic cupboard for DSL Router, NAS and these things in my livingroom.

To customize the project for my need without homeassistant but with node-red i disabled the HA API and enabled MQTT. I tried to add a 2nd temperature sensor but whatever i did it never had a value. So trying differenz GPIOs Pins, changing the sensor or add a pullup resistance it never worked. But thats not the question.

I think, in general, i havn't changed alot in your code but the scetch is never stable. Sometimes the ESP32 is running for 10 hours, sometimes only for 15min.
The reset reason is always Software Reset CPU

Any ideas what the problem could be or how to debug it?

Thanks

[Request] Possible to use two temperature sensors?

Thanks for this repo.. the code and schematics work great for me. My prototype is working great however I have a question.. is it possible to add another DHT temperature probe? My AV cabinets have two zones and I've added a fan in each. One is for the AV Receiver (always on when using TV) and the other is for gaming consoles (only on sometimes). I'd rather not build two separate fan controllers for two compartments. I don't mind both sides spinning faster when only one zone is needing more cooling (e.g. the gaming side being cooled even if there are no consoles active).

I had to reassign the DHT to GPIO23 on my nodemcu-32s board else it wouldn't work. PWM is on GPIO15. I've looking at the code as to what would be needed to support a 2nd DHT but the code is a bit too advanced for me. Ideally it would report two temperature values to Home Assistant as well and act on the worst one. But I would be more than pleased to get the worst value of the two as well. (one being 29c and the other 35c.. having it act like it's 35c and adjust fan accordingly).

Could you help with this? Many thanks.

make fan stop spinning at zero

Hello, I just installed a Corsair ML120 fan as you say and it works well except for the one when it reaches the stop temperature and it keeps turning at 1400 RPM. Could you help me create a stop or what parameters can I change to make it stop? the adjustments that you had at 13% the stop changed it to 0% but it continues turning. could you help me?? thank you.

3 wire fan

Hi, is it going to operate with 3 wire fan? I have two of these and would lik to try. I assume the fourth pin that is missing is tachometer pin,so i will miss the feedback

Fritzing Img ESP Pinouts?

Hi @patrickcollins12 - thanks for the awesome project! This has been on my to-do list for months, although I'm intending to modify it (or at least try to!) to control speed with humidity (drying cupboard use-case!)... Although just noticed I'm also going to have the 0% PWM / fan off issue too...

However, just as I was about to get going, it seems that the Fritzing diagram of the ESP pinouts don't match my ESP (Firebeetle), is the diagram intended to be correct or is it more a rough guide and should follow the descriptions? For example, your description and code use GPIO25, but I don't believe that's the pin shown on the fritzing?

Thanks again...

+/- in wiring

Hi, awesome little project !

But for me it looks like your schematic has a little error with plus and minus switched on the stepdown side and the bridge to ground on 3.3...
2022-05-10_16-09
s

Set the target temperature from an automation

I installed your fan-project in my NAS cabinet with two compartments. I have the temperature sensor at the top, because that's where my NAS is, which runs during the day. Below I have my backup NAS and my Raspberry.
I know, I just can install a second thermostat and use it. But I just want to monitore the system and HDD temperatures and want to set the PWM to ~100% or the target temperature to 20° just in case of an emergency. I don't think I'll need it, but having is better than needing.
So I wanted to ask if I can change the PWM. Since it would probably be constantly overwritten by the controller, lowering the target temperature is probably a better choice.
However, I couldn't find it. Is there a way to do this that I've just overlooked?

Thanks in advance!

No longer able to compile.

I was trying to change some of the code and whenever i try to upload to the esp i get the following error.. it happens on 2 different boards. i also would like to make another one but cant if it wont upload. could you provide any help? i love this project and i get ALOT of use out of it.

I think it happened after an update and i feel like a url or dependency is no longer available.im completely unsure,

Processing aquariumcooler (board: esp32dev; framework: arduino; platform: platformio/espressif32 @ 5.2.0)

HARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash

  • toolchain-xtensa-esp32 @ 8.4.0+2021r2-patch3

warning: Calling missing SConscript without error is deprecated.
Transition by adding must_exist=False to SConscript calls.
Missing SConscript '/data/cache/platformio/packages/framework-arduinoespressif32/tools/platformio-build.py'
File "/data/cache/platformio/platforms/espressif32/builder/frameworks/arduino.py", line 41, in
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
Library Manager: Installing FS
Warning! Could not find the package with 'FS' requirements for your system 'linux_x86_64'
Library Manager: Installing Update
Warning! Could not find the package with 'Update' requirements for your system 'linux_x86_64'
Library Manager: Installing ESPmDNS
Warning! Could not find the package with 'ESPmDNS' requirements for your system 'linux_x86_64'
Dependency Graph
|-- AsyncTCP-esphome @ 1.2.2
|-- WiFi @ 1.2.7
|-- ESPAsyncWebServer-esphome @ 2.1.0
| |-- AsyncTCP-esphome @ 1.2.2
|-- DNSServer @ 1.1.0
|-- noise-c @ 0.1.4
| |-- libsodium @ 1.10018.1
Compiling /data/aquariumcooler/.pioenvs/aquariumcooler/src/esphome/components/adc/adc_sensor.cpp.o
Compiling /data/aquariumcooler/.pioenvs/aquariumcooler/src/esphome/components/api/api_connection.cpp.o
In file included from src/esphome/components/adc/adc_sensor.h:4,
from src/esphome/components/adc/adc_sensor.cpp:1:
src/esphome/core/hal.h:14:10: fatal error: esp_attr.h: No such file or directory



#include <esp_attr.h>
^~~~~~~~~~~~
compilation terminated.
*** [/data/aquariumcooler/.pioenvs/aquariumcooler/src/esphome/components/adc/adc_sensor.cpp.o] Error 1
In file included from src/esphome/components/socket/socket.h:5,
from src/esphome/components/api/api_frame_helper.h:13,
from src/esphome/components/api/api_connection.h:3,
from src/esphome/components/api/api_connection.cpp:1:
src/esphome/components/socket/headers.h:116:10: fatal error: sys/ioctl.h: No such file or directory
#include <sys/ioctl.h>
^~~~~~~~~~~~~
compilation terminated.
*** [/data/aquariumcooler/.pioenvs/aquariumcooler/src/esphome/components/api/api_connection.cpp.o] Error 1
========================== [FAILED] Took 1.99 seconds ==========================

One console with two separate connected fans

Hello,

first of all respect and thanks for the guide! It was fun building it.
I connected two fans (one for in, one for out) to different pins. - I know I could have just soldered them together, but I didn't want to. - I can now control both separately and also get all sensor values output separately.

But I would like to specify only one target temperature value via the console and this should be given to both output IDs.

Is this possible? As far as I understand, I would have to specify both IDs of the "cool_output" here in the code. But I can't find the syntax for it.

climate:
  - platform: pid
    name: "Console Fan Thermostat Out"
    id: console_thermostat_out
    sensor: console_fan_temperature

    # It is summer right now, so 30c is a decent target.
    default_target_temperature: 30°C
    cool_output: console_fan_speed

Manual and thermostat fan control

Hi Patrick @patrickcollins12 ,
I am new to Github and I am not sure, whether this is the right place to ask you this.
I had been using your project quite successfully a few weeks ago (I want to use the warm air from an PV-inverter to warm my PV battery during the cold and humid winter months in my garage). I had uncommented the part for the manual control of the fan speed and - as you said in the readme - switched OFF the thermostat when I wanted to control the fan manually. This worked well until a few days ago. Now, even when I switch the thermostat OFF, the manual control only gives a short increase in rpm and then the rpm of the fan go back to zero, as if the thermostat was not switched OFF. I suspect that there was an update of the platforms somewhere which broke this. If I delete all the thermostat code from your project, I can control the fan manually without problems as before. Do you have any advise how I can have the option again to use both thermostat and manual control together as before?
Thank you very much for this project. It's my first Home Assistant/ESPHome project and I am having fun because of your great work.
Klaus

Tacho connection in documentation

Hi, isn't there a mistake in the documentation? You mean that the green line is the rpm sensor that needs one GPIO per fan but the green line seems to be the PWM in fact (as it is connected together from both fans to one GPIO). IMHO the blue one seems to be the rpm sensor on the picture.

Fan Connector Type Doesn't Seem Right

I wanted to do this project to cool my electronics closet. I'm not an EE and haven't done electronics in ages so I could be wrong about this.

I bought the same Corsair fans as you specified (LM 120). In you image, you specify a JST connector. My research shows that the connector on the fan connects to a Molex 0470531000. It has a 2.54mm pitch as opposed to the 2.5mm of the JST connectors. There appear to be 4 different types, all 2.5mm. I'm going to go with the Molex as I'm going to build it on a solder breadboard.

The other confusing item is the pin out for the fan. Your wiring diagram shows using the first three pins. The third pin is Tach. In you description, you mention not using this. The web documentation I've found says pin 4 is control/PWM. I'm assuming that's the one you meant.

Thanks for posting this project. I've been thinking about how I could do something similar for quite some time. Now I have a solution.

This is so cool! But...couple of questions?

Hi,

I have this running to control three fans on my inverter. Soon I will expand to cover a second inverter with a second set of fans (once I move out of breadboard stage). You made it so super easy to get up and running!

Question 1:
The main issue with inverter cooling is that I need a responsive cooling system but one that is skewed - I need a fast(ish) response and the long slow tail....is this where kd comes in?

Question 2:
I have a DHT dangling over the back of the inverter radiator to read the air temperature, but really I need something better to read the radiator fin temperature directly, or a way of pushing the inverter internal temperature (which HA knows) to the fan controller...but with the option to still use DHT incase HA fails for some reason. That is, use inverter internal temp reading and if null revert to DHT temperature. Is this possible? if so how the heck could I pull that off?

Question 3:
I'd really like to bring in the tachometer data so that I can detect fan failure. I can do all the logic in HA/NodeRed, just need to plumb up the pins and get a reading....any tips? I've seen a few ways of doing it with resistors, logic level shifters, capacitors etc....but it seems a little complicated? From the looks of things I have exactly the same fans as you... :-)

Thanks heaps!

CP.

Fan Override does not work

When setting the Fan to On (while disabling the thermostat) and setting a value the fans do spin up but go down again as soon as the next temperature reading comes in. So the override does not seem to be stable or I am doing it wrong?

question about external temperature instead of built in dht

hi, this project is cool
I am not super fluent in ESPhome - would someone help me modifying the code so that PID controller reacts on external temperature provided by the sensos that is already on Home Assistant, i.e. entity_id: sensor.external_cpu_temperature

I am not sure where in this yaml to include the temperature provided by this sensor (external_cpu_temperature) - it will be provided every few seconds if that matters.

thank you

Additional fans

Not sure this is an issue as I haven't actually started work on it. But I want to be able to connect 3 pwm fans and be able to read their rpm etc.

I have looked over the yaml and I assume I just copy the portion of code that specifies the ledc platform but change the gpio

If any one has a config for 2 or more fans that would be amazing.

Offset ?

I have finished my solar batter heater design and it's been running for several days now. The only issue I see is the offset.

5A650EA7-98A8-4C18-80E6-CECB2C4184FC

I've tried various values and none seem to make any difference... so I just set the temp 2-3 degrees above where I want it. So strange.

9DFEB570-FC21-43A0-9149-BF33D019D270

I have 2 sensors, a probe that always works but isn't exact and the actual BMS temp as a primary. if the BMS temp becomes unavailable (Solar Assistant Pi crashes, HA crashes,etc), the probe temp is used instead. Everything is contained within the esp and ESPHome.

overall I'm very happy with the results!

Cool project!

Nice job on this! I'm totally stealing your PID efforts for 2 of my projects.

The first (and easier) is for my solar battery heaters. I just finished getting a dimmer circuit working for 4 heating pads.
https://diysolarforum.com/threads/new-battery-heater-controller-home-assistant-and-esphome.53665/
I just got the ESPHome file to compile with all your PID stuff and added all the sensors to home assistant. It's late and I'll head to my shop in the AM to try and understand how this cool PID controller works.

The second, and far more advanced use case, is for my Smart Wood Pellet Stove project. I finally have victory over this pellet stove after a year of slogging it to make it actually smart with 685 lines of ESPHOME code to control every aspect of it.
https://github.com/jazzmonger/wood-stove-with-TYWE1S-Tuya-chip

My plan is to employ the PID component to control the Auger feed motor control for the pellets to barely keep the stove lit so the house doesn't overheat and the stove doesn't have to cycle on and off, requiring constant relighting and burning out $50 igniters every few months. In the graph, you can see the fire burning and cooling and burning and cooling, etc, etc as pellets are added and then backed off.

The idea is to maintain a constant LOW target burn temp that I can set. Minimum is about 190C, which I've found by trial and error and keeps the stove on. This barely keeps the pellets burning and minimal heat output, perfect as the weather gets gradually warmer outside. I'd increase that a bit when outside temps drop and the stove has to work harder to keep the room warm.
249CD219-F5FC-469B-9C39-93AE2DDF463C

jazzmonger/wood-pellet-stove-with-TYWE1S-Tuya-chip#28

I'm pondering what params to play with to use for the PID control line.
I have a few options:
Auger on time ( this is tricky as too little and fire goes out, too much and u get smoke)
Auger off time - how long before more pellets are added
Stoking temp - how low the exhaust temp goes before manually stoking the fire w more pellets

I you have any thoughts on this after the dozens of hours you probably spent on figuring out the PID stuff, I'm all ears!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.