Song History for Sonos

I´m searching for a way to display the recently played songs of my sonos player.
Right now I´m using a History Graph but you have to use the mouse pointer to see the songs recently played.
I´m searching for a way to show a list of three or more songs.
Is there an elegant way to do this?

You could obviously use some helper variables and shift them each time the song changes.
But the history is there already. otherwise, the history graph wouldn’t work. so there must be a way to get the last value and the second to last value and so on.

Did you figure this out? I’m looking to do the same thing.

I have solved it as follows:
I created 5 helpers as text (for the last 5 played songs) for each media device.
Then I have an automation that save the current title and artist and moves the other texts to the next helper text.
These helper texts are than shown in a markdown card in the ui.

that is the automation:

alias: Google Home mini - Track changed
description: ""
trigger:
  - platform: state
    entity_id:
      - media_player.esszimmer
    attribute: media_title
condition:
  - condition: device
    device_id: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    domain: media_player
    entity_id: media_player.esszimmer
    type: is_playing
action:
  - service: input_text.set_value
    target:
      entity_id: input_text.googlehomemini_current_track_5
    data:
      value: "{{ states('input_text.googlehomemini_current_track_4') }}"
  - service: input_text.set_value
    target:
      entity_id: input_text.googlehomemini_current_track_4
    data:
      value: "{{ states('input_text.googlehomemini_current_track_3') }}"
  - service: input_text.set_value
    target:
      entity_id: input_text.googlehomemini_current_track_3
    data:
      value: "{{ states('input_text.googlehomemini_current_track_2') }}"
  - service: input_text.set_value
    target:
      entity_id: input_text.googlehomemini_current_track_2
    data:
      value: "{{ states('input_text.googlehomemini_current_track') }}"
  - service: input_text.set_value
    target:
      entity_id: input_text.googlehomemini_current_track
    data:
      value: >-
        {{state_attr("media_player.esszimmer", "media_artist")}} -
        {{state_attr("media_player.esszimmer", "media_title")}}
mode: single

i hope that helps you.

1 Like

Thank You!

If you’re interested, here’s my version. It uses a single Trigger-based Template Sensor to maintain a record of the last 5 tracks played (artist, title, time). It can easily be expanded from 5 to whatever quantity is needed.

template:
  - trigger:
      - platform: state
        entity_id: media_player.kitchen
        attribute: media_title
    sensor:
      - name: Recent Tracks
        state: "{{ now().timestamp() | timestamp_custom() }}"
        attributes:
          tracks: >
            {% set current = this.attributes.get('tracks', []) %}
            {% set new = [{
                "artist": trigger.to_state.attributes.media_artist,
                "title": trigger.to_state.attributes.media_title,
                "time": now().isoformat() }]
                if is_state('media_player.kitchen', 'playing') else [] %}
            {{ (new + current)[:5] }}

Here’s the sensor’s information.

Here’s the content for the Markdown card.

|Artist||Title|
|:----|:-:|:----|
{% for x in state_attr('sensor.recent_tracks', 'tracks') | default([], true) -%}
  |{{x.artist}}||{{x.title}}|
{% endfor -%}

Here’s the appearance of the Markdown card.
image

4 Likes

that is a really nice solution. much easier to setup than mine.

i added an if statement to check if my soundbar is playing tv sound.

#### Media Player History ####

  - trigger:
      - platform: state
        entity_id: media_player.beam
        attribute: media_title
    sensor:
      - name: Recent Tracks Sonos Soundbar
        state: "{{ now().timestamp() | timestamp_custom() }}"
        attributes:
          tracks: >
            {% set current = this.attributes.get('tracks', []) %}
            {% set new = [{
                "artist": trigger.to_state.attributes.media_artist,
                "title": trigger.to_state.attributes.media_title,
                "time": now().isoformat() }]
                if is_state('media_player.beam', 'playing') and state_attr('media_player.beam', 'media_title') != 'TV' %}
            {{ (new + current)[:5] if is_state('media_player.beam', 'playing') and state_attr('media_player.beam', 'media_title') != 'TV' else current}}

Is this still working for folks? I’m just recently getting nothing in the card I am using and the template seems broken on my end:

Well seems I must have broken the template/sensor? If anyone knows how I would fix it would appreciate it.

If the last thing played didn’t have media_artist and media_title attributes, that’s the result (Undefined).

FWIW, you can append the default filter like this to make it report unknown instead of Undefined.

                "artist": trigger.to_state.attributes.media_artist | default('unknown'),
                "title": trigger.to_state.attributes.media_title | default('unknown'),

Alternately, you can use the default filter to look for some other attribute and report that instead. What that “other attribute” might be depends on the content being played.

Using the Variables & History integration https://github.com/Wibias/hass-variables

  - service: variable.update_sensor
    target:
      entity_id: sensor.vh_songs_played
    data:
      value: "{{ (states('sensor.vh_songs_played')|int(0))+1 }}"
      attributes:
        message_1: "{{states('sensor.readable_date_short')}} {{states('sensor.readable_time')}}: {{ state_attr('media_player.kitchen_white', 'media_artist') }}, {{ state_attr('media_player.kitchen_white', 'media_title') }}"
        message_2: "{{state_attr('sensor.vh_songs_played','message_1')}}"
        message_3: "{{state_attr('sensor.vh_songs_played','message_2')}}"
        message_4: "{{state_attr('sensor.vh_songs_played','message_3')}}"
        message_5: "{{state_attr('sensor.vh_songs_played','message_4')}}"
        message_6: "{{ trigger_message }}"