ZHA Double (and Triple) Click Experiments

Original title: “IKEA Trådfri Remote: ZHA Double (and Triple) Click”
I updated the title after sharing the results of my Xiaomi remote experiments.


I recently picked up an IKEA Trådfri Remote to try out. My computer is in the Living Room and I thought it would be nice to have a multi function remote to manage the fan and lights around me. After watching the zha_event logs I determined that I could get 9 functions out of the 5 button remote. 5 single clicks plus 4 long presses.

Unfortunately, zha_event was not capturing an event for double clicks like my Xiaomi double switches do. I kept thinking there might be a way to capture clicks say a half second apart. As it turns out part of the trick was to delay the single click action by a half second to allow a chance for a second click to be detected!

Anyway, if you are interested in learning more about how I did it, I go into a lot of detail in an article on my blog (link below).

You can find full versions of my automation and script at the links below. My full automation handles multiple remotes instead of just the one in the below example.

5 Likes

Today I sat down with a spare Xiaomi Aqara Wireless Mini Switch. It is the square one with a single button in the middle.

I attempted to recreate the multi-click success, but there seems to be a delay in the button presses being received by ZHA. The delay is long enough that I cannot consistently time the button presses to detect a double click. I even tried extending the delay from 1/2 a second to 2 seconds. Slowing my click rate down did not work. Speeding up my click rate didn’t work.

In the end the timing window for this Xiaomi button is just too narrow to make a double click on this button useful. I doubt any other Xiaomi battery powered buttons would work any differently, so I am going to end the Xiaomi button experiment here.

Let me know if you use this technique successfully any other ZHA buttons!

Tradfri 5 button remote update:

In my article I only tried capturing multi-click on the center button. I wanted to let you know that it also works on the other 4 buttons as well! This means we can use this remote for a practically unlimited number of actions.

So now we can use this remote for:

  • 5 single click actions
  • 4 long press actions
  • 5 double click actions
  • 5 triple click actions
  • etc.

For example, I setup my top and bottom buttons to:

  • 1 click = turn on/off primary lamp
  • 2 clicks = turn on/off table lamp
  • Long press up = increase primary and/or table lamp brightness by 20%
  • Long press down = decrease primary and/or table lamp brightness by 20%

I was eyeing the Ikea remote to control stuff in my living room (that’s not yet implemented but it’s in my head) and this is just perfect! Thank you.
PS: Also great to see what can actually be done with automations

1 Like

I don’t think I realized how game changing the new choose and mode features were going to be until now! I believe this could not have been accomplished sooner without custom Python code! :slight_smile:

This is exactly what I set out looking for!

I have a couple Ikea bulbs with toggle switches, and most of the time find it pretty annoying that the bulbs turn back on to their previous light level. A double-click for full brightness would be perfect.

Any suggestion for max length for input_text.zha_click?

1 Like

I felt like 0.5 seconds was a reasonable for delay between clicking a butting once to turn on a light and the light actually turning on. Much longer and you would be feeling impatient. You may have a use case for extending that delay, so give it a try and see how a single click feels.

Not the delay, the max text length of the field where the click info is stored. HA defaults it to 100, but I was guessing that’s probably too short. I changed it to 1000, but don’t really even know if I’m in the right ballpark. I’m guessing it depends on how many switches will be using it.

I had an epiphany! I was making this code more complex that I needed to. By using a counter entity, and assuming I am unlikely to be taping multiple ZHA buttons within a half second of each other, I got rid of the complex input_text field.

Here is my improved code for my three remotes!

