When I set up our lounge fan I had an excellent idea to add a physical switch that could control it. Initially this was setup to turn it on and off, but, given that this exists to parent and visitor proof the house I decided I would make it cycle through the fan speeds. It turns out that this seemingly simple request is a little more complex than I anticipated.

Outcome: a single button that will (in my case) cycle through fan speeds: fast, medium, slow, off.

To achieve this you need to add the following:

  • two helpers
  • some scenes
  • the actual automations

Instructions are provided for both the GUI and direct construction in the conf files.

Helpers

Go to Settings > Devices & Services > Helpers > Create Helper

You’re going to need two here, one to cycle through the fan speeds and the other to help keep the first in sync.

Fan speeds

For the fan speeds you need a Dropdown


Fan speed automation boolean

Add another automation, this time of type toggle:

Scenes

Next set up some scenes that correspond to the various states via Settings > Automation & Scenes > Scenes > Add Scene

Name your scene and add the entities you care about and the states they want to be in. Under entities you also want your automation flag set.

Once you’ve set your scene up you can duplicate it for the other states. For this case I didn’t need an “off” state but depending on what you want to achieve you might.

Click on your devices and entities in order to edit their states:

Automations

This is the bit that makes it all work. You need four state automations (high, med, low and off) and one to allow the switch to control the states.

Go to Settings > Automations & Scenes > Automations > Create Automation

For the state automations you need the trigger to be the “Fan Speed” dropdown taking a specific value and the action to be the corresponding scene.

As for the scenes you can duplicate this for the other states.

The button automation needs to be triggered by the button press and have an action of select next on the helper. You also want this to cycle through so that it goes back to the start.

Finally you want some more complex logic to make sure that when you change the state via another route the speed helper is kept up to date. I’m going to pseudo-code this as the whole thing doesn’t fit on one screen in the GUI.

The trigger for this one is the fan changing state or any attributes.

The first action is to work out the state of the fan if this hasn’t been triggered by the automation:

if fan_speed_automation is "off":
    if lounge_fan is "off":
        lounge_fan_speed = "off"
    else:
        if lounge_fan.speed > 80:
            lounge_fan_speed = "high"
        else if lounge_fan.speed > 50:
            lounge_fan_speed = "med"
        else if lounge_fan.speed > 10:
            lounge_fan_speed = "low"

The second is to set the fan_speed_automation to off.

Done.

Setup Via configuration

Helpers

input_select:
    lounge_fan_speed:
        name: Lounge Fan Speed
        icon: mdi:fan
        options:
            - high
            - med
            - low
            - off

input_boolean:
    fan_speed_automation:
        name: Fan Speed Automation
        icon: mdi: fan

Scenes

There’s no “off” here as I didn’t need it but for more complex scenes you might.

scene:
    - name: Lounge Fan Low
    - entities:
        fan.lounge_fan:
            percentage: 33
            state: 'on'
        input_boolean.fan_speed_automation:
            state: 'off'
    - name: Lounge Fan Med
    - entities:
        fan.lounge_fan:
            percentage: 66
            state: 'on'
        input_boolean.fan_speed_automation:
            state: 'off'
    - name: Lounge Fan High
    - entities:
        fan.lounge_fan:
            percentage: 100
            state: 'on'
        input_boolean.fan_speed_automation:
            state: 'off'

Automations

Create an automation for each state:

alias: Lounge Fan High
description: ""
trigger:
  - platform: state
    entity_id:
      - input_select.lounge_fan_speed
    to: high
condition: []
action:
  - service: scene.turn_on
    data: {}
    target:
      entity_id: scene.lounge_fan_high
mode: single

alias: Set lounge fan to medium
description: ""
trigger:
  - platform: state
    entity_id:
      - input_select.lounge_fan_speed
    to: med
    id: lounge_fan_speed_automation
condition: []
action:
  - service: scene.turn_on
    data: {}
    target:
      entity_id: scene.lounge_fan_med_2
mode: single

alias: Set lounge fan to low
description: ""
trigger:
  - platform: state
    entity_id:
      - input_select.lounge_fan_speed
    to: low
condition: []
action:
  - service: scene.turn_on
    data: {}
    target:
      entity_id: scene.lounge_fan_low
  - service: input_boolean.turn_on
    data: {}
    target:
      entity_id: input_boolean.fan_speed_automation
mode: single

alias: Set lounge fan to off
description: ""
trigger:
  - platform: state
    entity_id:
      - input_select.lounge_fan_speed
    to: "off"
condition: []
action:
  - type: turn_off
    device_id: 0cc997d5e37e5ab0155d4f742a131521
    entity_id: fan.lounge_fan
    domain: fan
mode: single

Button automation:

alias: Toggle lounge fan states
description: ""
trigger:
  - platform: device
    domain: mqtt
    device_id: d1555d371666a72c69bc6126e7a9492a
    type: action
    subtype: single_right
    discovery_id: 0x00158d0008cf5d84 action_single_right
action:
  - service: input_select.select_next
    data:
      cycle: true
    target:
      entity_id: input_select.lounge_fan_speed
mode: single

State automation:

alias: Ensure fan speed select matches fan speed
description: ""
trigger:
  - platform: state
    entity_id:
      - fan.lounge_fan
condition: []
action:
  - if:
      - condition: state
        entity_id: input_boolean.fan_speed_automation
        state: "off"
    then:
      - if:
          - condition: state
            entity_id: fan.lounge_fan
            state: "off"
        then:
          - service: input_select.select_option
            data:
              option: "off"
            target:
              entity_id: input_select.lounge_fan_speed
        else:
          - choose:
              - conditions:
                  - condition: numeric_state
                    entity_id: fan.lounge_fan
                    attribute: percentage
                    above: 80
                sequence:
                  - service: input_select.select_option
                    data:
                      option: high
                    target:
                      entity_id: input_select.lounge_fan_speed
              - conditions:
                  - condition: numeric_state
                    entity_id: fan.lounge_fan
                    attribute: percentage
                    above: 50
                sequence:
                  - service: input_select.select_option
                    data:
                      option: med
                    target:
                      entity_id: input_select.lounge_fan_speed
              - conditions:
                  - condition: numeric_state
                    entity_id: fan.lounge_fan
                    attribute: percentage
                    above: 10
                sequence:
                  - service: input_select.select_option
                    data:
                      option: low
                    target:
                      entity_id: input_select.lounge_fan_speed
  - service: input_boolean.turn_off
    data: {}
    target:
      entity_id: input_boolean.fan_speed_automation
mode: single

Sources