šŸ’Ø Adaptive fan speed control based on temperature and speed range

This blueprint automates speed control of your fans in relation to your chosen temperature range and fan speed range. A large part of this has been copied from another blueprint made by @MickW69. However it was missing some key elements I thought worthy to add. And I have changed how the mapping is done between the temp_range and the fan_speed_range. The original blueprint can be found here. All credit for the idea and original code should go to Mick. Thanks mate!

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

The new set_fan_speed equation is caculated as follows:

image

Currently tested on an EspHome fan with percentage step control.

Features:

  • The speed is calcualted and set each time the the fan is turned on.
  • A customizable delay is used to avoid changing the fan too frequently.
  • A minimum percent change can be set to avoid continuously adjusting.
  • A maximum percent change can be set to avoid huge % changes in your fan speed.
  • A blocking entity can be used (with an input_boolean) to block the automation from running.

A note on the max percentage change variable:

To ensure the set_fan_speed value never increases or decreases by more than a desired threshold, you can set a max_change which is a threshold value set for the difference betwen the current fan_speed and the calculated set_fan_speed. If the difference exceeds max_change, the set_fan_speed will be adjusted to fan_speed + max_change (for the positive direction) or fan_speed - max_change (for the negative direction) as necessary.

IMPORTANT!
Because the automation is triggered only when the temperature sensor changes or when the fan is turned on, if you have set a small max_change and the time between temperature changes is large, the time it takes for the fan to get the set_fan_speed could be large.

Min and Max temperatures

Min and Max temperature values for the slider inputs are now between 10 and 120 (unitless) for each slider input. This allows C and F temp sensors to be used and slider inputs to set a value well within any reasonable range (I hope :joy:)

Please note:
Make sure the temperature sensor you use is in the units (Ā°C or Ā°F) you want to use for the input sliders. If your temp sensor is in Ā°C but you want to use the Ā°F settings, you will need to create a template sensor to convert the sensor into the correct units.

:shield: MY OTHER BLUEPRINTS
:white_check_mark: Input Boolean Toggle Actions

blueprint:
  name: Auto fan speed
  description: "Temperature based Auto fan control.\n\n Fan Speed will be set when
    initially turned on by relating the ambient temperature to an equivalant speed
    setting. \nA time delay and a minimum percentage change is used to eliminate 
    frequent speed changes.\n At the minimum temperature setting the fan will turn 
    off. \n When the temperature rises above this minimum temperature setting, the 
    fan will automatically turn back on."
  domain: automation
  input:
    temp_sensor:
      name: šŸŒ” Temperature Sensor
      description: Enter your temperature sensor. Make sure the temperature sensor is in the units (Ā°C or Ā°F) you want to use for the settings below. 
        If your temp sensor is in Ā°C but you want to use the Ā°F settings, you will need to create a template sensor to convert the sensor into the correct units. 
      default: []
      selector:
        entity:
          domain:
          - sensor
          device_class:
          - temperature
          multiple: false
    fan_switch:
      name: šŸ’Ø Fan
      description: The fan you wish to speed control.
      selector:
        entity:
          domain:
          - fan
          multiple: false
    min_fan_speed:
      name: šŸ’Ø Minimum Fan Speed
      description: Set the minimum percentage speed when your fan is still on.
      default: 16
      selector:
        number:
          min: 1.0
          max: 100.0
          mode: slider
          step: 1.0
          unit_of_measurement: '%'
    max_fan_speed:
      name: šŸ’Ø Maximum Fan Speed
      description: Set the maximum percentage speed for your fan.
      default: 100
      selector:
        number:
          min: 1.0
          max: 100.0
          mode: slider
          step: 1.0
          unit_of_measurement: '%'
    max_temp:
      name: šŸ“ˆ Maximum Temperature
      description: What temperature would you like the fan to run at max fan speed.
      default: 40
      selector:
        number:
          min: 10.0
          max: 120.0
          step: 1.0
          mode: slider
    min_temp:
      name: šŸ“‰ Minimum Temperature
      description: What temperature would you like the fan to run at minimum speed.
      default: 23
      selector:
        number:
          min: 10.0
          max: 120.0
          step: 1.0
          mode: slider
    off_temp:
      name: šŸ›‘ The temperature the fan switches off
      description: What temperature would you like the fan to turn off? When the temperature falls below this value, 
        the fan turns off. When the temperature rises above this value, the fan will automatically turn back on 
        (unless you disable this via the "Enable auto fan on" setting). 
      default: 22
      selector:
        number:
          min: 10.0
          max: 120.0
          step: 1.0
          mode: slider

    auto_turn_on_enabled:
      name: āœ… Enable auto fan on 
      description: Let the fan automatically turn back on if the temperature returns to a value above the temperature that the fan switches off
      default: true
      selector:
        boolean: {}
    change_time:
      name: ā±ļø Change frequency delay
      description: How long to delay bewteen potential speed adjustments.
      default: 30
      selector:
        number:
          min: 1.0
          max: 120.0
          unit_of_measurement: minutes
          step: 1.0
          mode: slider
    change_threshold:
      name: Minimum percentage change
      description: The minimum percentage change (between current fan speed and set
        fan speed)
      default: 1
      selector:
        number:
          min: 1.0
          max: 100.0
          mode: slider
          step: 1.0
          unit_of_measurement: '%'
    max_change:
      name: Maximum percentage change
      description: The maximum percentage change (between current fan speed and set
        fan speed)
      default: 50
      selector:
        number:
          min: 1.0
          max: 100.0
          mode: slider
          step: 1.0
          unit_of_measurement: '%'
    blocker_entity:
      name: (OPTIONAL) Blocking entity
      description: If this entity's state is on, it will prevent the automation from running. E.g. sleepmode or away mode.
      default:
      selector:
        entity:
          multiple: false

  source_url: https://community.home-assistant.io/t/adaptive-fan-speed-control-based-on-temperature-and-speed-range/678152
