deCONZ All-In-One IKEA five button remote with actions - MAJOR UPDATE with simplified setup

Tags: #<Tag:0x00007f326a5fa728> #<Tag:0x00007f326a5fa520> #<Tag:0x00007f326a5fa2f0> #<Tag:0x00007f326a5fa200>

“One Remote To Rule 'Em All”

Introdution

Using a single IKEA five button remote, the round one, to :

  • choose a light, or a group of lights, with short press on the arrows
  • toggle the selected light on/off, with short press on Power
  • in- or decrease the brightness with a given value when short pressing the dim up or down
  • in- or decrease the brightness seamlessly, with maximum time on the dimming, when long pressing the dim up or down
  • turn on all lights in the group with 100% brigthness, when long pressing Power
  • long pressing the arrows is customizable with userdefined actions

Requirements

Firstly, we are going to use a IKEA five button remote paired up with deCONZ but unassigned of any deCONZ groups.

Since we need to store the current light choosen between each activation af the automation, we are in need af of placeholder. For this we are using a counter. This can be configured in the or YAML.
Example:

counter:
  idx_livingroom:

The counter only needs a enity_id - the rest is handled by the blueprint.

Creation of the automation

The Blueprint offers the following parameters to be used in the automation:

  • Step, a percentage value which the brightness should be alter when short pressing the dim buttons.
  • Transition short, the time used when doing a short press
  • Transition long, the time used when doing a long press (0 - 100%)
  • Long press left (optional), action(s) to perform when long pressing left button
  • Long press right (optional), action(s) to perform when right pressing left button

Using the blueprint in YAML mode

If you decide to make the automation directly in YAML it would look like this:

automation:
  - alias: Kitchen and Livingroom
    description: The All-in-One remote formuse in the kitchen and the livingroom.
    use_blueprint:
      path: J-Lindvig/all_in_one_remote.yaml
      input:
        long_press_transition: '30'
        remote: c08819d98af8b341299ea47c702e9a37
        counter: counter.all_in_one_test_id
        short_press_transition: '0.5'
        dim_step_pct: '20'
          lights:
            entity_id:
              - light.dining_table
              - light.kitchen_sink
              - light.livingroom

The blueprint

blueprint:
  name: deCONZ - IKEA remote All-In-One remote with actions
  description: |
    This blueprint utilize a IKEA five button (puck) remote to control a group of lights individually.
    
    REQUIREMENTS:
    ------------------------------------------------------------------------------------------------------------------------------------------------------
    Since we need to store the current light choosen between each activation af the automation, we are in need af of placeholder.
    For this we are using a counter. This can be configured in the or YAML.
    Example:

    counter:
      idx_livingroom:

    The counter only needs a enity_id - the rest is handled by the blueprint.

    HOW THE REMOTE WORKS:
    ------------------------------------------------------------------------------------------------------------------------------------------------------
    LEFT AND RIGHT:
    With a short press on either the left/right arrow, you will be able to switch between the light in the group. The current selected light give a short flash indicating your selection.
    Long press is assignable to any action(s).
    
    DIM UP OR DOWN:
    Short press will in/decrease brightness with the specified step in percent and short transition time.
    Long pres will in/decrease brightness continuesly using a transition time stating how long a dim from 0 to 100% shoiuld take.
    
    POWER:
    Short press toggles the selected light
    Long press turns on ALL lights in the group at 100%

    HOW THE AUTOMATION WORKS:
    ------------------------------------------------------------------------------------------------------------------------------------------------------
    We listen on "deconz_event" and extract the numeric representation of the pressed button and duration.

    The counter is updated with the ID of the current light.
    Secondly we choose the appropriate action from the given event.
    
    USING THE BLUEPRINT IN YAML MODE:
    ------------------------------------------------------------------------------------------------------------------------------------------------------
    If you decide to make the automation directly in YAML it would look like this:

    automation:
      - alias: Kitchen and Livingroom
        description: The All-in-One remote formuse in the kitchen and the livingroom.
        use_blueprint:
          path: J-Lindvig/all_in_one_remote.yaml
          input:
            long_press_transition: '30'
            remote: c08819d98af8b341299ea47c702e9a37
            counter: counter.all_in_one_test_id
            short_press_transition: '0.5'
            dim_step_pct: '20'
              lights:
                entity_id:
                  - light.dining_table
                  - light.kitchen_sink
                  - light.livingroom
  source_url: https://github.com/J-Lindvig/HomeAssistant/blob/master/blueprints/automation/J-Lindvig/all_in_one_remote.yaml
  domain: automation

  input:
    lights:
      name: Light(s)
      description: Choose the lights you wish to control
      selector:
        target:
          entity:
            domain: light
    
    remote:
      name: Remote
      description: IKEA five button remote to use
      selector:
        device:
          integration: deconz
          manufacturer: IKEA of Sweden
          model: TRADFRI remote control
    
    counter:
      name: ID holder
      description: "The counter holding the ID of the current light"
      selector:
        entity:
          domain: counter

    dim_step_pct:
      name: Step
      description: Step, in percent, to de- or increase brightness
      default: 20
      selector:
        number:
          min: 5.0
          max: 100.0
          mode: slider
          step: 5.0
          unit_of_measurement: "%"

    short_press_transition:
      name: Transition short
      description: Transtion time used when doing a short press
      default: 0.5
      selector:
        number:
          min: 0.0
          max: 2.0
          mode: slider
          step: 0.1
          unit_of_measurement: "seconds"

    long_press_transition:
      name: Transition long
      description: Transtion time used when doing a long press (0 - 100%)
      default: 30
      selector:
        number:
          min: 5.0
          max: 50.0
          mode: slider
          step: 1.0
          unit_of_measurement: "seconds"

    button_left_long:
      name: Left button - long press
      description: Action to run on long left button press
      default: []
      selector:
        action: {}

    button_right_long:
      name: Right button - long press
      description: Action to run on long right button press
      default: []
      selector:
        action: {}

mode: restart
max_exceeded: silent
variables:
  lights: !input lights
  counter: !input counter
  idx: 0
  dim_step_pct: !input dim_step_pct
  dim_step: 0
  prev_state: ""
  prev_brightness: 0
  short_press_transition: !input short_press_transition
  long_press_transition: !input long_press_transition
trigger:
- platform: event
  event_type: deconz_event
  event_data:
    device_id: !input remote
action:
# EXTRACT OR CALCULATE SOME OF THE VARIABLES
- variables:
    event: "{{ trigger.event.data.event }}"
    lights: "{{ lights['entity_id'] }}"
    idx: "{{ states(counter) }}"
    dim_step: "{{ (254 / (long_press_transition | int)) | round(0, 'floor') }}"

# SET THE MAXIMUM OF THE COUNTER TO THE LENGTH OF THE LIGHTS
- service: counter.configure
  data:
    entity_id: "{{ counter}}"
    maximum: "{{ lights | length - 1 }}"

# PERFORM A ACTION BASED ON THE EVENT
- choose:
  # LEFT OR RIGHT
  # Find the previous or next light and give it a short flash
  - conditions: "{{ event in (4002, 5002) }}"
    sequence:
      - variables:
          idx: >-
            {%- if event == 4002 -%}
              {{ (idx - 1) if idx > 0 else state_attr(counter, 'maximum') }}
            {%- else -%}
              {{ (idx + 1) if idx < state_attr(counter, 'maximum') else 0 }}
            {%- endif %}
          prev_state: "{{ states(lights[idx]) }}"
      - service: counter.configure
        data:
          entity_id: "{{ counter }}"
          value: "{{ idx }}"
          initial: "{{ idx }}"

      # Turn on the light and save the brightness of the light
      - service: light.turn_on
        data:
          entity_id: "{{ lights[idx] }}"
      - variables:
          prev_brightness: "{{ state_attr(lights[idx], 'brightness') | int }}"

      # Flash the light - HA style
      - repeat:
          count: 2
          sequence:
            - delay:
                milliseconds: 500
            - service: light.turn_off
              data:
                entity_id: "{{ lights[idx] }}"
            - delay:
                milliseconds: 500
            - service: light.turn_on
              data:
                entity_id: "{{ lights[idx] }}"
                brightness_pct: 100

      # Restore previous brightness
      - service: light.turn_on
        data:
          entity_id: "{{ lights[idx] }}"
          brightness: "{{ prev_brightness | int }}"

      # Take a second and restore previous state
      - delay: 1
      - service: "light.turn_{{ prev_state }}"
        data:
          entity_id: "{{ lights[idx] }}"

  # SHORT PRESS POWER
  # Toggle the choosen light
  - conditions: "{{ event == 1002 }}"
    sequence:
      - service: light.toggle
        data:
          entity_id: "{{ lights[idx] }}"

  # LONG PRESS POWER
  # Turn on all lights at 100%
  - conditions: "{{ event == 1001 }}"
    sequence:
      - service: light.turn_on
        target: !input lights
        data:
          brightness_pct: 100

  # SHORT PRESS UP OG DOWN (DIMMING IN STEPS)
  # Dim the choosen light up or down
  - conditions: "{{ event in (2002, 3002) }}"
    sequence:
      - service: light.turn_on
        data:
          entity_id: "{{ lights[idx] }}"
          brightness_step_pct: "{{ ( dim_step_pct | int ) if event == 2002 else (0 - ( dim_step_pct | int )) }}"
          transition: "{{ short_press_transition }}"

  # LONG PRESS UP OR DOWN (FLOW DIMMING) - HA STYLE...!!!
  - conditions: "{{ event in (2001, 3001) }}"
    sequence:

      # Turn on the light
      - service: light.turn_on
        data:
          entity_id: "{{ lights[idx] }}"

      # While pressing the button in/decrease the brightness with the calculated dim_step
      - repeat:
          while: []
          sequence:
            - service: light.turn_on
              data:
                entity_id: "{{ lights[idx] }}"
                brightness: "{{ state_attr(lights[idx], 'brightness') + (0 - dim_step if event == 3001 else dim_step) }}"
            - delay: 1

  # LONG PRESS LEFT
  - conditions: "{{ event == 4001 }}"
    sequence: !input button_left_long

  # LONG PRESS RIGHT
  - conditions: "{{ event == 5001 }}"
    sequence: !input button_right_long
