Esphome Fan Speed Control and Google Home

Hello there,

The extractor fan speed structure, which I have shared the codes below, checked on the esphome and controlled with the switch structure, works successfully on Home Assistant.
Briefly, we have 5 buttons, the first button turns off the fan completely. Buttons two, three and four turn the fan speeds and finally the fifth button turns the light on and off.

When using it via Home Assistant, since the fan speed value remains as it is when the fan is turned off, and when I restart it, it continues from where it left off at the last run speed.

The problem is, the fan seems to be on and off constantly on Google Home, and even if the fan is off, Google Home also seems to be on all the time.

What I understand is that even if the fan is off, Google Home looked like this because it was based on the fan speed value and status at the same time.

I solved the problem as follows, I updated the fan speed value to 0 when the fan was turned off and the problem was solved.

In this structure, although the fan speed is not visible on Google Home, the fan speed can be changed in voice control.

esphome:
  name: ha-mutfak-aspirator
  platform: ESP8266
  board: nodemcuv2
  on_boot:
    then:
      - fan.turn_off: ha_mutfak_aspirator_fan
      - light.turn_off: ha_mutfak_aspirator_light

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  fast_connect: true

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Ha-Mutfak-Aspirator"
    password: "Password"

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:
  password: !secret esphome_api_password

ota:
  password: !secret esphome_api_password
  
web_server:
  port: 80

sensor:
  - platform: wifi_signal
    name: WiFi Signal
    id: ha_mutfak_aspirator_wifi_signal
    update_interval: 60s
  - platform: adc
    pin: A0
    name: "Tehlikeli Gaz Oranı"
    accuracy_decimals: 2
    unit_of_measurement: "%"
    id: ha_mutfak_aspirator_gas_analog
#    on_value_range:
#      - above: 3.85
#        then:
#          - switch.turn_on: ha_mutfak_aspirator_fan
#      - below: 3.70
#        then:
#          - delay: 30s # !lambda "if (id(ha_mutfak_aspirator_fan).state) return 60000; else return 0;"
#          - switch.turn_off: ha_mutfak_aspirator_fan
  - platform: dht
    pin: D0
    temperature:
      name: "Aspiratör Sıcaklık"
    humidity:
      name: "Aspiratör Nem"
    model: AM2302

text_sensor:
  - platform: wifi_info
    ip_address:
      name: WiFi IP Address
      id: ha_mutfak_aspirator_wifi_ip_address
    ssid:
      name: WiFi SSID
      id: ha_mutfak_aspirator_wifi_ssid
    bssid:
      name: WiFi BSSID
      id: ha_mutfak_aspirator_wifi_bssid

binary_sensor:
  - platform: gpio
    id: ha_mutfak_aspirator_btn_fan_off
    pin:
      number: D1
      mode: INPUT_PULLUP
    on_press:
      then:
        - fan.turn_off: ha_mutfak_aspirator_fan
  - platform: gpio
    id: ha_mutfak_aspirator_btn_fan_1
    pin:
      number: D2
      mode: INPUT_PULLUP
    on_press:
      then:
        - fan.turn_on:
            id: ha_mutfak_aspirator_fan
            speed: 1
  - platform: gpio
    id: ha_mutfak_aspirator_btn_fan_2
    pin:
      number: D3
      mode: INPUT_PULLUP
    on_press:
      then:
        - fan.turn_on:
            id: ha_mutfak_aspirator_fan
            speed: 2
  - platform: gpio
    device_class: cold
    id: ha_mutfak_aspirator_btn_fan_3
    pin:
      number: D4
      mode: INPUT_PULLUP
    on_press:
      then:
        - fan.turn_on:
            id: ha_mutfak_aspirator_fan
            speed: 3
  - platform: gpio
    id: ha_mutfak_aspirator_btn_light
    pin:
      number: D5
      mode: INPUT_PULLUP
    on_press:
      then:
      - light.toggle: ha_mutfak_aspirator_light
      
output:
  - platform: gpio
    pin: D9
    id: ha_mutfak_aspirator_output_light
    inverted: True
  - platform: template
    id: ha_mutfak_aspirator_output_fan
    type: float
    write_action:
    - if:
        condition:
          lambda: return ((state == 0) && (state < 0.3));
        then:
          - switch.turn_off: ha_mutfak_aspirator_relay_1
          - switch.turn_off: ha_mutfak_aspirator_relay_2
          - switch.turn_off: ha_mutfak_aspirator_relay_3
    - if:
        condition:
          lambda: return ((state >= 0.3) && (state < 0.6));
        then:
          - switch.turn_on: ha_mutfak_aspirator_relay_1
    - if:
        condition:
          lambda: return ((state >= 0.6) && (state <= 0.9));
        then:
          - switch.turn_on: ha_mutfak_aspirator_relay_2
    - if:
        condition:
          lambda: return ((state >= 1));
        then:
          - switch.turn_on: ha_mutfak_aspirator_relay_3

