Z2M - IKEA Symfonisk Gen2 [E2123] Media Control v1.55

Hi all,

Here’s a blueprint to support controlling a media player with an Ikea Symfonisk Gen2 remote. It’s designed to work with the device added via Zigbee2MQTT (Z2M) only.
image

I wanted to allow for the use of more than one of these devices but also avoid the need to find and copy and paste topic strings from the entity MQTT settings. You can just select your device from the list :slight_smile:

Hope you find it useful.

NOTE: It’s best to select “Legacy = False” in the specific settings for your controllers in the Z2M config.

Blueprint

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

blueprint:
# Media control via IKEA Symfonisk Gen2 - Shawsky April 2023 v1.55
# Updated April 2024 - Add additional filtering to prevent triggering from other devices/false positives. Thanks kenno.
# Updated April 2024 - Add support for device rename in upcoming Z2M release & allow legacy action for Play/Pause
# Updated September 2023 - Further updates for group/non grouped behaviour / fix issue for volume hold for grouped/non grouped. Allow 100 volume steps.
# Updated August 2023 - Resolve a volume issue for media players with no group_memeber attribute
# Updated June 2023 - Resolve filtering issue where multiple devices are in use
# Updated May 2023 - Add group volume control

# Volume changes partially based on https://gist.github.com/erkr/a437ebcb98a2b5ba2deebabd02f5ffae Eric Kreuwels
# and https://gist.github.com/alexwmaustin/2c25cfa1a0ade1ab9fc1ef0940289672 Alex Austin

  name: Z2M - IKEA Symfonisk sound controller GEN2 for media
  description: 
    'Control the selected media player (and any joined to it) with an IKEA Symfonisk sound controller GEN2 via Zigbee2MQTT (Z2M)

    Supports single press on media buttons and single, double and long press for the "dot" buttons.'
  domain: automation
  input:
    remote:
      name: Remote
      description: The IKEA Symfonisk controller GEN2 to use
      selector:
          device:
            filter:
            - integration: mqtt
              manufacturer: IKEA
              model: SYMFONISK sound remote gen2 (E2123)
            - integration: mqtt
              manufacturer: IKEA
              model: SYMFONISK sound remote, gen 2 (E2123)
    base_topic:
      name: Zigbee2MQTT Base mqtt topic
      description: The base topic configured in Zigbee2MQTT. If you haven't changed this, leave the default here ("zigbee2mqtt")
      default: zigbee2mqtt
    media_player:
      name: Media Player
      description: The media player to control with this automation
      selector:
        entity:
          domain: media_player
          multiple: false
    volume_steps:
      name: Volume number of steps
      description: Controls the volume scale. The default of 25 is the same scale as the Sonos app.
      default: 25
      selector:
        number:
          min: 5
          max: 100
          step: 5
          unit_of_measurement: "Num"
          mode: slider
    single_dot:
      name: Single Dot (Single)
      description: Action to run on single dot press
      default: []
      selector:
        action: {}
    single_dot_double_press:
      name: Single Dot (Double)
      description: Action to run on single dot double press
      default: []
      selector:
        action: {}
    single_dot_long_press:
      name: Single Dot (Long)
      description: Action to run on single dot long press
      default: []
      selector: 
        action: {}
    double_dot:
      name: Double Dot (Single)
      description: Action to run on double dot press
      default: []
      selector:
        action: {}
    double_dot_double_press:
      name: Double Dot (Double)
      description: Action to run on double dot double press
      default: []
      selector:
        action: {}
    double_dot_long_press:
      name: Double Dot (Long)
      description: Action to run on double dot long press
      default: []
      selector:
        action: {}
      
mode: restart
max_exceeded: silent

trigger_variables:
  base_topic: !input base_topic
  controller: !input remote

trigger:
  - platform: mqtt
    topic: "{{ base_topic }}/+/action"
condition:
  - condition: template
    value_template: "{{ trigger.topic == base_topic+'/'+device_attr(controller, 'name')+'/action' }} "  