automation:
  alias: ZHA Button Click
  id: zha_button_click
  initial_state: true
  mode: restart # Force restart to pickup double click
  max_exceeded: silent
  trigger:
    platform: event
    event_type: zha_event
  action:
    # Increment the counter then delay 0.5 second to allow for a second click to cancel the second action.
    - service: counter.increment
      entity_id: counter.zha_button_click
    - delay:
        seconds: 0.5

    # Store the click count and reset the counter.
    - variables:
        click_count: '{{ states("counter.zha_button_click") }}'
    - service: counter.reset
      entity_id: counter.zha_button_click

    # Retrieve the remaining values needed to determine which action was requested.
    - variables:
        remotes:
          # Ikea
          "ec:1b:bd:ff:fe:23:9c:ee": "remote_family_room"
      
          # Xiaomi
          "00:15:8d:00:01:2d:d7:c3": "button_printer_power"
          "00:15:8d:00:02:83:e2:b6": "remote_bedroom_double_rocker"
        manufacturers:
          "ec:1b:bd:ff": "ikea"
          "00:15:8d:00": "xiaomi"

        device_ieee: '{{ trigger.event.data.device_ieee }}'

        manufacturer: '{{ manufacturers[device_ieee[0:11]] }}'
        remote: '{{ remotes[device_ieee] }}'
        click_count: |
          {% if manufacturer == "xiaomi" %}
            {%- set count = trigger.event.data.args.value %}
            {%- if count == False or count is not number %}
              {{- 0 }}
            {%- else %}
              {{ count|int }}
            {%- endif %}
          {% else %}
            {{ click_count }}
          {%- endif %}
        # Removed '(manufacturer == "xiaomi" and click_count == 0) to make printer button work.'
        command: |
          {% set command = trigger.event.data.command %}
          {%- if (manufacturer == "hue" and command == "step")
              or (manufacturer == "ikea" and command == "checkin")
              or remote|trim == "" %}
            {%- set command = "ignore" %}
          {%- endif %}
          {{- command }}
        command_modifier: |
          {% if manufacturer == "ikea" %}
            {{ trigger.event.data.args[0] }}
          {%- endif %}

    # Only take action for commands other than "ignore".
    - choose:
        - conditions: '{{ command != "ignore" }}'
          sequence:
            # Take the requested action!
            - service: script.zha_button_actions
              data:
                click_count: '{{ click_count }}'
                command: '{{ command }}'
                command_modifier: '{{ command_modifier }}'
                manufacturer: '{{ manufacturer }}'
                remote: '{{ remote }}'

script:
  zha_button_actions:
    sequence:
      - choose:
          # Printer Power Button
          #   * Xiaomi Mijia Wireless Switch (round)
          - conditions: '{{ remote == "button_printer_power" }}'
            sequence:
              - service: switch.toggle
                entity_id: switch.printers

          # Family Room 5 button remote
          #   * IKEA Tradfri Remote Control
          - conditions: '{{ remote == "remote_family_room" }}'
            sequence:
              - choose:
                  # Button: Power (middle)
                  - conditions:
                      - condition: template
                        value_template: '{{ command == "toggle" }}'
                    sequence:
                      - choose:
                          # Single Click
                          - conditions: '{{ click_count == 1 }}'
                            sequence:
                              # Toggle the fan.
                              - service: fan.toggle
                                entity_id: fan.family_room
                          # Double click
                          - conditions: '{{ click_count == 2 }}'
                            sequence:
                              - service: switch.toggle
                                entity_id: switch.tv_family_room
                          # Triple click
                          - conditions: '{{ click_count == 3 }}'
                            sequence:                        
                              - choose:
                                  # The door is locked
                                  - conditions: '{{ states("lock.front_door")|lower|trim == "locked" }}'
                                    sequence:
                                      - service: lock.unlock
                                        entity_id: lock.front_door
                                      
                                      - service: input_boolean.turn_on
                                        entity_id: input_boolean.leave_unlocked
                                # The door is unlocked
                                default:
                                  - service: input_boolean.turn_off
                                    entity_id: input_boolean.leave_unlocked
                                  
                                  - service: lock.lock
                                    entity_id: lock.front_door
                          # Quadruple Click
                          - conditions: '{{ click_count == 4 }}'
                            sequence:
                              - service: input_boolean.toggle
                                entity_id: input_boolean.guest_mode

                  # Brightness Up (top)
                  - conditions: '{{ command == "step_with_on_off" }}'
                    sequence:
                      - choose:
                          # Single Click
                          - conditions: '{{ click_count == 1 }}'
                            sequence:
                              - service: light.turn_on
                                data:
                                  entity_id: light.family_room
                                  brightness_pct: 100
                          # Double click
                          - conditions: '{{ click_count == 2 }}'
                            sequence:
                              - service: light.turn_on
                                data:
                                  entity_id: light.table_lamp
                                  brightness_pct: 100

                  # Brightness down (bottom)
                  - conditions: '{{ command == "step" }}'
                    sequence:
                      - choose:
                          # Single Click
                          - conditions: '{{ click_count == 1 }}'
                            sequence:
                              - service: light.turn_off
                                entity_id:
                                  - light.family_room
                                  - light.table_lamp
                          # Double click
                          - conditions: '{{ click_count == 2}}'
                            sequence:
                              - service: light.turn_off
                                entity_id: light.table_lamp

                  ###############################
                  # SINGLE CLICK / HOLD BUTTONS #
                  ###############################

                  # Single Click: Arrow left (right)
                  - conditions: '{{ command == "press" and command_modifier == 256 }}'
                    sequence:
                      - service: light.turn_on
                        data:
                          entity_id: light.family_room_floor_lamp
                          brightness_pct: 100
                  # Single Click: Arrow right (left)
                  - conditions: '{{ command == "press" and command_modifier == 257 }}'
                    sequence:
                      - service: light.turn_off
                        entity_id: light.family_room_floor_lamp

                  # Hold: Brightness Up (top)
                  - conditions: '{{ command == "move" }}'
                    sequence:
                      - service: light.turn_on
                        data:
                          entity_id:
                            - light.family_room
                            - light.table_lamp
                          brightness_step_pct: "-20"
                  # Hold: Brightness down (bottom)
                  - conditions: '{{ command == "move_with_on_off" }}'
                    sequence:
                      - service: light.turn_on
                        data:
                          entity_id:
                            - light.family_room
                            - light.table_lamp
                          brightness_step_pct: "20"
                  # Hold: Arrow left (left)
                  - conditions: '{{ command == "hold" and command_modifier == 3329 }}'
                    sequence:
                      - service: light.turn_on
                        data:
                          entity_id: light.family_room_floor_lamp
                          brightness_step_pct: "-20"
                  # Hold: Arrow right (right)
                  - conditions: '{{ command == "hold" and command_modifier == 3328 }}'
                    sequence:
                      - service: light.turn_on
                        data:
                          entity_id: light.family_room_floor_lamp
                          brightness_step_pct: "20"

          # Bedroom Double Switch
          #   * Xiaomi Double Rockers, Battery Powered
          - conditions: '{{ remote == "remote_bedroom_double_rocker" }}'
            sequence:
              - choose:
                  # Single Click: Left
                  - conditions: '{{ command == "left_single" }}'
                    sequence:
                      - service: light.toggle
                        entity_id: light.bedroom
                  # Single Click: Right
                  - conditions: '{{ command == "right_single" }}'
                    sequence:
                      - service: light.toggle
                        entity_id: light.brian
                  # Single Click: Both
                  - conditions: '{{ command == "both_single" }}'
                    sequence:
                      - service: light.toggle
                        entity_id: light.glowforge
                  # Double Click: Left
                  - conditions: '{{ command == "left_double" }}'
                    sequence:
                      - service: switch.toggle
                        entity_id: switch.sound_machine
                  # Double Click: Right
                  - conditions: '{{ command == "right_double" }}'
                    sequence:
                      - service: switch.toggle
                        entity_id: switch.bedroom_fan
                  # Double Click: Both
                  - conditions: '{{ command == "both_double" }}'
                    sequence:
                      - service: switch.toggle
                        entity_id:
                          - switch.sound_machine
                          - switch.bedroom_fan
2 Likes

Just to be clear:
ZHA integration so no additional hub or gateway is required for this integration, is it correct?
I’m currently using Conbee II for all my zigbee integrations, it would be great to use it for this remote, too.
Thanks!
-f

I am also using a Conbee II with the ZHA integration. I think that answers your question.

1 Like

Hi,

Thank you for your post! I have been trying to understand it for hours now and no luck :smiley:. I am very new to Hassio and coding in general. I wanted to add a double click to my TRADFRI Switch on/off - the simple rocker switch with dimmer they have - to go to max brightness on my TRADFRI light.

Can you please help me :frowning:? I am literally drowning in this. I didn’t even manage to create the script and helper to store the click data :smiley:. I am very new to Hassio and coding in general. I wanted to add a double click to my TRADFRI Switch on/off - the simple rocker switch with dimmer they have - to go to max/min brightness on my TRADFRI light.

Can you please help me :frowning:? I am literally drowning in this. I didn’t even manage to create the script and helper to store the click data :smiley:.

Thank you for your help! That’s huge!

I created this complex coding example before Blueprints existed. Have you seen this Blueprint? This claims to work as a dimmer.

Thank you! Yes, I am using this blueprint. But it’s not supporting double clicks which would be awesome for going to max brightness immediately and not waiting for the slow gradient dimming.

Could u descripe how u did setup the event functions for duble click ?

Thank you for asking! I failed to remember to update my example code here and on my blog, but I did post an optimized version of this code a few posts above this one.

The following line causes the Automation to restart (before taking any more actions). (Read more about Automation Modes.)

mode: restart

I optimized this code to count the number of clicks which occur within 0.5 seconds of each other, before taking actions based on which button was clicked and how many times it was clicked.

To minimize up front processing, I start with the assumption that any zha_events are probably button click events. So I don’t do any filtering at this point.

  trigger:
    platform: event
    event_type: zha_event

The first action increments a counter.

    - service: counter.increment
      entity_id: counter.zha_button_click

