IKEA E2490 BILRESA Scroll Wheel

IKEA E2490 BILRESA Scroll Wheel Controller (Zigbee2MQTT + ZHA)

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

A unified blueprint for the IKEA E2490 BILRESA scroll wheel that works with both Zigbee2MQTT and ZHA integrations.

Features

Multi-Mode Scrolling

Control any combination of the following with the scroll wheel:

  • Brightness - Light brightness (1-255)
  • Volume - Media player volume (0.0-1.0)
  • Color Temperature - Light warmth/coolness
  • Hue - Light color (0-360°)

Smart Mode Cycling

  • Double-press ON cycles through your configured scroll modes
  • Only cycles through modes that have entities configured (e.g., if you only set up brightness and volume, it cycles between just those two)
  • Single mode? No cycling occurs, keeping things simple

Intelligent Controls

  • Single-press ON/OFF controls the appropriate entity for the current mode:
    • Light entity for brightness/color temp/hue modes
    • Media player entity for volume mode
  • Auto-reset (optional): Automatically returns to your default scroll mode after a period of inactivity

Volume Protection

  • Max volume limit prevents unexpected loud surprises
  • Lower max values also provide finer scroll precision

Required Helpers

To enable mode cycling and auto-reset features, create these two helpers (via UI or configuration.yaml):

input_select:
  e2490_scroll_mode:
    name: "E2490 Scroll Mode"
    options:
      - brightness
      - volume
      - color_temp
      - hue
    initial: brightness
    icon: mdi:gesture-swipe

input_datetime:
  e2490_last_activity:
    name: "E2490 Last Activity"
    has_date: true
    has_time: true

Note: These helpers are optional. Without them, the blueprint works in single-mode operation using your default scroll mode.

Configuration

  • Import the blueprint using the button above
  • Create a new automation from the blueprint
  • Select your E2490 device
  • Configure your target entities for the modes you want to use
  • (Optional) Select the helper entities for mode cycling and auto-reset
  • (Optional) Adjust reset timeout (default: 60 seconds) and max volume (default: 1.0)

Full Blueprint

3 Likes

Hi,

I have just tried this out and it’s probably the best blueprint I’ve found for the scroll wheel to control lights.

I haven’t tested the hue/colour options yet, but for dimming it’s highly responsive and very fast - I had tried using Matter and blueprints that use Matter, but the ones I tried felt slow and didn’t work as well.

I’ve been experimenting with the IKEA scroll wheel to control lights for a while and I had pretty much given up until I found this blueprint.

I currently use Moes/Tuya zigbee smart knobs to control lights, and they’re OK but I was hoping to change over to IKEA as they use rechargable batteries.

I am not sure if I will change though as even with this blueprint the IKEA scroll wheel isn’t quite perfect.

The main issue I have is that it works very well held in the hand and turning the wheel with your thumb, but I want something that works well attached to the wall - and the physical action of trying to turn the IKEA wheel when it’s attached to the wall is very awkward - it’s not very well designed for that use.

I won’t rush to replace all the light controls in my house just yet - but this blueprint is definitely the best I’ve found so far.

Thank you so much for this blueprint! I’m new to Zigbee and MQTT, and your work has been incredibly helpful.

I run two Zigbee2MQTT instances with separate topics (automating across two locations), which meant the hardcoded zigbee2mqtt topic didn’t quite work for my zigbee2mqtt_house setup. With some help, I modified the blueprint to add a configurable MQTT Base Topic input field, and now it works perfectly across both my instances.

The dual Z2M/ZHA support, mode cycling with helpers, and overall robustness is really impressive. The core logic is beautifully coded - my modification was tiny compared to the solid foundation you built.

If you’re interested in supporting multiple MQTT base topics out of the box, I’m happy to share the modification. Either way, thank you for creating such a well-designed blueprint!

Quick follow-up: Just realized the auto-reset timeout feature has a bug that causes it to fail silently.

The problem: Line 243’s datetime comparison throws TypeError: can't subtract offset-naive and offset-aware datetimes, which breaks the auto-reset functionality.

The fix: Replace:

yaml and (now() - (states(last_activity_helper) | as_datetime)).total_seconds() > reset_timeout

With:
yaml
and (as_timestamp(now()) - as_timestamp(states(last_activity_helper))) > reset_timeout

Converting to Unix timestamps before comparison avoids the timezone issue. Tested and working perfectly now!

I just tried this and I’m having some issues when using it with the media player mode. if i just use the scroll wheel it works fine but if i change the volume from something else from 50% to 20% and then try to turn it up again it goes to 60% instead of 30%.

Hi,

Thanks for this. I have configured this on my system and it is working fine with the button to turn on/off an associated zigbee light. However, when trying to use the scroll wheel to manage the brightness I get this error in the trace

Triggered by the event ‘zha_event’ at 26 January 2026 at 15:06:01

If: No action executed

Choose: Option 2 executed

Stopped because an error was encountered at 26 January 2026 at 15:06:01 (runtime: 0.02 seconds)

Error rendering data template: TypeError: ‘int’ object is not iterable

I am using ZHA and was hesitant to send this as it is probably just me being stupid somewhere but any advice welcome.

Thanks!

I’m getting this error too. I ‘took control’ of the blueprint and changed:

target:
entity_id: ‘{{ brightness_target }}’
data:
brightness: |
{% if lvl is none %}255{% else %}{{ (lvl|int)|min(255)|max(1) }}{% endif %}
transition: ‘{{ trans }}’

to be:

target:
entity_id: “{{ brightness_target }}”
data:
brightness: “{{ lvl }}”
transition: “{{ trans }}”

…and this worked. I’m not sure if the min/max is needed as I’ve never seen the value go outside of this when scrolling the wheel?

Thanks. In the end I used Gemini to help me fix this and took control like you did but changed the whole thing to the following, which also fine tuned some of the transition for me to feel a little smoother. It stripped out the non ZHA stuff as I am not using.

alias: Office Scroll Button Ceiling
triggers:
  - id: zha-on
    event_type: zha_event
    event_data:
      device_id: 7520a8b06ecc642c86889ecf9b5e78a3
      command: "on"
    trigger: event
  - id: zha-off
    event_type: zha_event
    event_data:
      device_id: 7520a8b06ecc642c86889ecf9b5e78a3
      command: "off"
    trigger: event
  - id: zha-level
    event_type: zha_event
    event_data:
      device_id: 7520a8b06ecc642c86889ecf9b5e78a3
      command: move_to_level
    trigger: event
actions:
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ trigger.id == 'zha-level' }}"
        sequence:
          - variables:
              current_brightness: >-
                {{ state_attr(brightness_target, 'brightness') | default(0) |
                int }}
              target_lvl: "{{ trigger.event.data.args[0] | default(0) | int }}"
              diff: "{{ (target_lvl - current_brightness) * scaling_factor }}"
              final_brightness: "{{ (current_brightness + diff) | round(0) | int }}"
          - action: light.turn_on
            target:
              entity_id: "{{ brightness_target }}"
            data:
              brightness: "{{ [ [final_brightness, 255] | min, 1 ] | max }}"
              transition: 0.1
      - conditions:
          - condition: template
            value_template: "{{ trigger.id == 'zha-on' }}"
        sequence:
          - action: light.turn_on
            target:
              entity_id: "{{ brightness_target }}"
      - conditions:
          - condition: template
            value_template: "{{ trigger.id == 'zha-off' }}"
        sequence:
          - action: light.turn_off
            target:
              entity_id: "{{ brightness_target }}"
variables:
  brightness_target: light.office_ceiling_light
  scaling_factor: 0.5
mode: restart
max_exceeded: silent
1 Like

I think there is a problem with this blueprint, which is triggered every time z2m posts a message.
I don’t understand this trigger :

Hi!
Thank you very.much for the blueprint.
I am using this scroll wheel as a volume controller for my onkyo avr but I have an issue that i dont know how to resolve.
My onkyo vokume is 0-80 with a step every 0.5.
When i use my.old ikea scroll wheel i can fine tune this for a very granular control that half a wheel rotate changes the volume by 0.5
With this blueprint i can only jump every 5 units of.volume and this is not so good.
How could I change this step to be smaller?
Thank you.

Its a shame we cannot control more than one device like matter.