action:
  - variables:
      controllertopic: "{{ base_topic }}/{{ device_attr(controller, 'name') }}/action"
      player: !input 'media_player'
      steps: !input volume_steps
      stepsize: '{{ 1.0 / steps }}'
  - choose:
    - conditions:
      - "{{ trigger.payload != ''}}"
      - "{{ trigger.topic == controllertopic }}"
      sequence:
        - choose:
          ## Commands

          # Play / Pause
          - conditions: "{{ trigger.payload == 'toggle' or trigger.payload == 'play_pause' }}"
            sequence:
            - service: media_player.media_play_pause
              entity_id: !input 'media_player'
          # Next Track
          - conditions: "{{ trigger.payload == 'track_next' }}"
            sequence:
            - service: media_player.media_next_track
              entity_id: !input 'media_player'
          # Previous Track
          - conditions: "{{ trigger.payload == 'track_previous' }}"
            sequence:
            - service: media_player.media_previous_track
              entity_id: !input 'media_player'

          ## Volume for media players supporting groups

          # Volume Up Press
          - conditions: "{{ trigger.payload == 'volume_up' and state_attr(player, 'group_members') != none and state_attr(player, 'group_members') != [] }}"
            sequence:
              - repeat:
                  for_each: "{{ state_attr(player, 'group_members') }}"
                  sequence:
                  - service: media_player.volume_set
                    target:
                      entity_id: "{{ repeat.item }}"
                    data:
                      volume_level: >-
                        {% set volume = state_attr(repeat.item, "volume_level") + stepsize %}
                        {{ 1.0 if volume > 1.0 else volume }}

          # Volume Down Press
          - conditions: "{{ trigger.payload == 'volume_down' and state_attr(player, 'group_members') != none and state_attr(player, 'group_members') != [] }}"
            sequence:
              - repeat:
                  for_each: "{{ state_attr(player, 'group_members') }}"
                  sequence:
                  - service: media_player.volume_set
                    target:
                      entity_id: "{{ repeat.item }}"
                    data:
                      volume_level: >-
                        {% set volume = state_attr(repeat.item, "volume_level") - stepsize %}
                        {{ 0.0 if volume < 0.0 else volume }}

          # Volume Up Hold
          - conditions: "{{ trigger.payload == 'volume_up_hold' and state_attr(player, 'group_members') != none and state_attr(player, 'group_members') != [] }}"
            sequence:
              - repeat:
                  for_each: "{{ state_attr(player, 'group_members') }}"
                  sequence:
                  - service: media_player.volume_up
                    target:
                      entity_id: "{{ repeat.item }}"

          # Volume Down Hold
          - conditions: "{{ trigger.payload == 'volume_down_hold' and state_attr(player, 'group_members') != none and state_attr(player, 'group_members') != [] }}"
            sequence:
              - repeat:
                  for_each: "{{ state_attr(player, 'group_members') }}"
                  sequence:
                  - service: media_player.volume_down
                    target:
                      entity_id: "{{ repeat.item }}"

          ## Volume for media players not supporting groups

          # Volume Up
          - conditions: "{{ trigger.payload == 'volume_up' and (state_attr(player, 'group_members') == none or state_attr(player, 'group_members') == []) }}"
            sequence:
              - service: media_player.volume_set
                target:
                  entity_id: "{{ player }}"
                data:
                  volume_level: >-
                    {% set volume = state_attr(player, "volume_level") + stepsize %}
                    {{ 1.0 if volume > 1.0 else volume }}
           
          # Volume Down Press
          - conditions: "{{ trigger.payload == 'volume_down' and (state_attr(player, 'group_members') == none or state_attr(player, 'group_members') == []) }}"
            sequence:
              - service: media_player.volume_set
                target:
                  entity_id: "{{ player }}"
                data:
                    volume_level: >-
                      {% set volume = state_attr(player, "volume_level") - stepsize %}
                      {{ 0.0 if volume < 0.0 else volume }}
          
          # Volume Up Hold
          - conditions: "{{ trigger.payload == 'volume_up_hold' and (state_attr(player, 'group_members') == none or state_attr(player, 'group_members') == []) }}"
            sequence:
              - service: media_player.volume_up
                target:
                  entity_id: "{{ player }}"
          
          # Volume Down Hold
          - conditions: "{{ trigger.payload == 'volume_down_hold' and (state_attr(player, 'group_members') == none or state_attr(player, 'group_members') == []) }}"
            sequence:
              - service: media_player.volume_down
                target:
                  entity_id: "{{ player }}"

          ## Actions

          # Single Dot Press
          - conditions: "{{ trigger.payload == 'dots_1_short_release' }}"
            sequence: !input single_dot
          # Single Dot Double Press
          - conditions: "{{ trigger.payload == 'dots_1_double_press' }}"
            sequence: !input single_dot_double_press
          # Single Dot Long Press
          - conditions: "{{ trigger.payload == 'dots_1_long_press' }}"
            sequence: !input single_dot_long_press
          # Double Dot Press
          - conditions: "{{ trigger.payload == 'dots_2_short_release' }}"
            sequence: !input double_dot
          # Double Dot Double Press
          - conditions: "{{ trigger.payload == 'dots_2_double_press' }}"
            sequence: !input double_dot_double_press
          # Double Dot Long Press
          - conditions: "{{ trigger.payload == 'dots_2_long_press' }}"
            sequence: !input double_dot_long_press

Setup
Select your device, adjust your MQTT base topic if required, choose a media_player to control or a media_player that will act as the main device in a scenario where other players are grouped with it. Finally, configure the “dot” buttons as needed

Usage

  • :arrow_forward: - Toggle Play / Pause
  • :previous_track_button: - Previous Track
  • :next_track_button: - Next Track
  • :arrow_up_small: - Volume Up. Supports single press and hold
  • :arrow_down_small: - Volume Down. Supports single press and hold
  • Single Dot - Supports single, double and long press to fire one or more actions
  • Double Dot - Supports single, double and long press to fire one or more actions

Credits
Eric Kreuwels & Alex Austin for the original volume adjust aspects

Updates

2024-04-16 v1.55: Add additional filtering to remove the false positives of the automations triggering for MQTT topics or where you run multiple Ikea E2123 devices. This should help clean up log book entries etc. Thanks kenno.

2024-04-10 v1.54: Update device selector to account for the Ikea refactoring which will change the model name slightly. Both versions supported. Add support for the legacy action on the play/pause button.

2023-09-06 v1.52/v1.53: Update to allow 100 volume steps. / Fix copy paste fail on volume down hold for non grouped players.

2023-09-06 v1.51: Fix to stop non grouped players with empty group_members attribute triggering the grouped volume actions.

2023-09-05 v1.5: Resolve an issue with non grouped players presenting empty arrays rather than “none” in the group members attribute. Also apply these and previous fixes to volume hold.

2023-08-15 v1.4: Resolve an issue with volume not working on media player integrations that do not populate the group members attribute for single devices/group in a different way to the Sonos integration

2023-06-26 v1.3: Resolve an issue where multiple devices are attached to a system and all automations are triggered by any device.

2023-05-08 v1.2: Added support for volume control of all Sonos players joined to/grouped with the media player specified in the automation. The volume is adjusted on a per player basis so any differential set in the Sonos app is maintained. Note: To continue control the main media player specified in the automation must always remain in the Sonos group.

2023-04-16 v1.1: Tweak descriptive text for volume steps and set the default to match the scale of the Sonos app.

12 Likes

Looks Great - just bought a couple to use for multiple purposes (dots) - looks like you saved me a lot of work. Installed and wíll test over the next few days

@motionist :slight_smile: Good to hear, let me know how you get on with it. I’ve been using mine in anger now for a few days and it’s a great little remote.

It works smooth
Easy to setup
Thanks again

1 Like

At line 101 replace :

  - conditions: '{{ trigger.payload == ''toggle'' }}'

by :

  - conditions: '{{ trigger.payload == ''play_pause'' }}' 

There is an error in this source for the PLAY button… IKEA E2123 control via MQTT | Zigbee2MQTT

It’s not an error, “toggle” is the action exposed by Z2M, from the link you posted:

It’s working fine as is by the way, I use mine all of the time :slight_smile:

Edited as my original reply mentioned f/w differences but it’s not relevant to the Play button action

Yes, I know and I read the doc, yet without changing it doesn’t work…there is a mystery !

Are you using Zigbee2MQTT? I saw on another thread you’re using ZHA? This is Z2M only.

Yes and the event is play_pause

Are you using the official implementation or do you have a custom .js as the early versions whilst support was added did use different actions?

“toggle” is the official action for the supported implementation, this is the same screengrab from my HA instance

I use the normal version of Z2M 1.30.4-1, no beta, no JS.

Another thing, I just realized that dot_2 is not working…

I followed this thread and re-paired. I now have the dot 2 but still play_pause… We’ll see later…

I was going to say, remove and re-pair as you definitely have the config from an older version going on - the dot 2 not working is a bit of a giveaway.

Anyway, until your play button sends an action of “toggle” it isn’t running the final Z2M implementation for this device.

We’ll see with the updates.

In general I manage all my remotes with ControlerX which is very convenient and I prefer ZHA in production because I can deply it on smaller installations of my friends who do not have Z2M.

Thanks for your help.

No worries, hope you get it resolved.

Thank you for creating this blueprint. I tried it out, and everything works fine except for the volume controls (no change). This is the error:

Stopped because an error was encountered at May 6, 2023 at 9:07:08 PM (runtime: 0.02 seconds)
Error rendering data template: TypeError: unsupported operand type(s) for -: ‘NoneType’ and ‘float’

EDIT: I changed the media player to one device and the volume controls worked. The above error was because I was trying to control a group of Sonos.

Thanks for the feedback. Yes it’s not designed for a sonos group.

Edit: I’ve had a play around with this today as I had a goal to sort out some multi room volume stuff, turns out it was the same problem :smiley:

@RF2 Any chance you can give the yaml below a try before I update the blueprint? Thanks

blueprint:
# Media control via IKEA Symfonisk Gen2 - Shawsky April 2023
# Updated May 2023 - Group volume control
# Based on https://gist.github.com/erkr/a437ebcb98a2b5ba2deebabd02f5ffae Eric Kreuwels
# and https://gist.github.com/alexwmaustin/2c25cfa1a0ade1ab9fc1ef0940289672 Alex Austin
  name: Z2M - IKEA Symfonisk sound controller GEN2 for media
  description: 
    'Control the selected media player with an IKEA Symfonisk sound controller GEN2 via Zigbee2MQTT (Z2M)

    Supports single press on media buttons and single, double and long press for the "dot" buttons.'
  domain: automation
  input:
    remote:
      name: Remote
      description: The IKEA Symfonisk controller GEN2 to use
      selector:
        device:
          integration: mqtt
          manufacturer: IKEA
          model: SYMFONISK sound remote gen2 (E2123)
          multiple: false
    base_topic:
      name: Zigbee2MQTT Base mqtt topic
      description: The base topic configured in Zigbee2MQTT. If you haven't changed this, leave the default here ("zigbee2mqtt")
      default: zigbee2mqtt
    media_player:
      name: Media Player
      description: The media player to control with this automation
      selector:
        entity:
          domain: media_player
          multiple: false
    volume_steps:
      name: Volume number of steps
      description: Controls the volume scale. The default of 25 is the same scale as the Sonos app.
      default: 25
      selector:
        number:
          min: 5
          max: 50
          step: 5
          unit_of_measurement: "Num"
          mode: slider
    single_dot:
      name: Single Dot (Single)
      description: Action to run on single dot press
      default: []
      selector:
        action: {}
    single_dot_double_press:
      name: Single Dot (Double)
      description: Action to run on single dot double press
      default: []
      selector:
        action: {}
    single_dot_long_press:
      name: Single Dot (Long)
      description: Action to run on single dot long press
      default: []
      selector: 
        action: {}
    double_dot:
      name: Double Dot (Single)
      description: Action to run on double dot press
      default: []
      selector:
        action: {}
    double_dot_double_press:
      name: Double Dot (Double)
      description: Action to run on double dot double press
      default: []
      selector:
        action: {}
    double_dot_long_press:
      name: Double Dot (Long)
      description: Action to run on double dot long press
      default: []
      selector:
        action: {}
      
mode: restart
max_exceeded: silent

trigger_variables:
  base_topic: !input base_topic
  controller: !input remote

trigger:
  - platform: mqtt
    topic: "{{ base_topic }}/+/action"
