Xiaomi Aqara double button support for double clicks

I got my Xiaomi Aqara double buttons (wireless switch) yesterday and got a bit annoyed at the fact that it didn’t support double clicks and long clicks. I still haven’t been able to solve long clicks, any input is appreciated, but I did manage go implement both single and double clicks. The same could be extended to support triple clicks etc by just adding a “for: seconds: 1” to the double click automation.

  # livingroom_switch_left_status:
  #   name: Living room switch left status
  #   initial: 'off'
  #   options:
  #     - 'off'
  #     - 'single'
  #     - 'double'
  #     - 'long'

  # livingroom_switch_left_number:
  #   name: Living room switch left status
  #   initial: 0
  #   min: 0
  #   max: 110
  #   step: 1

  ## These automations are used to set the status of an aqara button to either off, single, double or long. 
  ## The Aqara buttons does not support this out of the box, so this is a way to emulate it with automations and input selects.
  ## A bit of a hack, but should work. Have to be repeated for left button, right button and both buttons in order to get it all to work.
  ## Then the input select can be used for automations rather than using the on/off directly. Since the Aqara buttons only show up
  ## as a binary sensor, it can only have two values, on or off.

  # Set an input select when button is clicked.
  - alias: Livingroom switch left button single click
    trigger:
      - platform: event
        event_type: click
        event_data:
          entity_id: binary_sensor.wall_switch_left_158d000171d630
          click_type: single
    condition:
      - condition: state
        entity_id: input_select.livingroom_switch_left_status
        state: 'off'
    action:
      - service: input_select.select_option
        data:
          entity_id: input_select.livingroom_switch_left_status
          option: 'single'

  # Now to detect double clicks. We detect a single click and check if the input select is already single. if so, it's a double.
  - alias: Livingroom switch left button double click
    trigger:
      - platform: event
        event_type: click
        event_data:
          entity_id: binary_sensor.wall_switch_left_158d000171d630
          click_type: single
    condition: 
      - condition: state
        entity_id: input_select.livingroom_switch_left_status
        state: 'single'
    action:
      - service: input_select.select_option
        data:
          entity_id: input_select.livingroom_switch_left_status
          option: 'double'

  # If the input select doesn't change state for 2 seconds, change back to off. 
  - alias: Livingroom switch left button set to off
    trigger:
      - platform: state
        entity_id: input_select.livingroom_switch_left_status
        to: 'single'
        for:
          seconds: 2
      - platform: state
        entity_id: input_select.livingroom_switch_left_status
        to: 'double'
        for:
          seconds: 2
    action:
      - service: input_select.select_option
        data:
          entity_id: input_select.livingroom_switch_left_status
          option: 'off'

  # If the input select is double, turn off the ceiling group if on, turn on if off. Also set status to off.
  - alias: Livingroom switch left button double click ceiling is on
    trigger:
      - platform: state
        entity_id: input_select.livingroom_switch_left_status
        to: 'double'
    condition:
      - condition: state
        entity_id: light.living_room_roof_1
        state: 'on'
    action:
      - service: homeassistant.turn_off
        entity_id: 
          - group.livingroom_ceiling
      - service: input_select.select_option
        data:
          entity_id: input_select.livingroom_switch_left_status
          option: 'off'

  - alias: Livingroom switch left button double click ceiling is off
    trigger:
      - platform: state
        entity_id: input_select.livingroom_switch_left_status
        to: 'double'
    condition:
      - condition: state
        entity_id: light.living_room_roof_1
        state: 'off'
    action:
      - service: homeassistant.turn_on
        entity_id: 
          - group.livingroom_ceiling
      - service: input_select.select_option
        data:
          entity_id: input_select.livingroom_switch_left_status
          option: 'off'

  # I want to increase the light if single press is done. Max is 100. Starting at 5 and going up 17 per time, we get these numbers:
  # 5, 22, 39, 56, 73, 90, 107
  # 5 is pretty perfect for low light like watching tv, and 90 is too bright already.
  # 110 is the maximum number for the input_number so I needed something that maxed out over 100 but below 110.
  # Also sets the status to off so it can be used again without waiting for the reset timer
  - alias: Livingroom switch left button single press increase number
    trigger:
      - platform: state
        entity_id: input_select.livingroom_switch_left_status
        to: 'single'
        for:
          seconds: 1
    action:
      - service: input_number.set_value
        data_template: 
          entity_id: input_number.livingroom_switch_left_number
          value: '{{ states.input_number.livingroom_switch_left_number.state | int + 17 }}'
      - service: input_select.select_option
        data:
          entity_id: input_select.livingroom_switch_left_status
          option: 'off'
      
  # If we go over 100, reduce to 5 to restart the flow. 
  - alias: Set livingroom switch state to 5 if over 100
    trigger:
      - platform: numeric_state
        entity_id: input_number.livingroom_switch_left_number
        # value_template: '{{ states.input_number.livingroom_switch_left_number.state  }}'
        above: 100
    action:
      - service: input_number.set_value
        data_template: 
          entity_id: input_number.livingroom_switch_left_number
          value: '5'

  # When we change the input_number, set the ceiling group to that brightness as a percentage
  - alias: Set livingroom ceiling based on input_number
    trigger:
      - platform: state
        entity_id: input_number.livingroom_switch_left_number
    action:
      - service: homeassistant.turn_on
        data_template:
          entity_id: group.livingroom_ceiling
          brightness_pct: '{{ states.input_number.livingroom_switch_left_number.state | int }}'



  # Never found a good way to make this work
  #- alias: Livingroom switch left button long click
  #  trigger:
  #    - platform: event
  #      event_type: click
  #      event_data:
  #        entity_id: binary_sensor.wall_switch_left_158d000171d630
  #        click_type: single
  #      for: 
  #        seconds: 1
  #  action:
  #    - service: input_select.select_option
  #      data:
  #        entity_id: input_select.livingroom_switch_left_status
  #        option: 'long'