light:
  - platform: binary
    name: "Aspiratör Işık"
    id: ha_mutfak_aspirator_light
    output: ha_mutfak_aspirator_output_light

fan:
  - platform: speed
    name: "Aspiratör Fan"
    id: ha_mutfak_aspirator_fan
    output: ha_mutfak_aspirator_output_fan
    speed_count: 3
    on_turn_on:
      then:
        - if:
            condition:
              lambda: return (id(ha_mutfak_aspirator_fan).speed == 0);
            then:
              - fan.turn_on:
                  id: ha_mutfak_aspirator_fan
                  speed: 1
    on_turn_off:
      then:
        lambda: id(ha_mutfak_aspirator_fan).speed = 0;

switch:
  - platform: gpio
    pin: D6
    inverted: true
    id: ha_mutfak_aspirator_relay_1
    interlock: &interlock_group [ha_mutfak_aspirator_relay_1, ha_mutfak_aspirator_relay_2, ha_mutfak_aspirator_relay_3]
    interlock_wait_time: 100 ms
    restore_mode: RESTORE_DEFAULT_OFF
  - platform: gpio
    pin: D7
    inverted: true
    id: ha_mutfak_aspirator_relay_2
    interlock: *interlock_group
    interlock_wait_time: 100 ms
    restore_mode: RESTORE_DEFAULT_OFF
  - platform: gpio
    pin: D8
    inverted: true
    id: ha_mutfak_aspirator_relay_3 
    interlock: *interlock_group
    interlock_wait_time: 100 ms
    restore_mode: RESTORE_DEFAULT_OFF

good works

1 Like

I hope it worked.

Last code;

substitutions:
  devicename: ha_mutfak_aspirator
  deviceFriendlyName: Aspiratör
  relayInterlockWaitTime: 100 ms
  sound_Button: 'Button:d=64,o=5,b=140:f#.'
  sound_Siren: 'Siren:d=16,o=5,b=120:c.'

esphome:
  name: ${devicename}
  platform: ESP8266
  board: nodemcuv2
#  esp8266_restore_from_flash: true
  on_boot:
  - then:
    - fan.turn_off: ${devicename}_fan
    - lambda: id(${devicename}_fan).speed = 0;
    - light.turn_off: ${devicename}_light
    - rtttl.stop

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  fast_connect: true

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: ${devicename}
    password: "${devicename}_0tGQCjfCSzIA"

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:
  password: !secret esphome_api_password

ota:
  password: !secret esphome_api_password
  
web_server:
  port: 80

sensor:
  - platform: wifi_signal
    name: ${deviceFriendlyName} WiFi Signal
    id: ${devicename}_wifi_signal
  - platform: adc
    pin: A0
    name: ${deviceFriendlyName} Tehlikeli Gaz
    device_class: carbon_monoxide
    accuracy_decimals: 2
    unit_of_measurement: "%"
    id: ${devicename}_gas_analog
    update_interval: 5 s
    on_value_range:
      - above: 0.95
        then:
        - fan.turn_on:
            id: ${devicename}_fan
            speed: 3
        - while:
            condition:
              lambda: return (id(${devicename}_gas_analog).state >= .95);
            then:
              - rtttl.play: ${sound_Siren}
              - delay: 500 ms
      - below: 0.6
        then:
        - rtttl.stop
        - delay: 60 s
        - fan.turn_off: ${devicename}_fan
        - lambda: id(${devicename}_fan).speed = 0;

  - platform: dht
    pin: D0
    model: AM2302
    temperature:
      name: ${deviceFriendlyName} Sıcaklık
    humidity:
      name: ${deviceFriendlyName} Nem

text_sensor:
  - platform: wifi_info
    ip_address:
      name: ${deviceFriendlyName} WiFi IP Address
      id: ${devicename}_wifi_ip_address
    ssid:
      name: ${deviceFriendlyName} WiFi SSID
      id: ${devicename}_wifi_ssid
    bssid:
      name: ${deviceFriendlyName} WiFi BSSID
      id: ${devicename}_wifi_bssid

binary_sensor:
  - platform: gpio
    id: ${devicename}_btn_fan_off
    internal: true
    pin:
      number: D1
      mode: INPUT_PULLUP
    on_press:
    - then:
      - fan.turn_off: ${devicename}_fan
  - platform: gpio
    id: ${devicename}_btn_fan_1
    internal: true
    pin:
      number: D2
      mode: INPUT_PULLUP
    on_press:
    - then:
      - fan.turn_on:
          id: ${devicename}_fan
          speed: 1
  - platform: gpio
    id: ${devicename}_btn_fan_2
    internal: true
    pin:
      number: D3
      mode: INPUT_PULLUP
    on_press:
    - then:
      - fan.turn_on:
          id: ${devicename}_fan
          speed: 2
  - platform: gpio
    device_class: cold
    id: ${devicename}_btn_fan_3
    internal: true
    pin:
      number: D4
      mode: INPUT_PULLUP
    on_press:
    - then:
      - fan.turn_on:
          id: ${devicename}_fan
          speed: 3
  - platform: gpio
    id: ${devicename}_btn_light
    internal: true
    pin:
      number: D5
      mode: INPUT_PULLUP
    on_press:
    - then:
      - light.toggle: ${devicename}_light

output:
  - platform: esp8266_pwm
    pin: D6
    id: passive_buzzer
  - platform: gpio
    pin: D10
    id: ${devicename}_output_light
    inverted: True
  - platform: template
    id: ${devicename}_output_fan
    type: float
    write_action:
    - if:
        condition:
          lambda: return ((state == 0) && (state < .3));
        then:
        - if:
            condition:
              lambda: return (id(${devicename}_relay_1).state || id(${devicename}_relay_2).state || id(${devicename}_relay_3).state);
            then:
            - rtttl.stop
            - rtttl.play: ${sound_Button}
            - switch.turn_off: ${devicename}_relay_1
            - switch.turn_off: ${devicename}_relay_2
            - switch.turn_off: ${devicename}_relay_3
    - if:
        condition:
          lambda: return ((state >= .3) && (state < 0.6));
        then:
        - if:
            condition:
              lambda: return !id(${devicename}_relay_1).state;
            then:
            - rtttl.stop
            - rtttl.play: ${sound_Button}
            - switch.turn_on: ${devicename}_relay_1
    - if:
        condition:
          lambda: return ((state >= .6) && (state < .9));
        then:
        - if:
            condition:
              lambda: return !id(${devicename}_relay_2).state;
            then:
            - rtttl.stop
            - rtttl.play: ${sound_Button}
            - switch.turn_on: ${devicename}_relay_2
    - if:
        condition:
          lambda: return ((state >= 1));
        then:
        - if:
            condition:
              lambda: return !id(${devicename}_relay_3).state;
            then:
            - rtttl.stop
            - rtttl.play: ${sound_Button}
            - switch.turn_on: ${devicename}_relay_3

rtttl:
  output: passive_buzzer

light:
  - platform: binary
    name: ${deviceFriendlyName} Işık
    id: ${devicename}_light
    output: ${devicename}_output_light
    on_turn_on:
    - then:
      - rtttl.stop
      - rtttl.play: ${sound_Button}
    on_turn_off:
    - then:
      - rtttl.stop
      - rtttl.play: ${sound_Button}

fan:
  - platform: speed
    name: ${deviceFriendlyName} Fan
    id: ${devicename}_fan
    output: ${devicename}_output_fan
    speed_count: 3
    on_turn_on:
    - then:
      - if:
          condition:
            lambda: return (id(${devicename}_fan).speed == 0);
          then:
            - fan.turn_on:
                id: ${devicename}_fan
                speed: 1
    on_turn_off:
    - then:
      - lambda: id(${devicename}_fan).speed = 0;

switch:
  - platform: gpio
    pin: D7
    inverted: true
    internal: true
    id: ${devicename}_relay_1
    restore_mode: RESTORE_DEFAULT_OFF
    interlock: &interlock_group ['${devicename}_relay_1', '${devicename}_relay_2', '${devicename}_relay_3']
    interlock_wait_time: ${relayInterlockWaitTime}
  - platform: gpio
    pin: D8
    inverted: true
    internal: true
    id: ${devicename}_relay_2
    restore_mode: RESTORE_DEFAULT_OFF
    interlock: *interlock_group
    interlock_wait_time: ${relayInterlockWaitTime}
  - platform: gpio
    pin: D9
    inverted: true
    internal: true
    id: ${devicename}_relay_3
    restore_mode: RESTORE_DEFAULT_OFF
    interlock: *interlock_group
    interlock_wait_time: ${relayInterlockWaitTime}
2 Likes