variables:
  temp_sensor: !input temp_sensor
  fan_switch: !input fan_switch
  auto_turn_on_enabled: !input 'auto_turn_on_enabled'

  min_fan_speed: !input min_fan_speed
  max_fan_speed: !input max_fan_speed

  max_temp: !input max_temp 
  min_temp: !input min_temp
  off_temp: !input off_temp

  change_time: !input change_time
  max_change: !input max_change
  change_threshold: !input change_threshold
  blocker_entity: !input blocker_entity
  current_temp: "{{ states(temp_sensor) | float(0)}}"
  fan_speed: '{{ state_attr(fan_switch,''percentage'') | float(0)}}'
  temp_range: '{{max_temp | float(0)-min_temp | float(0)}}'
  fan_range: '{{max_fan_speed | float(0) - min_fan_speed | float(0)}}'
  slope: '{{fan_range | float(0)/temp_range | float(0)}}'
  initial_set_fan_speed: '{{ [[slope|float(0) * (current_temp|float(0) - min_temp|float(0)) + min_fan_speed|float(0),  min_fan_speed] | max, max_fan_speed] | min}}'
  adjusted_set_fan_speed: >
    {% set diff = initial_set_fan_speed - fan_speed %}
    {% if diff > max_change|float(0) %}
      {{ fan_speed + max_change|float(0) }}
    {% elif diff < -max_change|float(0) %}
      {{ fan_speed - max_change|float(0) }}
    {% else %}
      {{ initial_set_fan_speed }}
    {% endif %}
  set_fan_speed: '{{ adjusted_set_fan_speed }}'
  speed_diff: '{{(fan_speed - set_fan_speed)|abs}}'
trigger:
- platform: state
  entity_id:
  - !input fan_switch
  id: fanon
  from: 'off'
  to: 'on'
- platform: state
  id: temp_state_change
  entity_id:
  - !input temp_sensor
condition:
- condition: template
  alias: Check for blocker entity
  value_template: '{{ (blocker_entity == none) or (states(blocker_entity) == ''off'')}}'