3 Likes

Thank you for your contribution! Well documented with clean code. I like the technique you used to initialize the input_select.

My only suggestion is that this template:

                brightness: >-
                  {%- set brightness = state_attr(light, 'brightness') | int %}
                  {%- set step = dim_step %}
                  {% if event == 3001 %}
                    {% set step = 0 - step %}
                  {% endif %}
                  {{ state_attr(light, 'brightness') | int + step }}

can be reduced to this:

                brightness: >-
                  {{ state_attr(light, 'brightness') + (0 - dim_step if event == 3001 else dim_step) }}

There’s no need to use an int filter in this case because the brightness attribute is already an integer value.

Screenshot from 2021-01-13 15-44-09

Thank you very much for your kind words and optimization.
I will implement the improvement as soon as possible.

Best wishes

Jacob

I don’t have an IKEA 5-button remote to test but what prevents this repeat from increasing brightness to more than 255 or decreasing to less than zero?

      # While pressing the button in/decrease the brightness with the calculated dim_step
      - repeat:
          while: []
          sequence:
            - service: light.turn_on
              data:
                entity_id: "{{ light }}"
                brightness: "{{ state_attr(light, 'brightness') + (0 - dim_step if event == 3001 else dim_step) }}"
            - delay: 1

so awesome @J-Lindvig now it is released!! great blueprint

Actually not, but it doesn’t matter since HA simply turns the off when it reaches 0 and ignores values above 255. Furthermore the loop stops when the button is released.
So for the sake of simplicity I have choosen not to perform a test. This is the same reason why dim_step is calculated outside of the while scope. But again thank you for interest.

Sorry for the inconvenience, apparently only 1 block of code is allowed to make the blueprint importable into Home Assistant. Therefore the 3 examples is placed as blockqoutes.

Thanks! I just tested it (using Developer tools > Services) and confirmed that it doesn’t exactly ignore an out-of-range value but converts it to the nearest range limit.

For example, if the light’s brightness is 50 and the command is to set it to -10, the brightness will be set to 0 (lower range limit). Conversely, if the command is 300, the brightness is set to 255 (upper range limit).

However, you are correct, because this behavior means you don’t have to check the brightness values in the repeat. Home Assistant will simply “do the right thing” with out-of-range brightness values.

if anyone is able to test it with wifi bulbs, and hear if there is any problem with dim up and down on long press, i have some weird experience with my yeelight bulbs :slight_smile: