ZHA - IKEA STYRBAR E2313 - Media Player Control (White 4-button remote)

Hey everyone! 
I’ve been working on a blueprint for controlling a media player with the IKEA STYRBAR E2313 (the white 4-button remote) via ZHA, and after some debugging I’m happy to share it here.
Button Layout
Button Short press Long press
â–² Top Play / Pause Mute toggle
▼ Bottom Stop (empty — customize freely)
Left Previous track Volume down (repeating)
Right Next track Volume up (repeating)
Features
Play/Pause, Stop, Next/Previous track on short press
Smooth volume control on long press — holds and repeats until you release the button
Mute toggle on long hold of the top button
Configurable volume step and repeat interval
Works with any media_player entity (Sonos, Chromecast, Music Assistant, VLC, etc.)
Quirks handled
This remote has two known ZHA quirks that required special handling:
- The
on-event quirk on left/right hold
When you hold the
or
button, the remote fires this sequence of events:
press → on → hold → release
The extra on event would incorrectly trigger Play/Pause mid-hold. This blueprint uses wait_for_trigger with a 400ms window to detect whether a hold follows the on event — if so, Play/Pause is skipped.
2. Asymmetric hold behaviour on left vs. right
The
left button repeats hold events natively while held down. The
right button only sends a single hold event followed by release. Both volume actions now use the same loop pattern: adjust volume → wait for release or timeout → repeat if no release received.
Configuration
Setting Default Description
Remote — Your IKEA STYRBAR device in ZHA
Media player — The media player entity to control
Volume step 0.05 How much volume changes per tick (0.01–0.20)
Repeat interval 300ms Speed of volume repeat while holding (100–1000ms)
Blueprint YAML
Paste the YAML below into a new file in /config/blueprints/automation/ and reload blueprints, or use the import button.
blueprint:
name: IKEA STYRBAR E2313 - Media Player (ZHA)
description: >
Control a media player with the IKEA STYRBAR E2313 (white 4-button remote) via ZHA.
Button layout:
▲ Short press → Play / Pause
▲ Long press → Mute toggle
▼ Short press → Stop
▼ Long press → (empty / customize freely)
◀ Short press → Previous track
◀ Long press → Volume down (repeating)
▶ Short press → Next track
▶ Long press → Volume up (repeating)
Also compatible with E2001 (silver variant).
domain: automation
input:
remote:
name: STYRBAR Remote
description: Select your IKEA STYRBAR device from ZHA.
selector:
device:
integration: zha
manufacturer: IKEA of Sweden
model: Remote Control N2
media_player:
name: Media Player
description: The media player entity to control.
selector:
entity:
domain: media_player
volume_step:
name: Volume Step
description: How much volume changes per tick (0.01–0.20).
default: 0.05
selector:
number:
min: 0.01
max: 0.20
step: 0.01
mode: slider
volume_repeat_ms:
name: Repeat Interval (ms)
description: How fast volume changes while the button is held.
default: 300
selector:
number:
min: 100
max: 1000
step: 50
unit_of_measurement: ms
mode: slider
mode: restart
max_exceeded: silent
variables:
player: !input media_player
vol_step: !input volume_step
vol_repeat_ms: !input volume_repeat_ms
trigger:
- platform: event
event_type: zha_event
event_data:
device_id: !input remote
action:
- variables:
command: "{{ trigger.event.data.command }}"
args: "{{ trigger.event.data.args }}"
- choose:
# ▲ Short press → Play / Pause
# Waits briefly to detect if a hold follows (left/right quirk guard)
- conditions:
- condition: template
value_template: "{{ command == 'on' }}"
sequence:
- wait_for_trigger:
- platform: event
event_type: zha_event
event_data:
device_id: !input remote
command: hold
timeout:
milliseconds: 400
continue_on_timeout: true
- condition: template
value_template: "{{ wait.trigger is none }}"
- action: media_player.media_play_pause
target:
entity_id: !input media_player
# ▲ Long press → Mute toggle
- conditions:
- condition: template
value_template: "{{ command == 'move_with_on_off' }}"
sequence:
- action: media_player.volume_mute
target:
entity_id: !input media_player
data:
is_volume_muted: >
{{ not state_attr(player, 'is_volume_muted') }}
# ▼ Short press → Stop
- conditions:
- condition: template
value_template: "{{ command == 'off' }}"
sequence:
- action: media_player.media_stop
target:
entity_id: !input media_player
# ▼ Long press → (no action)
- conditions:
- condition: template
value_template: "{{ command == 'move' }}"
sequence: []
# ◀ Short press → Previous track
- conditions:
- condition: template
value_template: "{{ command == 'press' and args == [257, 13, 0] }}"
sequence:
- action: media_player.media_previous_track
target:
entity_id: !input media_player
# ◀ Long press → Volume down (loop until release)
- conditions:
- condition: template
value_template: "{{ command == 'hold' and args == [3329, 0] }}"
sequence:
- repeat:
while:
- condition: template
value_template: "{{ true }}"
sequence:
- action: media_player.volume_set
target:
entity_id: !input media_player
data:
volume_level: >
{{ [state_attr(player, 'volume_level') - vol_step, 0] | max }}
- wait_for_trigger:
- platform: event
event_type: zha_event
event_data:
device_id: !input remote
command: release
timeout:
milliseconds: !input volume_repeat_ms
continue_on_timeout: true
- condition: template
value_template: "{{ wait.trigger is none }}"
# ▶ Short press → Next track
- conditions:
- condition: template
value_template: "{{ command == 'press' and args == [256, 13, 0] }}"
sequence:
- action: media_player.media_next_track
target:
entity_id: !input media_player
# ▶ Long press → Volume up (loop until release)
- conditions:
- condition: template
value_template: "{{ command == 'hold' and args == [3328, 0] }}"
sequence:
- repeat:
while:
- condition: template
value_template: "{{ true }}"
sequence:
- action: media_player.volume_set
target:
entity_id: !input media_player
data:
volume_level: >
{{ [state_attr(player, 'volume_level') + vol_step, 1] | min }}
- wait_for_trigger:
- platform: event
event_type: zha_event
event_data:
device_id: !input remote
command: release
timeout:
milliseconds: !input volume_repeat_ms
continue_on_timeout: true
- condition: template
value_template: "{{ wait.trigger is none }}"
Tested on HA 2025.x with a STYRBAR E2313 (firmware 2.4.17) and Music Assistant. Let me know if you run into any issues or have suggestions! ![]()