action:
  - variables:
      fname: "{{ device_attr(controller, 'name') }}"
      player: !input 'media_player'
      steps: !input volume_steps
      stepsize: '{{ 1.0 / steps }}'
  - choose:
    - conditions:
      - "{{ trigger.payload != ''}}"
      - "{{ fname in trigger.topic }}"
      sequence:
        - choose:
          # Play / Pause
          - conditions: "{{ trigger.payload == 'toggle' }}"
            sequence:
            - service: media_player.media_play_pause
              entity_id: !input 'media_player'
          # Next Track
          - conditions: "{{ trigger.payload == 'track_next' }}"
            sequence:
            - service: media_player.media_next_track
              entity_id: !input 'media_player'
          # Previous Track
          - conditions: "{{ trigger.payload == 'track_previous' }}"
            sequence:
            - service: media_player.media_previous_track
              entity_id: !input 'media_player'
          # Volume Up Press
          - conditions: "{{ trigger.payload == 'volume_up' }}"
            sequence:
              - repeat:
                  for_each: "{{ state_attr(player, 'group_members') }}"
                  sequence:
                  - service: media_player.volume_set
                    target:
                      entity_id: "{{ repeat.item }}"
                    data:
                      volume_level: >-
                        {% set volume = state_attr(repeat.item, "volume_level") + stepsize %}
                        {{ 1.0 if volume > 1.0 else volume }}
                    
          # Volume Down Press
          - conditions: "{{ trigger.payload == 'volume_down' }}"
            sequence:
              - repeat:
                  for_each: "{{ state_attr(player, 'group_members') }}"
                  sequence:
                  - service: media_player.volume_set
                    target:
                      entity_id: "{{ repeat.item }}"
                    data:
                      volume_level: >-
                        {% set volume = state_attr(repeat.item, "volume_level") - stepsize %}
                        {{ 0.0 if volume < 0.0 else volume }}
              
          # Volume Up Hold
          - conditions: "{{ trigger.payload == 'volume_up_hold' }}"
            sequence:
              - repeat:
                  for_each: "{{ state_attr(player, 'group_members') }}"
                  sequence:
                  - service: media_player.volume_set
                    target:
                      entity_id: "{{ repeat.item }}"
                    data:
                      volume_level: >-
                        {% set volume = state_attr(repeat.item, "volume_level") + stepsize %}
                        {{ 1.0 if volume > 1.0 else volume }}
                        
          # Volume Down Hold
          - conditions: "{{ trigger.payload == 'volume_down_hold' }}"
            sequence:
              - repeat:
                  for_each: "{{ state_attr(player, 'group_members') }}"
                  sequence:
                  - service: media_player.volume_set
                    target:
                      entity_id: "{{ repeat.item }}"
                    data:
                      volume_level: >-
                        {% set volume = state_attr(repeat.item, "volume_level") - stepsize %}
                        {{ 0.0 if volume < 0.0 else volume }}
              
          # Single Dot Press
          - conditions: "{{ trigger.payload == 'dots_1_short_release' }}"
            sequence: !input single_dot
          # Single Dot Double Press
          - conditions: "{{ trigger.payload == 'dots_1_double_press' }}"
            sequence: !input single_dot_double_press
          # Single Dot Long Press
          - conditions: "{{ trigger.payload == 'dots_1_long_press' }}"
            sequence: !input single_dot_long_press
          # Double Dot Press
          - conditions: "{{ trigger.payload == 'dots_2_short_release' }}"
            sequence: !input double_dot
          # Double Dot Double Press
          - conditions: "{{ trigger.payload == 'dots_2_double_press' }}"
            sequence: !input double_dot_double_press
          # Double Dot Long Press
          - conditions: "{{ trigger.payload == 'dots_2_long_press' }}"
            sequence: !input double_dot_long_press

Ahh, that worked great! I still had to choose a single Sonos for Media Player (choosing the group helper didn’t work), but changing volume for that single Sonos will change the other ones that are in the same group. Thank you!!

Great, thanks for testing. Yes it’s tied to a “main” media player.

Could you let me know what helper you’re using for the sonos group as it’s not something I’m familiar with and I can take a look if it’s possible to make it work.

Thank you for making the update!

It’s a “media player” group helper that has 3 Sonos devices on the main floor. I wanted to do some sort of group volume control, but hasn’t been able to work it out, so it’s not part of any automation or anything.