ESP Home 3 Speed Fan Conversion

If would need to be a condition based action, based on what fan speed is currently selected. In ESPhome you can do if/then/else statements, but I’m not sure if you can do if/elseif/elseif/else or not…

There is likely a way to do this with lambda’s but I’m not skilled in writing those.

ESPhome code: (not complete)

</s> <s>button:</s> <s> - platform: gpio</s> <s> name: Fan Button</s> <s> id: button</s> <s> on_press:</s> <s> then:</s> <s> - if:</s> <s> condition:</s> <s> - switch.is_on: switch_low</s> <s> then:</s> <s> - switch.turn_off: switch_low</s> <s> - switch.turn_on: switch_med</s> <s>
Hopefully you get the idea, but I would imagine there is a more elegant way to do this with lambda’s.

EDIT: see solution from RoadlikkUK below.

Thanks for the quick reply. Unfortunately, I do not quite understand the solution. I have a button and would like to achieve a different state with each press on it. So the speed Slow Medium and Fast or Off. In C++ this would probably be a counter from 0 to 3 and the assignment via a switch-case statement. This should be possible with ESPHome! Only I do not know how…

Check this link, there is an Action for that.

Increments through speed levels of the fan with the given ID when executed. If the fan’s speed level is set to maximum when executed, turns fan off.

button:
  - platform: template
    name: Fan Button
    id: fanbutton
    on_press:
      - fan.cycle_speed: fan_1
1 Like

Wow! I had no idea that existed, thanks. I may as well delete my last nonsense post!

Fan Component

With the fan domain you can create components that appear as fans in the Home Assistant frontend. A fan can be switched on or off, optionally has a speed between 1 and the maximum supported speed of the fan, and can have an oscillation and direction output.

How is this supposed to help me with my automation in the device? I have read everything and think that this is mainly about the front end. If I’m wrong please show me a solution with the platform gpio so a physical button.

Try this instead then, it would seem that the last example was for a ‘virtual’ button, not physical.

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO01
      mode: INPUT_PULLUP
      inverted: True
    name: "Fan Cycle"
    filters:
      - delayed_on: 10ms
    on_press:
      then:
        - fan.cycle_speed: fan_1

No worries Dave, I used your example further up in this thread to change my fan from 3 buttons and 1 switch to the correct way with fan speeds. RF remote fan control

1 Like

When I insert this example I get the following error message…

"Unable to find action with the name ‘fan.cycle_speed’.

Do I need to declare anything else?

OK, that’s true… I’ll look into that.

Alright, that’s weird because it’s fine now, in my fan config and compiling and uploading. I’m not sure what to say about that.

Is the fan.cycle_speed: pointing to your fan id:

tom

1 Like

Thanks for your trouble.

The fan declaration does not exist for me because I did not know it yet. Honestly, I also do not know how to set this with me. I would like to switch only three solid state relays. Show you my code so far. The switches represent the relays. The push button is connected to D5.

esphome:
  name: test

esp8266:
  board: d1_mini

# Enable logging
logger:

# Enable Home Assistant API
api:
  
ota:
  
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  reboot_timeout: 0s
  power_save_mode: none

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Test Fallback Hotspot"
    password: "nAdxHohdmdVM"

captive_portal:

web_server:
  port: 80

time:
#  - platform: homeassistant
#    id: time
  - platform: sntp
    id: time_ntp
    timezone: Europe/Berlin
    
i2c:
  sda: D3
  scl: D2
  scan: True

globals:
   - id: my_global_int
     type: int
     restore_value: no
     initial_value: '0'
     
sensor:
  - platform: bme280
    temperature:
      name: "BME280 Temperature"
      id: bme280_temperature
      oversampling: 16x
    pressure:
      name: "BME280 Pressure"
    humidity:
      name: "BME280 Humidity"
      id: bme280_humidity
    address: 0x76
    update_interval: 30s 
    

binary_sensor:
  - platform: gpio
    pin:
      number: D5
      mode:
        input: true
        pullup: true
      inverted: True
    name: "Taster"
    id: taster
    on_press:
      then:


switch:
  - platform: gpio
    pin: D1
    name: "Stufe 1"
    id: low
    
  - platform: gpio
    pin: D6
    name: "Stufe 2"
    id: middle
   
  - platform: gpio
    pin: D7
    name: "Stufe 3"
    id: high
   
    
font:
  - file: "Roboto-Regular.ttf"
    id: RB3
    size: 24
  
  - file: "Roboto-Regular.ttf"
    id: RB2
    size: 20
  
  - file: "Roboto-Regular.ttf"
    id: RB1
    size: 16  
  
  - file: 'slkscr.ttf'
    id: RB4
    size: 8

  - file: 'bebas-neue-regular.ttf'
    id: RB5
    size: 48

  - file: 'arial.ttf'
    id: RB6
    size: 14

  - file: 'bebas-neue-regular.ttf'
    id: RB7
    size: 32
    
display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    id: "my_display"
    reset_pin: D0
    address: 0x3C
    pages:
      - id: page1
        lambda: |-
          // Print temperature 
          if (id(bme280_temperature).has_state()) {
          it.printf(90, 20, id(RB3), TextAlign::TOP_RIGHT , "%.1f°", id(bme280_temperature).state);
          }

          // Print humidity
          if (id(bme280_humidity).has_state()) {
          it.printf(100, 40, id(RB3), TextAlign::TOP_RIGHT , "%.1f%%", id(bme280_humidity).state);
          }
      - id: page2
        lambda: |-
          it.strftime(20, 60, id(RB5), TextAlign::BASELINE_LEFT, "%H:%M", id(time_ntp).now());

interval:
  - interval: 5s
    then:
      - display.page.show_next: my_display
      - component.update: my_display          
              

This was just a test and should be deleted.

esphome:
  name: test

esp8266:
  board: d1_mini

# Enable logging
logger:

# Enable Home Assistant API
api:
  
ota:
  
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  reboot_timeout: 0s
  power_save_mode: none

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Test Fallback Hotspot"
    password: "nAdxHohdmdVM"

captive_portal:

web_server:
  port: 80

time:
#  - platform: homeassistant
#    id: time
  - platform: sntp
    id: time_ntp
    timezone: Europe/Berlin
    
i2c:
  sda: D3
  scl: D2
  scan: True

binary_sensor:
  - platform: gpio
    pin:
      number: D5
      mode:
        input: true
        pullup: true
        inverted: True
    name: "Fan Cycle"
    filters:
      - delayed_on: 10ms
    on_press:
      then:
        - fan.cycle_speed: ceilingfan

output:
  - platform: template
    id: custom_fan
    type: float 
    write_action:
      - if:
          condition:
            lambda: return ((state == 0));
          then:
            # action for off
            - switch.turn_off: low
            - switch.turn_off: middle
            - switch.turn_off: high
      - if:
          condition:
            lambda: return ((state > 0) && (state < 0.4));
          then:
            # action for speed 1
            - switch.turn_off: middle
            - switch.turn_off: high
            - switch.turn_on: low
            
      - if:
          condition:
            lambda: return ((state > 0.4) && (state < 0.7));
          then:
            # action for speed 2
            - switch.turn_off: low
            - switch.turn_off: high
            - switch.turn_on: middle
            
      - if:
          condition:
            lambda: return ((state > 0.7));
          then:
            # action for speed 3
            - switch.turn_off: low
            - switch.turn_off: middle
            - switch.turn_on: high

fan:
  - platform: speed
    id: custom_fan
    output: ceiling_fan
    name: "Ceiling Fan"
    speed_count: 3
    

sensor:
  - platform: bme280
    temperature:
      name: "BME280 Temperature"
      id: bme280_temperature
      oversampling: 16x
    pressure:
      name: "BME280 Pressure"
    humidity:
      name: "BME280 Humidity"
      id: bme280_humidity
    address: 0x76
    update_interval: 30s 
    
switch:
  - platform: gpio
    pin: D1
    name: "Stufe 1"
    id: low
    
  - platform: gpio
    pin: D6
    name: "Stufe 2"
    id: middle
   
  - platform: gpio
    pin: D7
    name: "Stufe 3"
    id: high
   
    
font:
  - file: "Roboto-Regular.ttf"
    id: RB3
    size: 24
  
  - file: "Roboto-Regular.ttf"
    id: RB2
    size: 20
  
  - file: "Roboto-Regular.ttf"
    id: RB1
    size: 16  
  
  - file: 'slkscr.ttf'
    id: RB4
    size: 8

  - file: 'bebas-neue-regular.ttf'
    id: RB5
    size: 48

  - file: 'arial.ttf'
    id: RB6
    size: 14

  - file: 'bebas-neue-regular.ttf'
    id: RB7
    size: 32
    
display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    id: "my_display"
    reset_pin: D0
    address: 0x3C
    pages:
      - id: page1
        lambda: |-
          // Print temperature 
          if (id(bme280_temperature).has_state()) {
          it.printf(90, 20, id(RB3), TextAlign::TOP_RIGHT , "%.1f°", id(bme280_temperature).state);
          }

          // Print humidity
          if (id(bme280_humidity).has_state()) {
          it.printf(100, 40, id(RB3), TextAlign::TOP_RIGHT , "%.1f%%", id(bme280_humidity).state);
          }
      - id: page2
        lambda: |-
          it.strftime(20, 60, id(RB5), TextAlign::BASELINE_LEFT, "%H:%M", id(time_ntp).now());

interval:
  - interval: 5s
    then:
      - display.page.show_next: my_display
      - component.update: my_display
1 Like

Wow thanks for doing the work and rewriting the program. That’s how it works already. Thank you very much. One question for understanding…
Let’s say I have a device with three relays so no fan or something like that. Would I have to solve the task in the same way? I don’t understand why this is so complicated.

The rewrite was a mash up of yours and @sparkydave’s.

I’m not sure I understand your question, can I suggest you keep looking into ESPHome as that’s the only way you’ll understand it. Take this script/program/sketch for example and look into why it does what is does.

Yes that’s true I still have a lot to learn. Unfortunately, there are not so many examples of automation with esphome. If you have a source, please send it to me. I thank you again for your help.

Hello everyone, this is exactly what i was looking for. The proyect im starting to build.

I copied @RoadkillUK code, removed the I2C, temp sensor, and display becouse i wont be using it.

But im got some errors. I really didnt understand what i had to do. I changed some of the ID for the fan and finally started working.

this is how it ended up working for me:

fan:

  - platform: speed

    id: ceilingfan

    output: custom_fan

    name: "Ceiling Fan"

    speed_count: 3

binary_sensor:

  #Pulsador cambia velocidad en D0

  - platform: gpio

    pin:

      number: 14

      mode:

        input: True

        pullup: True

      inverted: True

    name: "Fan Cycle"

    on_press:

      then:

        - fan.cycle_speed: ceilingfan

output:

  - platform: template

    id: custom_fan

    type: float

    write_action:

      - if:

          condition:

            lambda: return ((state == 0));

          then:

            # action for off

            - switch.turn_off: low

            - switch.turn_off: middle

            - switch.turn_off: high

      - if:

          condition:

            lambda: return ((state > 0) && (state < 0.4));

          then:

            # action for speed 1

            - switch.turn_off: middle

            - switch.turn_off: high

            - switch.turn_on: low

           

      - if:

          condition:

            lambda: return ((state > 0.4) && (state < 0.7));

          then:

            # action for speed 2

            - switch.turn_off: low

            - switch.turn_off: high

            - switch.turn_on: middle

           

      - if:

          condition:

            lambda: return ((state > 0.7));

          then:

            # action for speed 3

            - switch.turn_off: low

            - switch.turn_off: middle

            - switch.turn_on: high

switch:

  #Pin D1 Velocidad Baja

  - platform: gpio

    pin: 5

    name: "Vent Baja"

    id: low

  #Pin D2 Velocidad Media

  - platform: gpio

    pin: 4

    name: "Vent Medio"

    id: middle

  #Pin D3 Velocidad Maxima

  - platform: gpio

    pin: 0

    name: "Vent Max"

    id: high