Zigbee2mqtt - Ikea Bilresa

This is based on another blueprint which I unfortunately are no longer able to find - arrrgh…

I set my Bilresa switch from matter to zigbee. The mentioned blueprint was only capable of switching lamps on/off but the whell did not have any effect on brightness.

The blueprint here - made by Gemini with only some short prompts, works flawless for me.

blueprint:
  name: Bilresa Scroll Controller V2 (Direct & Clean)
  author: whag (patched)
  description: >
    Steuert Licht, Media oder Klima über den IKEA Bilresa (Zigbee2MQTT).
    Behebt den Konflikt zwischen Tasten und Drehrad sowie das Verschlucken von Dimm-Schritten.
  domain: automation
  input:
    mqtt_topic:
      name: MQTT Topic
      description: "Das Zigbee2MQTT Topic deines Schalters (z.B. zigbee2mqtt/bilresa_wohnzimmer)."
      default: "zigbee2mqtt/FRIENDLY_NAME_HERE"
      selector:
        text:
    controlled_entity:
      name: Entity to Control
      description: "Die zu steuernden Entitäten (Licht, Media Player oder Klima)."
      selector:
        entity:
          domain: [light, media_player, climate]
          multiple: true
    control_mode:
      name: Control Mode
      description: "Wähle, wie das Drehrad regeln soll."
      default: light_brightness_direct
      selector:
        select:
          options:
            - {label: "Light - Brightness (Direct 1:1 Level)", value: light_brightness_direct}
            - {label: "Light - Brightness (Relative Steps)", value: light_brightness}
            - {label: "Light - Colour Temp", value: light_temp}
            - {label: "Light - Colour Wheel (RGB)", value: light_color}
            - {label: "Media Volume", value: media}
            - {label: "Climate Temperature", value: climate}

    step_brightness:
      name: Brightness Step Percentage
      description: "Prozentuale Änderung pro Dreh-Impuls (nur für Relative Steps)."
      default: 15
      selector:
        number: {min: 1, max: 100, step: 1, unit_of_measurement: "%"}
    step_temp:
      name: Colour Temp Step
      description: "Mired-Schritte pro Dreh-Impuls."
      default: 30
      selector:
        number: {min: 1, max: 100, step: 1}
    step_color:
      name: Colour Hue Step
      description: "Grad-Schritte auf dem Farbkreis (1-360)."
      default: 15
      selector:
        number: {min: 1, max: 360, step: 1, unit_of_measurement: "°"}
    step_media:
      name: Volume Step Percentage
      description: "Lautstärke-Änderung pro Impuls (0.01 bis 0.2)."
      default: 0.05
      selector:
        number: {min: 0.01, max: 0.2, step: 0.01}
    step_climate:
      name: Temperature Step
      description: "Temperatur-Schritte in °C."
      default: 0.5
      selector:
        number: {min: 0.1, max: 5, step: 0.1, unit_of_measurement: "°C"}

    session_timeout:
      name: Session Timeout
      description: "Sekunden für fortlaufende Dreh-Erkennung (für Relative Steps)."
      default: 2
      selector:
        number: {min: 0.5, max: 5, step: 0.5, unit_of_measurement: "s"}
    action_single_on: {name: Single On, default: [], selector: {action: {}}}
    action_single_off: {name: Single Off, default: [], selector: {action: {}}}
    action_double_on: {name: Double On, default: [], selector: {action: {}}}
    action_double_off: {name: Double Off, default: [], selector: {action: {}}}

mode: queued
max: 10
max_exceeded: silent

trigger:
  - platform: mqtt
    id: "trig_on"
    topic: !input mqtt_topic
    payload: "on"
    value_template: "{{ value_json.action }}"
  - platform: mqtt
    id: "trig_off"
    topic: !input mqtt_topic
    payload: "off"
    value_template: "{{ value_json.action }}"
  - platform: mqtt
    id: "trig_on_double"
    topic: !input mqtt_topic
    payload: "on_double"
    value_template: "{{ value_json.action }}"
  - platform: mqtt
    id: "trig_off_double"
    topic: !input mqtt_topic
    payload: "off_double"
    value_template: "{{ value_json.action }}"
  - platform: mqtt
    id: "trig_scroll"
    topic: !input mqtt_topic
    payload: "brightness_move_to_level"
    value_template: "{{ value_json.action }}"

