Double click event from a rocker switch

Hi,

I’m pretty experienced with HA but relatively new to Esphome and I’m wondering if this is somehow possible.

What I have right now:
Shelly i3 flashed with Esphome with one of it’s inputs connected to a standard rocker type wall switch. It reports a state of that switch to HA in form of a binary sensor. The HA automation then toggles lights every time the binary sensor changes states between ON and OFF.

What I would like to achieve:
Keep the existing functionality, so flipping that rocker switch will still toggle the same lights. Add additional functionality where if I quickly toggle the wall switch twice (up->down->up or down->up->down), HA will then toggle different lights.

Would it be possible to maybe add some additional binary sensor in esphome and then write automation where toggling the wall switch twice in a quick succesion will toggle a state of that virtual binary sensor? Or am I overcomplicating it and there’s an easier way?

Do it all in ESPHome.

First create a couple of Template Binary Sensors:

binary_sensor:
  - platform: template
    name: "Light Switch 1"
    id: template_sw1

  - platform: template
    name: "Light Switch 2"
    id: template_sw2

Then make your existing sensor (the one connected to your toggle switch) internal: true and add on_state and on_click events (for example - have a look at the available options to see which one fits your use case):

binary_sensor:
  - platform: gpio 
    id: input_sw
    internal: true
    # ...
    on_state:
      then:
        - if:
            condition:
              lambda: 'return id(template_sw1).state'
            then:
              - binary_sensor.template.publish:
                id: template_sw1
                state: OFF
            else:
              - binary_sensor.template.publish:
                id: template_sw1
                state: ON

Do the same for the on_click event, or whatever else you choose. Note you can have multiple on_click events with different timers - this makes binary sensors pretty flexible.

Amazing! Thank you zoogara.

I will be away now for 2 weeks but when I come back, I will post an update on how it worked for me.

Hi, apologies for the delay in coming back with an update.

I built a test circuit and flashed the i3 with the following code:

# Physical wall switch sensor automation
binary_sensor:
  - platform: gpio
    pin:
      number: GPIO12
      mode: INPUT
    name: i3-kitchen Input 1
    id: wallswitch1
    internal: true
    filters:
      - delayed_on_off: 200ms
    on_state:
      then:
        - if:
            condition:
               lambda: 'return id(template_sw1).state;'
            then:
              - binary_sensor.template.publish:
                  id: template_sw1
                  state: OFF
            else:
              - binary_sensor.template.publish:
                  id: template_sw1
                  state: ON
    on_multi_click:
    - timing:
        - ON for at most 1s
        - OFF for at most 1s
        - ON for at most 1s
      then:
        - binary_sensor.template.publish:
            id: template_sw2
            state: OFF # <<< how to toggle status?
    - timing:
        - OFF for at most 1s
        - ON for at most 1s
        - OFF for at most 1s
      then:
        - binary_sensor.template.publish:
            id: template_sw2
            state: OFF # <<< how to toggle status?

# Virtual switches
  - platform: template
    name: "Kitchen counter LED switch"
    id: template_sw1
  - platform: template
    name: "Kitchen cabinets LED switch"
    id: template_sw2

I came across a few problems, I couldn’t figure out.

First is probably very easy - how to set default states for the virtual switches? When I power the device, it reports to HA like this:

Kitchen cabinets LED switch - status Unknown
Kitchen counter LED switch - status On

I would like both sensors to start with an OFF status on boot.

The other question is how to ‘toggle’ the virtual sensors (see comments in the code)?

Hi, I’m starting to understand the logic of esphome code and I realize now that my previous post had some silly questions. Please disregard them.

I got it all working with the following code:

esphome:
  name: i3-kitchen
  on_boot:
    priority: 600
    then:
      - binary_sensor.template.publish:
          id: template_sw1
          state: ON
      - binary_sensor.template.publish:
          id: template_sw2
          state: OFF

esp8266:
  board: esp01_1m

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "####################################"

ota:
  password: "###############################"

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

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

captive_portal:

# Physical wall switch sensor automation
binary_sensor:
  - platform: gpio
    pin:
      number: GPIO12
      mode: INPUT
    name: i3-kitchen Input 1
    id: wallswitch1
    internal: true
    filters:
      - delayed_on_off: 50ms
    on_state:
      then:
        - if:
            condition:
               lambda: 'return id(template_sw1).state;'
            then:
              - binary_sensor.template.publish:
                  id: template_sw1
                  state: OFF
            else:
              - binary_sensor.template.publish:
                  id: template_sw1
                  state: ON
    on_multi_click:
    - timing:
        - ON for at most 500ms
      then:
        - if:
            condition:
               lambda: 'return id(template_sw2).state;'
            then:
              - binary_sensor.template.publish:
                  id: template_sw2
                  state: OFF
            else:
              - binary_sensor.template.publish:
                  id: template_sw2
                  state: ON
    - timing:
        - OFF for at most 500ms
      then:
        - if:
            condition:
               lambda: 'return id(template_sw2).state;'
            then:
              - binary_sensor.template.publish:
                  id: template_sw2
                  state: OFF
            else:
              - binary_sensor.template.publish:
                  id: template_sw2
                  state: ON

# Virtual switches
  - platform: template
    name: "Kitchen counter LED switch"
    id: template_sw1
  - platform: template
    name: "Kitchen cabinets LED switch"
    id: template_sw2

There is just one small issue with the above code. When I quickly flip the wall switch ON->OFF->ON or OFF->ON->OFF, the on_multi_click automation works and it toggles the value of the template_sw2 but it also momentarily changes the value of the template_sw1 which is undesirable behaviour.

Would you have any idea how to fix it?

Sorry been away for a few weeks.

My first suggestion would be to get rid of the on_state: and replace it with another event with a minimum time for detect?

Thanks Daryl. Thinking along the same lines, I also tried the below code but the problem is that Esphome will run through all my trigger conditions and trigger all events for all matching conditions. That means a single input event (for example flipping the switch ON/OFF quickly) will not only trigger the intended action under these conditions:

    - timing:
        - OFF for at most 500ms
        - ON for at least 501ms

but it won’t stop there and it will also trigger this one:

    - timing:
        - ON for at least 501ms

Full code:

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO12
      mode: INPUT
    name: i3-kitchen Input 1
    id: wallswitch1
    internal: true
    filters:
      - delayed_on_off: 50ms
    on_multi_click:
    - timing:
        - ON for at most 500ms
        - OFF for at least 501ms
      then:
        - if:
            condition:
               lambda: 'return id(template_sw2).state;'
            then:
              - binary_sensor.template.publish:
                  id: template_sw2
                  state: OFF
            else:
              - binary_sensor.template.publish:
                  id: template_sw2
                  state: ON
    - timing:
        - OFF for at most 500ms
        - ON for at least 501ms
      then:
        - if:
            condition:
               lambda: 'return id(template_sw2).state;'
            then:
              - binary_sensor.template.publish:
                  id: template_sw2
                  state: OFF
            else:
              - binary_sensor.template.publish:
                  id: template_sw2
                  state: ON
    - timing:
        - OFF for at least 501ms
      then:
        - if:
            condition:
               lambda: 'return id(template_sw1).state;'
            then:
              - binary_sensor.template.publish:
                  id: template_sw1
                  state: OFF
            else:
              - binary_sensor.template.publish:
                  id: template_sw1
                  state: ON
    - timing:
        - ON for at least 501ms
      then:
        - if:
            condition:
               lambda: 'return id(template_sw1).state;'
            then:
              - binary_sensor.template.publish:
                  id: template_sw1
                  state: OFF
            else:
              - binary_sensor.template.publish:
                  id: template_sw1
                  state: ON

I am using this code to make my double click and long click work, but is there a way to have the clicks behave like buttons instead of switches?

Now every time I click the state changes from OFF to ON or vice versa, while I would love to just have the impulse going from OFF to ON and back to OFF.

Nevermind I brute forced it:

    on_click:
    - min_length: 50ms
      max_length: 350ms
      then:
        - if:
            condition:
              lambda: 'return id(btn_single).state;'
            then:
              - binary_sensor.template.publish:
                  id: btn_single
                  state: OFF
              - delay: 100ms
              - binary_sensor.template.publish:
                  id: btn_single
                  state: ON                  
            else:
              - binary_sensor.template.publish:
                  id: btn_single
                  state: ON
              - delay: 100ms
              - binary_sensor.template.publish:
                  id: btn_single
                  state: OFF