Start with a running fan, then adjust its speed
To set Home Assistant fan speed by temperature, use the built-in fan.set_percentage action with a room-temperature reading and a visible Auto speed switch. First confirm your fan accepts speed commands. Then rehearse the two-speed rule below before connecting it to the real device.
The household turns the fan on when someone wants a breeze and off when they leave. While Auto speed is enabled, Home Assistant chooses a slower or faster speed. There is no automatic start merely because the room is warm, and no temperature-based shutoff. That makes the controls easier to explain: the fan switch controls the motor; Auto speed controls who chooses the speed.
A circulating fan helps a person feel cooler; it does not refrigerate the room. Do not expect the thermometer to fall until the fan shuts itself off. The Department of Energy’s cooling guide (PDF) distinguishes room air circulation from cooling the building. Bathroom extraction belongs in our separate humidity-controlled bathroom fan guide.
Researched from current Home Assistant documentation on October 31, 2026. The example is a configuration walkthrough, not a tested fan installation. No noise, airflow, energy-saving or response-time measurements are claimed. The cover is an illustration.
1. Check the existing fan’s capabilities
An entity is a named control or reading in Home Assistant, such as fan.office. Its integration is the connection that makes it available. You need permission to create helpers and automations, an existing room sensor, and a fan already connected through an integration that supports speed control. The built-in helpers and actions below require no paid license or extra app.
On a phone, scroll sideways inside the table.
| What you have | Decision | Check first |
|---|---|---|
| A fan entity with a working speed slider and reliable on/off feedback | Use this routine. | Identify two accepted percentage values and verify physical changes appear in Home Assistant. |
| Only an on/off switch, including a smart plug | This speed routine does not apply. | Follow the appliance’s supported controls. Do not substitute a light dimmer or improvise motor wiring. |
| Only preset choices such as Auto or Breeze | Use the supported preset path or the fan’s own controls. | A preset is not a promise of percentage speed control. |
| An air conditioner’s fan mode | Use its climate integration’s documented controls. | HVAC fan modes are separate from a standalone fan entity. |
| A remote-control bridge that guesses the fan’s state | Do not rely on this routine to preserve a physical off command. | Without reliable feedback, a displayed “on” can be wrong. Prefer explicit manual control. |
Home Assistant represents supported speeds as percentages, but a three-speed fan still has three speeds. A request for 40% does not create a fourth motor setting. Presets can also control speed themselves. These distinctions follow the fan entity contract; check the documentation for your particular integration before enabling the routine.
2. Choose two speeds and two temperature boundaries
This example uses 33% and 100% for a hypothetical three-speed room fan. Those are demonstration settings, not universal comfort recommendations. Later, replace them with the two values your fan actually accepts and reports.
- Above 25.5°C: request the faster speed.
- Below 24.5°C: request the slower speed.
- From 24.5°C through 25.5°C, including both exact boundaries: keep the current speed.
This gap prevents small temperature changes near 25°C from repeatedly switching speeds. That behavior is called hysteresis. Our Threshold helper guide explains the same idea for a reusable on/off status; this routine compares the reading directly and keeps the fan’s reported speed inside the gap.
Match the numbers to the source reading’s unit. For a Fahrenheit sensor, the equivalent boundaries are 76.1°F and 77.9°F. The templates below compare numbers; they do not convert units automatically. On restart inside the gap, the routine leaves whatever speed the fan reports, rather than restoring an earlier preference.
3. Rehearse without controlling a real fan
A helper is a virtual control stored in Home Assistant. This rehearsal changes only a number helper. Keep these demo helpers out of existing groups, labels and routines that control equipment.
- Go to Settings → Devices & services → Helpers → Create helper. Create two Toggle helpers named Fan demo running and Fan demo auto. Keep both off initially.
- Create a Number helper named Fan demo temperature, minimum 15, maximum 35, step 0.1, unit °C. Set it to 24.
- Create another Number helper named Fan demo speed, minimum 0, maximum 100, step 1, unit %. Set it to 33. Put all four helpers on a dashboard so you can see their changes.
- Open Settings → Automations & scenes, create a new empty automation, and use its menu’s Edit in YAML option. Paste the rehearsal below and replace example entity IDs with the actual IDs shown in your helper settings. Save it. Menu wording can differ across releases.
- Turn both demo toggles on and follow the table in order. Change the helpers themselves to trigger the automation; do not use Run actions, which is not a test of its triggers and top-level conditions.
The Number helper supplies the pretend temperature and displayed speed. The Toggle helpers stand in for a running fan and permission to adjust it.
On a phone, scroll sideways inside the code box and copy the entire example.
Helper-only rehearsal YAML
alias: Fan speed temperature rehearsal
mode: restart
triggers:
- trigger: state
entity_id: input_number.fan_demo_temperature
to: null
- trigger: state
entity_id:
- input_boolean.fan_demo_running
- input_boolean.fan_demo_auto
to: "on"
- trigger: homeassistant
event: start
- trigger: time_pattern
minutes: "/5"
conditions:
- condition: state
entity_id: input_boolean.fan_demo_auto
state: "on"
- condition: state
entity_id: input_boolean.fan_demo_running
state: "on"
actions:
- variables:
temperature: "{{ states('input_number.fan_demo_temperature') }}"
current_speed: "{{ states('input_number.fan_demo_speed') }}"
low_speed: 33
high_speed: 100
- condition: template
value_template: >-
{{ is_number(temperature) and is_number(current_speed) }}
- variables:
requested_speed: >-
{% if temperature | float > 25.5 %}
{{ high_speed }}
{% elif temperature | float < 24.5 %}
{{ low_speed }}
{% else %}
{{ current_speed | float }}
{% endif %}
- condition: template
value_template: >-
{{ ((requested_speed | float) -
(current_speed | float)) | abs > 2 }}
- condition: template
value_template: >-
{{ is_state('input_boolean.fan_demo_auto', 'on') and
is_state('input_boolean.fan_demo_running', 'on') }}
- action: input_number.set_value
target:
entity_id: input_number.fan_demo_speed
data:
value: "{{ requested_speed | int }}"
Expected results from the rule, not measurements from hardware. Wait for each result before continuing.
| Step | Change | Expected demo speed |
|---|---|---|
| 1 | Both toggles on; temperature 24°C; starting speed 33% | 33% |
| 2 | Temperature to 25.5°C, then 25.6°C | 33% at 25.5; 100% at 25.6 |
| 3 | Temperature back to 25°C, then 24.5°C | 100% at both values |
| 4 | Temperature to 24.4°C | 33% |
| 5 | Auto off; set speed to 67%; temperature to 26°C | 67%; pause prevents a new command |
| 6 | Auto on, while Running remains on | 100%; enabling Auto rechecks the current temperature |
| 7 | Running off; set speed to 0%; temperature to 24°C | 0%; no restart of an off fan |
The Running toggle does not itself change the demo speed; it only stands in for the real fan’s on/off report. Step 7 therefore sets both values explicitly. If a row fails, inspect the automation’s trace before connecting equipment. A trace is the record of which trigger, conditions and actions ran.
4. Connect the rule to one room fan
- Disable the rehearsal automation. Leave its helpers separate from the real routine.
- Create a Toggle helper called Office fan auto speed and turn it off. In the current documented UI, expand More options → Each time Home Assistant starts and choose Turn off if you want to re-enable Auto deliberately after a restart. This startup setting does not turn the helper off now; do both steps. Pausing leaves the motor and its present speed alone.
- Confirm the actual controls. With someone in the room, use the fan’s supported controls to select a comfortable lower and higher speed. Check that Home Assistant reports both correctly, and that turning the fan off physically changes its entity to off. Stop here if feedback is unreliable.
- Create a separate live automation using the code below. Replace
sensor.office_temperature,fan.officeandinput_boolean.office_fan_auto_speedeverywhere with your actual IDs. Setlow_speedandhigh_speedto accepted reported values; adapt both temperature numbers if your sensor uses Fahrenheit. - Check every target and keep Auto speed off while saving. Then turn the fan on normally, enable Auto speed and observe it. Above the upper boundary it should select the higher speed; below the lower boundary it should select the lower speed; in the gap it should leave the speed alone. Pause Auto before making further manual adjustments.
Live fan automation YAML — review targets before enabling Auto speed
alias: Office fan automatic speed
mode: restart
triggers:
- trigger: state
entity_id: sensor.office_temperature
to: null
- trigger: state
entity_id:
- fan.office
- input_boolean.office_fan_auto_speed
to: "on"
- trigger: homeassistant
event: start
- trigger: time_pattern
minutes: "/5"
conditions:
- condition: state
entity_id: input_boolean.office_fan_auto_speed
state: "on"
- condition: state
entity_id: fan.office
state: "on"
actions:
- variables:
temperature: "{{ states('sensor.office_temperature') }}"
current_speed: "{{ state_attr('fan.office', 'percentage') }}"
low_speed: 33
high_speed: 100
- condition: template
value_template: >-
{{ is_number(temperature) and is_number(current_speed) }}
- variables:
requested_speed: >-
{% if temperature | float > 25.5 %}
{{ high_speed }}
{% elif temperature | float < 24.5 %}
{{ low_speed }}
{% else %}
{{ current_speed | float }}
{% endif %}
- condition: template
value_template: >-
{{ ((requested_speed | float) -
(current_speed | float)) | abs > 2 }}
- condition: template
value_template: >-
{{ is_state('input_boolean.office_fan_auto_speed', 'on') and
is_state('fan.office', 'on') }}
- action: fan.set_percentage
target:
entity_id: fan.office
data:
percentage: "{{ requested_speed | int }}"
The Set fan speed action targets one specific fan. The routine skips a speed command when the reported speed is already within two percentage points of the request; this accommodates small rounding differences. Choose speeds farther apart than that. It also ignores changes to the fan’s speed attribute as triggers, avoiding a loop caused by its own action.
Temperature updates, enabling Auto, a fan becoming on, Home Assistant startup, and a five-minute check can each run the rule. The periodic check reads Home Assistant’s stored states; it does not force the thermometer to send a fresh sample. These are triggers followed by conditions, so every normal run requires Auto on and a fan reported on. Those two conditions are checked again just before the speed action, including when actions are run manually.
5. Make pause and failure behavior visible
Put Auto speed beside the fan control and temperature reading on the household dashboard. Turn Auto off before choosing a speed you want to keep. Changing the speed alone does not pause this example: the next temperature update or periodic check may replace it. Our manual-override guide covers wider household pause rules.
The default Toggle helper setting restores its previous state after a restart. With that default, Auto can resume once readings are usable. The current Toggle documentation also provides a Turn off at startup option, recommended here for deliberate re-enabling. If your installed version does not expose that option, do not assume it starts off: keep the restore behavior in your household instructions and leave Auto off before a planned restart.
Unknown or unavailable temperature and speed readings fail the numeric check, so no new speed command is sent. The motor may keep running at its last setting. A numeric reading that has stopped updating can still pass, and a delayed on/off report can be wrong. This rule cannot guarantee that a physical stop and a nearly simultaneous speed command will never cross. Pause Auto first when taking manual control, and keep the fan’s normal physical controls usable.
Use this only for ordinary room comfort, with the fan installed and used as its manufacturer directs. Do not apply it to required ventilation, smoke extraction, equipment cooling or any other safety function. Running the automation locally does not make a cloud-connected fan local: the sensor and fan integrations determine their own data and control paths.
If the behavior is unexpected
Scroll sideways to read all three columns.
| Observation | Check | Next step |
|---|---|---|
| The fan stays off in a warm room | Its entity is off. | Expected: start it yourself. Auto speed does not grant permission to start the motor. |
| 25°C sometimes leaves it low and sometimes high | 25°C is inside the gap. | Expected: it retains the current reported speed. Rehearse 25.6 and 24.4 to check both boundaries. |
| It keeps undoing my manual speed | Auto is still on. | Pause Auto first, then set the speed you want. |
| It repeatedly sends the same speed request | The fan reports a different discrete step, or feedback is delayed. | Pause Auto; use a supported reported value and inspect the integration. Do not add faster polling. |
| No new speed command appears | Trace, numeric readings, entity IDs and Auto state. | Fix the failing condition. Do not convert a missing temperature to zero to force it through. |
| The motor changes speed by itself | A manufacturer Auto/Breeze preset or another routine may be active. | Choose one speed controller and pause the others through their normal controls. |
Frequently asked questions
Can a smart plug vary a fan’s speed?
An on/off smart plug does not provide the fan’s speed controls. This example requires an integrated fan that accepts percentage speed commands. Follow the appliance and control manufacturer’s compatibility instructions.
Does pausing Auto speed turn the fan off?
No. It prevents this automation from issuing new speed commands. Use the fan’s normal control to stop the motor.
Will this work without internet?
The automation runs on Home Assistant, but its input and output paths also matter. Both the temperature sensor and fan must remain accessible through their integrations. A cloud-dependent fan connection does not become local because the rule runs at home.
Can I use the fan’s built-in Auto mode instead?
Yes, when its own sensor and behavior suit the room. Choose that controller or this Home Assistant routine deliberately, and verify the controls your exact integration exposes. Do not assume preset support also means percentage-speed support.