The delay of 0.5 seconds allows for another click to occur before continuing. Should another click occur before another action is taken, this automation will restart.

    - delay:
        seconds: 0.5

Next I store the number of clicks in a variable, then reset the button click counter to zero.

    - variables:
        click_count: '{{ states("counter.zha_button_click") }}'

    - service: counter.reset
      entity_id: counter.zha_button_click

After that all of the details about which action was requested is sorted out in the variables: section.

  1. The remote: variable decides if the event came from one of my remotes (and which remote sent the clicks).
  2. Since some remotes handle click counts internally the click_count: variable sorts out which count value to use.
  3. The command: variable stores the requested command or decides if the event should be ignored as an event unrelated to remote button clicks.

Finally the choose: action passes the processed variables to the zha_button_actions script.

Now that you understand how the automation works, if you read through the script you will notice the comments do a pretty thorough job of explaining which choose: condition applies a command sequence to which remote button event. :slight_smile:

2 Likes

Many thanks @BrianHanifin , I have been somewhat baffled by how to access and interpret the output of a new MOEs 4 gang Scene Switch I’ve bought to evaluate.

What’s got me stumped amongst the otherwise very erudite explanation of your art, is how you determined and stored the device variables values. This bit here:

    - variables:
        remotes:
          # Ikea
          "ec:1b:bd:ff:fe:23:9c:ee": "remote_family_room"
      
          # Xiaomi
          "00:15:8d:00:01:2d:d7:c3": "button_printer_power"
          "00:15:8d:00:02:83:e2:b6": "remote_bedroom_double_rocker"
        manufacturers:
          "ec:1b:bd:ff": "ikea"
          "00:15:8d:00": "xiaomi"

I presume this info is found by watching the zha_events coming through, but, pardon my ignorance, how do you do that?

You are exactly right! Admittedly this code is more advanced than most users will need. I like to try to challenge my programming abilities from time to time, so I created a script that could handle my various remotes.

Using the following guide, you can create your own automation to handle unique button presses.

  1. Go to Developer Tools > Events.
  2. Under Listen to events type zha_event.
  3. Click Start listening.
  4. Press a button on your MOES Switch.

Open your Home Assistant instance and show your event developer tools.

The event created by pressing the center button once on my IKEA 5 button remote:

{
    "event_type": "zha_event",
    "data": {
        "device_ieee": "ec:1b:bd:ff:fe:23:9c:ee",
        "unique_id": "ec:1b:bd:ff:fe:23:9c:ee:1:0x0006",
        "device_id": "fc6086430b1711eba700f15cccf019c9",
        "endpoint_id": 1,
        "cluster_id": 6,
        "command": "toggle",
        "args": []
    },
    .
    .
    .
}

There you can gather the information which is unique to your button presses for each device. For this button I see the "device_ieee" is the unique identifier for this remote. The unique "command" identifying which button was pressed is "toggle".

Pressing the Top button outputs this event:

{
    "event_type": "zha_event",
    "data": {
        "device_ieee": "ec:1b:bd:ff:fe:23:9c:ee",
        "unique_id": "ec:1b:bd:ff:fe:23:9c:ee:1:0x0008",
        "device_id": "fc6086430b1711eba700f15cccf019c9",
        "endpoint_id": 1,
        "cluster_id": 8,
        "command": "step_with_on_off",
        "args": [
            0,
            43,
            5
        ]
    },
    .
    .
    .
}

By looking for the differences between all of the events I was able to determine most of this remote’s button presses can be distinguished by simply using the "command" values. However, in this case the right and left buttons are identified with the same "press" command. Looking for further differences I noticed the first "args" value was 256 for the right button, and 257 for the left button.

Every button’s "data" will be a bit different. As long as you can identify a consistent value difference between each button press, you can create code to handle each unique press.

P.S. My code is intended to allow Home Assistant to count multiple rapid button presses in remotes which immediately report single clicks. Some remotes handle multi-clicks internally, which makes this code unnecessary. So try double and triple clicking your buttons to see if it’s event reports how many times the button was clicked. If your remote handles multiple button clicks internally, then the extra complexity of this script is unnecessary for you.

Many thx @BrianHanifin for the detailed reply,

Much appreciated. I will give that a go shortly.

I have also been trying via the zigbee2mqtt platform using a ConBee II, and although the device will pair there aren’t currently working device or conversion definitions available. It looks pretty daunting following the procedures documented for that platform to integrate a new device.

I attempted to give that a go @BrianHanifin , but nothing shows up.

The device is paired though only one of four switches actually gets registered: