Pairing IKEA KAJPLATS and BILRESA Devices Over Matter-over-Thread and Building a Home Assistant Blueprint
IKEA's new KAJPLATS bulb and BILRESA remotes ship with Matter-over-Thread firmware and a Zigbee-capable radio. Pair them the way the quick-start card suggests and they bond to each other over Zigbee Touchlink, which pulls both devices off Thread and out of Home Assistant. This guide commissions them over Matter with a QR code instead, explains why the remotes cannot bind directly to the bulb, and finishes with two reusable Home Assistant Blueprints, one for the BILRESA two-way switch and one for the scroll wheel.
For the story behind this build, read Fun with the New IKEA Smart Devices on Frizzle Tech Blog.
Prerequisites
You need a working Home Assistant install with the Matter Server add-on running, at least one Thread border router on the same network, and the Home Assistant Companion App on a phone. Matter commissioning relies on local IPv6 and mDNS, so the phone, the border router, and Home Assistant must share a LAN that passes multicast traffic.
- IKEA KAJPLATS E26 smart bulb, plus a lamp to hold it.
- IKEA BILRESA two-way switch (dual button) and BILRESA scroll wheel, with AAA batteries.
- A Thread border router (for example a Home Assistant Connect ZBT-2, a Nest Hub, or a HomePod).
- Home Assistant with the Matter Server add-on, and the Companion App on your phone.
- An IPv6-enabled LAN with working local mDNS discovery.
Step 1: Sync Thread Credentials and Commission Over Matter
Do not hold the remote near the bulb and press the pairing button four times. That starts Zigbee Touchlink, which bonds the two devices directly and removes them from Thread. Commission each device separately instead.
On a new Android phone, Bluetooth transfer can succeed while the local Matter handshake times out. Fix that before you scan anything. In the Companion App, open Settings, then Companion App, then Troubleshooting, and choose Sync Thread credentials. Next, confirm your preferred Thread network under Android Settings, then Google, then Devices & sharing, then Thread networks. If the handshake still times out, turn off Private DNS temporarily and restart the phone so Google Play Services picks up the fresh Thread dataset.
Put the device in Matter pairing mode. For a BILRESA, hold the pairing button inside the battery compartment for about 10 seconds, until the LED pulses. For a KAJPLATS, power cycle it 6 times. Then open Settings, then Devices & Services, then Add Device, choose Add Matter device, and scan the QR code on the packaging. Repeat for each remote and the bulb.
Step 2: Understand Touchlink, Zigbee, and the Matter Switch Endpoint
Zigbee is a valid alternative. The radios are dual-protocol, so the four-press sequence can pair a device to a Zigbee coordinator such as ZHA or Zigbee2MQTT. There, standard cluster binding with genOnOff and genLevelCtrl works, so a remote can control a bulb without the hub in the loop. The tradeoff is that you lose Matter multi-admin onboarding and Thread routing for that device, and you must commit to one stack per device.
On Matter, the Matter Server web UI on port 5580 shows what IKEA built. The node interview for the scroll wheel reports the following:
VendorName: IKEA of Sweden
ProductName: BILRESA scroll wheel
Matter version: 1.3.0
All device types: Ota Requestor / Power Source / Root Node / Generic Switch
The remotes are Generic Switch (0x000F) devices with no Binding cluster (0x001E). They cannot send unicast commands to a bulb, so each press arrives in Home Assistant as an event entity with types such as multi_press_1, long_press, and long_release. Something on the hub has to turn those events into light commands, and a Blueprint is the cleanest way to do that.
Step 3: Deploy the BILRESA Two-Way Switch Blueprint
Save this file to /path/to/homeassistant/blueprints/automation/ikea/bilresa_dual_button_matter.yaml. Button 1 turns the light on and a long press brightens it. Button 2 turns it off and a long press dims it. The actions strictly filter on multi_press_1 for clicks so Home Assistant does not fire on both initial_press and release.
blueprint:
name: IKEA BILRESA Two-Way Switch (Matter) Light Controller
description: >
Bind an IKEA BILRESA dual-button Matter-over-Thread remote to a target light
or light group with single-press On/Off and long-press brightness stepping.
domain: automation
input:
button_1_event:
name: Button 1 (Up / On) Event Entity
description: The Matter event entity for Button 1 (for example, event.bilresa_dual_button_button_1)
selector:
entity:
filter:
- domain: event
integration: matter
button_2_event:
name: Button 2 (Down / Off) Event Entity
description: The Matter event entity for Button 2 (for example, event.bilresa_dual_button_button_2)
selector:
entity:
filter:
- domain: event
integration: matter
target_light:
name: Target Light
description: The KAJPLATS bulb or light group to control
selector:
target:
entity:
- domain: light
dim_step_pct:
name: Long-Press Brightness Step (%)
description: Percentage to brighten or dim on long press
default: 20
selector:
number:
min: 5
max: 50
unit_of_measurement: "%"
mode: queued
max: 10
triggers:
- trigger: state
entity_id: !input button_1_event
id: button_1
- trigger: state
entity_id: !input button_2_event
id: button_2
conditions:
- condition: template
value_template: >
{{ trigger.to_state.state not in ['unavailable', 'unknown'] }}
actions:
- variables:
event_type: "{{ trigger.to_state.attributes.event_type | default('') }}"
- choose:
- conditions:
- condition: trigger
id: button_1
- condition: template
value_template: "{{ event_type == 'multi_press_1' }}"
sequence:
- action: light.turn_on
target: !input target_light
- conditions:
- condition: trigger
id: button_1
- condition: template
value_template: "{{ event_type == 'long_press' }}"
sequence:
- action: light.turn_on
target: !input target_light
data:
brightness_step_pct: !input dim_step_pct
- conditions:
- condition: trigger
id: button_2
- condition: template
value_template: "{{ event_type == 'multi_press_1' }}"
sequence:
- action: light.turn_off
target: !input target_light
- conditions:
- condition: trigger
id: button_2
- condition: template
value_template: "{{ event_type == 'long_press' }}"
sequence:
- action: light.turn_on
target: !input target_light
data:
brightness_step_pct: "{{ -1 * (dim_step_pct | int) }}"
Reload automations, then create an automation from the Blueprint. Pick the two event entities (for example event.bilresa_dual_button_button_1 and event.bilresa_dual_button_button_2) and your target light (for example light.kajplats_desk_lamp).
Step 4: Deploy the BILRESA Scroll Wheel Blueprint
The BILRESA scroll wheel exposes 9 distinct event entities across its 3 selectable hardware channels. On the physical hardware, the endpoints map as follows:
- **Buttons 1, 4, and 7**: Spinning the wheel to the right (Clockwise / Up / Brighten).
- **Buttons 2, 5, and 8**: Spinning the wheel to the left (Counter-Clockwise / Down / Dim).
- **Buttons 3, 6, and 9**: Center push action (Toggle Light).
Channel 1 uses endpoints 1 to 3; Channel 2 uses endpoints 4 to 6; and Channel 3 uses endpoints 7 to 9. Home Assistant prefixes these event entities using the device name chosen during commissioning, such as event.bilresa_scroll_wheel_button_1 through event.bilresa_scroll_wheel_button_9.
When you first commission the scroll wheel, many of these entities are disabled by default in the Home Assistant entity registry. Enable them under Settings, then Devices and Services, then Matter, then your BILRESA device. Note that endpoints 4 through 9 display Unavailable or Unknown until each channel is actively clicked on the physical hardware for the first time.
Because the hardware gives you three independent channels, you can control three different rooms or lights from a single remote without building complex routing automations. To do that, instantiate this Blueprint three separate times: create one automation instance for Channel 1 (buttons 1 to 3) mapped to your primary desk lamp, a second instance for Channel 2 (buttons 4 to 6) mapped to a nightstand lamp, and a third instance for Channel 3 (buttons 7 to 9) mapped to your bedroom ceiling fixture. Switching channels on the remote shifts control across fixtures immediately.
Because IKEA implemented the wheel rotation under Matter's Generic Switch cluster rather than an analog dial, spinning the wheel emits button press events: turning 1 tick fires multi_press_1 ("Pressed once"), 2 ticks fires multi_press_2 ("Pressed twice"), and spinning faster fires multi_press_3 through multi_press_8 ("Pressed x times", where x is 3 to 8). The blueprint extracts the tick count directly from totalNumberOfPressesCounted (and event_type), scaling the brightness step proportionally so a gentle turn steps gently and a fast spin sweeps across the full brightness range smoothly.
Save the blueprint below to /path/to/homeassistant/blueprints/automation/ikea/bilresa_scroll_wheel_matter.yaml.
blueprint:
name: IKEA BILRESA Scroll Wheel (Matter) Light & Dimmer Controller
description: >
Control lights with an IKEA BILRESA Scroll Wheel Matter remote.
Supports single-press toggle on center push (Buttons 3, 6, or 9) and dynamic
velocity-scaled brightness adjustments when spinning the wheel (Buttons 1/4/7
for clockwise up, Buttons 2/5/8 for counter-clockwise down), scaling smoothly
across pressed once (1 tick), pressed twice (2 ticks), and pressed x times
(3 to 8 ticks).
domain: automation
input:
press_event:
name: Wheel Center Press Event Entity (Button 3, 6, or 9)
description: The Matter event entity for center push (e.g., event.bilresa_scroll_wheel_button_3 for Ch 1, button_6 for Ch 2, button_9 for Ch 3)
selector:
entity:
filter:
- domain: event
integration: matter
scroll_up_event:
name: Scroll Clockwise / Up Event Entity (Button 1, 4, or 7)
description: The Matter event entity for clockwise scroll (e.g., event.bilresa_scroll_wheel_button_1 for Ch 1, button_4 for Ch 2, button_7 for Ch 3)
selector:
entity:
filter:
- domain: event
integration: matter
scroll_down_event:
name: Scroll Counter-Clockwise / Down Event Entity (Button 2, 5, or 8)
description: The Matter event entity for counter-clockwise scroll (e.g., event.bilresa_scroll_wheel_button_2 for Ch 1, button_5 for Ch 2, button_8 for Ch 3)
selector:
entity:
filter:
- domain: event
integration: matter
target_light:
name: Target Light
description: The KAJPLATS bulb or light group to toggle and dim
selector:
target:
entity:
- domain: light
scroll_step_pct:
name: Base Brightness Step Per Scroll Tick (%)
description: Percentage to adjust brightness per tick. Scales dynamically for 1 tick (pressed once), 2 ticks (pressed twice), and 3-8 ticks (pressed x times).
default: 5
selector:
number:
min: 1
max: 25
unit_of_measurement: "%"
mode: restart
triggers:
- trigger: state
entity_id: !input press_event
id: wheel_press
- trigger: state
entity_id: !input scroll_up_event
id: wheel_up
- trigger: state
entity_id: !input scroll_down_event
id: wheel_down
conditions:
- condition: template
value_template: >
{{ trigger.to_state.state not in ['unavailable', 'unknown'] }}
actions:
- variables:
step: !input scroll_step_pct
event_type: "{{ trigger.to_state.attributes.event_type | default('') }}"
raw_count: "{{ trigger.to_state.attributes.totalNumberOfPressesCounted | default(0) | int }}"
ticks: >-
{% if raw_count in [1, 2, 3, 4, 5, 6, 7, 8] %}
{{ raw_count }}
{% elif event_type.startswith('multi_press_') %}
{{ [([event_type.replace('multi_press_', '') | int(1), 1] | max), 8] | min }}
{% else %}
1
{% endif %}
step_val: "{{ [((step | int) * (ticks | int)), 100] | min }}"
- choose:
- conditions:
- condition: trigger
id: wheel_press
- condition: template
value_template: "{{ event_type in ['multi_press_1', 'initial_press', ''] }}"
sequence:
- action: light.toggle
target: !input target_light
- conditions:
- condition: trigger
id: wheel_up
sequence:
- action: light.turn_on
target: !input target_light
data:
brightness_step_pct: "{{ step_val }}"
- conditions:
- condition: trigger
id: wheel_down
sequence:
- action: light.turn_on
target: !input target_light
data:
brightness_step_pct: "{{ -1 * (step_val | int) }}"
Early KAJPLATS firmware can add one to two seconds of delay because each press travels from the remote to the border router, to Home Assistant, and back to the bulb. Keep transitions short and leave the mode on restart for the wheel so fast scrolling does not pile up.
Hardware & Gear Used in This Guide
- IKEA KAJPLATS Smart Bulb: Matter-over-Thread bulb (E26 1100lm globe or E12 WS globe 800lm) that joins the mesh with a QR code.
- IKEA BILRESA Two-Way Switch: Dual-button remote that fires Up and Down events.
- IKEA BILRESA Scroll Wheel: Clickable wheel with three channels and nine event entities.
- IKEA GRILLPLATS Smart Outlet: Matter outlet that works with the same Blueprint pattern.
- Thread Border Router: Bridges your Thread mesh to the LAN so Home Assistant can reach each device.
What You Can Do Next
- Read the companion story on Frizzle Tech Blog for how the Touchlink surprise happened in a real house.
- Point the Blueprints at a light group so one remote controls every KAJPLATS bulb in a room, and tune the brightness step to taste.
- Set short transition times on the target lights to hide hub latency, then try the 3D-printed Skadis pegboard mount for a Tertial lamp that holds the bulb.
Later,
SteveO