Now I just have to repeat this tiny little snippet for the right button and both buttons pressed… It works pretty flawlessly, I will probably tweak the timings a bit to make it feel more intuitive. The tradeoff is I need it to be in single click status long enough for even the kids to have time to do a double click before the single click automation is triggered.

Code is also available at https://github.com/DevvAndreas/Home-Assistant-Config/blob/master/automation/state%20based/switch_automations.yaml along with the rest of my config

4 Likes

Could this be useful?
https://github.com/home-assistant/home-assistant/compare/dev...xiaomi-aqara-button?quick_pull=1

Then you get an attribute showing the last action.
You can then make a template sensor to display it at the frontend.

Yeah that looks super useful! If there would be a way to get these kinds of clicks in the component without having to write complicated automations to get around it, that would be amazing.

Ok, then I will add it for the nest release:

3 Likes

That is absolutely amazing, huge thanks! Looking forward to next release.

Would be interesting if this would work also for the Xiaomi cube. Would it be possible/feasible?

Thanks in advance.

That is added earlier

Cool, thanks. I really need to update my Home Assistant.

Anyone mind sharing their code for this one? If it would go to the docs would be even more great

Looking to program my automations for my new buttons soon. Does this work ok? Reliable?

I’m concerned there may be unwanted interaction between the 2 second reset timer and a second single click.

I also don’t think the reset timer is actually necessary? As the state of the input select will never be single or double for as long as seconds?

It will always resolve after one second (for single) or immediately (for double) and reset to off.

Did you have problems when you left that part of these automations out?

do you think this could be simplified using an input number to count with? Rather than defining the step from 0->1 and from 1->2. I can’t see how you’d make it wait on any given input number for 1 second before going on to the automation you want to use though. any suggestions appreciated.

I was thinking about something like this:

https://pastebin.com/Ge8QT5t0

I hasdn’t realised that the double/long clicks weren’t recognised in Home Assistant (should have done some more research!). To get multiple clicks to work i’ve been playing around in appdaemon and at first attemp it seems pretty straightforward to implement a counter (this way you can have different actions called for >2 clicks).

I haven’t implement any ‘doing’ code yet but the log outputs the correct number of clicks, the only thing that would need tweaking is the delay I think 1 second is probably plenty but it may depend on system lag.

import appdaemon.appapi as appapi

class XiaomiWallSwitch(appapi.AppDaemon):

def initialize(self):
    
    self.counter = 0
    
    self.handle = None

    self.listen_event(self.count_presses, "click", entity_id="binary_sensor.wall_switch_left_x", click_type="single")

def count_presses(self, event, data, kwargs):

    self.counter += 1
    
    self.cancel_timer(self.handle) if self.counter > 1 else False
        
    self.handle = self.run_in(self.button_press, 2)
    
def button_press(self, kwargs):
    
    self.log(self.counter)

    self.counter = 0
    
    self.handle = None