đź’¨ 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 blocking entity can be used (with an input_boolean) to block the automation from running.
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.
      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: What temperature would you like the fan to run at max fan speed.
      description: Set the high temperture sensor value.
      default: 31
      selector:
        number:
          min: 15.0
          max: 50.0
          step: 1.0
          mode: slider
    min_temp:
      name: What temperature would you like the fan to run at minimum speed.
      description: Set the low temperture sensor value.
      default: 23
      selector:
        number:
          min: 15.0
          max: 45.0
          step: 1.0
          mode: slider
    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). 
      default: 21.5
      selector:
        number:
          min: 15.0
          max: 50.0
          step: 1.0
          mode: slider
    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: '%'
    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:
  change_time: !input change_time
  min_temp: !input min_temp
  off_temp: !input off_temp
  max_temp: !input max_temp
  min_fan_speed: !input min_fan_speed
  max_fan_speed: !input max_fan_speed
  temp_sensor: !input temp_sensor
  fan_switch: !input fan_switch
  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)}}'
  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}}'
  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 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
      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:
    - 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
      above: !input off_temp
    sequence:
    - service: homeassistant.turn_on
      data:
        percentage: '{{set_fan_speed}}'
      target:
        entity_id: '{{fan_switch}}'
    - delay:
        minutes: !input change_time
mode: single

4 Likes

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

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