action:
- choose:
  - conditions:
    - condition: trigger
      alias: Only run if fan was switched on 
      id: fanon
    - condition: template
      alias: Is the percentage change great enough? 
      value_template: '{{ speed_diff | float(0) > change_threshold | float(0) }}'
    sequence:
    - service: homeassistant.turn_on
      data:
        percentage: '{{set_fan_speed}}'
      target:
        entity_id: '{{fan_switch}}'
    - delay:
        minutes: !input change_time
  - conditions:
    - condition: template
      value_template: '{{states(fan_switch) == ''on''}}'
      alias: Make sure the fan is already on (ignore if it's been switched off)
    - condition: template
      alias: Is the percentage change great enough? 
      value_template: '{{ speed_diff | float(0) > change_threshold | float(0) }}'
    - condition: template
      alias: Is the temperature above the off temp? 
      value_template: '{{ current_temp | float(0) > off_temp | float(0) }}'
    sequence:
    - service: homeassistant.turn_on
      target:
        entity_id: '{{fan_switch}}'
      data:
        percentage: '{{set_fan_speed}}'
    - delay:
        minutes: !input change_time
  - conditions:
    - condition: not
      alias: Make sure the fan hasn't just been turned on 
      conditions:
      - condition: trigger
        id: fanon
    - condition: numeric_state
      entity_id: !input temp_sensor
      below: !input off_temp
    sequence:
    - service: homeassistant.turn_off
      target:
        entity_id: '{{fan_switch}}'
  - conditions:
    - '{{ auto_turn_on_enabled }}'
    - condition: template
      value_template: '{{states(fan_switch) == ''off''}}'
      alias: Is the fan currently off?  
    - condition: template
      alias: Is the temperature above the off temp? 
      value_template: '{{ current_temp | float(0) > off_temp | float(0) }}'
    sequence:
    - service: homeassistant.turn_on
      data:
        percentage: '{{set_fan_speed}}'
      target:
        entity_id: '{{fan_switch}}'
    - delay:
        minutes: !input change_time
mode: single


7 Likes

Interesting.
Donā€™t know if you knew this existed, but it might be interesting to consider if it helps you here or not.

1 Like

Interesting integration. I didnā€™t know no. Also not sure itā€™s relevant to this blueprint? Did you have something specific?

I think it draws the line for you and provides a value for Y based on the given value for X. I think thatā€™s what your math is doing in a straight line.
I donā€™t know, I havenā€™t used this but it looked like a way to do it if you donā€™t want an exactly linear responseā€¦
A lot of fans have little or no blow at low speed, especially ceiling fans, so when the temp is in the 20-30 % level, maybe the fan should start at medium earlier than 33% and then shift high down as well to like 60% temp. Nonlinear kind of thingā€¦

Thatā€™s an interesting idea! Iā€™m not sure I personally need it for my use case. But Iā€™d be happy to look into it if someone wanted this implemented.

Just looking at that Compensation Intergration you linked earlier and it indeed appears to do something similar to what my math already does. At this stage I donā€™t see a reason to make use of it though because itā€™s most likely implementing a linear regression algorithm to solve for the coefficients. Which in this case is a bit too heavy handed.

Cool find though. Iā€™ll keep it in mind for anything else

1 Like

Heavy handed, probably, but it should be fun to play with.

What would be required to put this in fahrenheit?

@PaulChicago
Well actually, as long as your temperature sensor is in Fahrenheit, and you set all the inputs for each selector as if they were in Fahrenheit too, the equation will work the same. The issue is going to be that the selectors have max/min that is probably going to be out of range when trying to use them for Fahrenheit values.

So if you wanted to tweak it to suit yourself, must take a copy of the yaml and change the selector inputs max/min values to better suit a Fahrenheit value. EG:

    max_temp:
      name: What temperature would you like the fan to run at max fan speed.
      description: Set the high temperture sensor value (degC).
      default: 31
      selector:
        number:
          min: 15.0
          max: 40.0
          step: 1.0
          mode: slider

Might become something like:

    max_temp:
      name: What temperature would you like the fan to run at max fan speed.
      description: Set the high temperture sensor value (degC).
      default: 31
      selector:
        number:
          min: 60.0
          max: 140.0
          step: 1.0
          mode: slider

which is just the approximate conversion from degC to Fahrenheit. You would just need to do that for each them. And thatā€™s it.

This is super convenient and fits venting my hot technical room. Any chance to have fan auto on as an option as well?

1 Like

Glad to hear you found it helpful! Could you explain what you mean by ā€œauto onā€? Do you mean have the fan turn on when HA starts? or something else?

For my use case, it would be nice to have the fan turn on by itself at a set temperature, then adapt fan speed to keep the temperature within min and max. For example, when the room temperature reaches 23 C, then fan turns on by itself. If the room temperature drops below 23, then it turns off. I can of course have another automation turn the fan on, but it would be nice to have one automation take care of it.

1 Like

@egiljae yeah awesome. Well the blueprint did already automatically turn off the fan when the temperature fell below the temp_off value (see the setting What temperature would you like the fan to turn off.). However it didnā€™t turn it back on.

Youā€™ll be pleased to know that I have just added this functionality. Now the temp_off value is used to check if the fan should be turned off OR back on again. Let me know how you go with the testing of this and feed back to me any issues :slight_smile:

Regarding upgrading the blueprint to the latest changes: just re-import the blueprint above and all settings should be copied across to your existing automations already using this blueprint.

1 Like

Will definitely try this controlling my cooling fan.

Would be cool if you could use a helper input number to set the target temperature. That way you could set the desired temp from your dashboard.

When you say target temperature do you mean the max-temp, the min-temp or the off-temp? or all three? See below for descriptions of each.

I mean the off-temp. And maybe have the min-temp and max-temp as offsets from off-temp. So you could enter for example +1 for min temp and +2 for max temp and 20 for off-temp in the blueprint. That would turn on (and off) the fan at, for example 20 degrees, run at maximum att 22 and minimum at 21.

Thinking of it now, do you really need a minimum temp? Isnā€™t that the same as the off(on)-temp? If you set off-temp, the fan would start at minimum speed when passing the set value or maybe Iā€™m misunderstanding.

This sounds like a very specific use case. Iā€™d be happy to work on a separate blueprint if you really want this feature? Or if there is enough interest in something like this?

The minimum temp is different from the off temp because it allows the user to map the rate of the fan speed increase/decrease to the rate of the temperature increase/decrease. The off temp could be significantly lower than the min temp. In this way, the fan will simply stay at that lowest speed setting even as the temperature continues to fall below the min temp. It will remain on until it reaches the off temp. Thereā€™s many cases where the user may not want the fan to switch off at the minimum temperature.

Yeah maybe it is. My thought was that it could work like you set the temperature on you wall thermostat and the fan ā€œcurveā€ (min-temp and max-temp) is moved up or down relative to the chosen temperature. I will try and see if I can try and change it myself but my skills are very basic so I might ask for help :slight_smile:

Yeah absolutely! Give it a crack and let me know how you go. Out of interest, what is your use case? What are you planning or thinking of using this blueprint for?

I will use it to control my fan convector for cooling. I tried your blueprint and it seems to work great.

I tried changing it to use input helpers but canā€™t get it to work.
I created one ā€œinput_number.ac_tempā€ helper that I use to set the desired temperatur.
Then I created two template sensors that just adds 1 and 3 degrees to ā€œinput_number.ac_tempā€ {{ states('input_number.ac_temp') | float(0) + 1}}

I then use these in the modded BP.

The problem is the automation wonā€™t trigger. If I use the original BP it triggers on temp_sensor variable but not in my modified. And I havenā€™t changed the temp_sensor.

    max_temp:
      name: What temperature would you like the fan to run at max fan speed.
      description: Set the high temperture sensor value.
      selector:
        entity:
          multiple: false
    min_temp:
      name: What temperature would you like the fan to run at minimum speed.
      description: Set the low temperture sensor value.
      selector:
        entity:
          multiple: false
    off_temp:
      name: What temperature would you like the fan to turn off.
      description:
        When the temperature falls below this value, the fan turns off.
        When the temperature rises above this value, the fan will automatically turn
        back on (unless the blocking entity is turned on).
      selector:
        entity:
          multiple: false

The change you made to turn the fan back on again. How can I disable that aspect? I would prefer the fan to stay off when temperatures reach the off temp. I can manually turn back on the next day when Iā€™m using the room again.