variables:
  target_entity: !input controlled_entity
  mode: !input control_mode
  s_bright: !input step_brightness
  s_temp: !input step_temp
  s_color: !input step_color
  s_media: !input step_media
  s_climate: !input step_climate

action:
  - choose:
      - conditions: "{{ trigger.id == 'trig_on' }}"
        sequence: !input action_single_on
      - conditions: "{{ trigger.id == 'trig_off' }}"
        sequence: !input action_single_off
      - conditions: "{{ trigger.id == 'trig_on_double' }}"
        sequence: !input action_double_on
      - conditions: "{{ trigger.id == 'trig_off_double' }}"
        sequence: !input action_double_off

      - conditions: "{{ trigger.id == 'trig_scroll' }}"
        sequence:
          - variables:
              lvl: >
                {{ trigger.payload_json.action_level if trigger.payload_json.action_level is defined else trigger.payload_json.brightness }}
              new_val: "{{ 255 if lvl is none else lvl | int }}"
              # Aktuelle Helligkeit der Lampe als Referenz für Richtung heranziehen, falls Bilresa keinen Startwert liefert
              first_light: "{{ target_entity[0] if target_entity is iterable and target_entity is not string else target_entity }}"
              current_light_bri: "{{ state_attr(first_light, 'brightness') | int(128) }}"
              direction: >
                {% if new_val >= 254 %} 1
                {% elif new_val <= 5 %} -1
                {% elif new_val > current_light_bri %} 1
                {% else %} -1 {% endif %}

          - choose:
              # 1. DIREKTE 1:1 ÜBERNAHME (Empfohlen für Bilresa)
              - conditions: "{{ mode == 'light_brightness_direct' }}"
                sequence:
                  - service: light.turn_on
                    target:
                      entity_id: !input controlled_entity
                    data:
                      brightness: "{{ [1, [new_val, 255] | min] | max }}"
                      transition: 0.2

              # 2. RELATIVE SCHRITTE
              - conditions: "{{ mode == 'light_brightness' }}"
                sequence:
                  - service: light.turn_on
                    target:
                      entity_id: !input controlled_entity
                    data:
                      brightness_step_pct: "{{ s_bright * direction }}"
                      transition: 0.2

              - conditions: "{{ mode == 'light_temp' }}"
                sequence:
                  - service: light.turn_on
                    target:
                      entity_id: !input controlled_entity
                    data:
                      color_temp: >
                        {% set current = state_attr(first_light, 'color_temp') | int(370) %}
                        {% set min_m = state_attr(first_light, 'min_mireds') | int(153) %}
                        {% set max_m = state_attr(first_light, 'max_mireds') | int(500) %}
                        {{ [min_m, [current - (s_temp * direction), max_m]|min]|max }}
                      transition: 0.2

              - conditions: "{{ mode == 'light_color' }}"
                sequence:
                  - service: light.turn_on
                    target:
                      entity_id: !input controlled_entity
                    data:
                      hs_color:
                        - "{{ ( (state_attr(first_light, 'hs_color')[0] | default(0) | float) + (s_color * direction) ) % 360 }}"
                        - "{{ (state_attr(first_light, 'hs_color')[1] | default(100) | float) }}"
                      transition: 0.2

              - conditions: "{{ mode == 'media' }}"
                sequence:
                  - service: >
                      {% if direction == 1 %} media_player.volume_up
                      {% else %} media_player.volume_down {% endif %}
                    target:
                      entity_id: !input controlled_entity

              - conditions: "{{ mode == 'climate' }}"
                sequence:
                  - service: climate.set_temperature
                    target:
                      entity_id: !input controlled_entity
                    data:
                      temperature: "{{ state_attr(first_light, 'temperature') | float(20) + (s_climate * direction) }}"

Thanks for sharing.
I have 10 bilresa remotes (2 buttons model) and kajplats bulbs. It is possible to change color temperature on double click? Like touchlink mode?
Is possible to get touchlink mode working if bilresa is integrated in home assistant via matter, zha or z2m?
Thanks :hugs: