List of mappings in a template sensor attribute_templates

I’m looking to have a template sensor that contains, in an attribute, a list of mappings. Here’s what I have so far:

sensor:
  - platform: template
    sensors:
      test:
        value_template: "on"
        entity_id:
          - sensor.time
        attribute_templates:
          data: >
              {%- set test1 = {
                "key1" : "value1",
                "key2" : "value2",
                "key3" : "value3",
                "key4" : "value4",
                "key5" : "value5"
              }
              -%}
              {%- set test2 = {
                  "key1" : "value6",
                  "key2" : "value7",
                  "key3" : "value8",
                  "key4" : "value9",
                  "key5" : "value0"
                }
              -%}
              {{ [test1,test2] }}

When I put this in dev tools, I get the desired result. I can tell that it’s a list at that point, because if I write [test1,test2][0] I get the first mapping. But when I create a sensor with the above definition, the attribute becomes a string, so when I write state_attr('sensor.test','data')[0] I get [.

Further explanation, to avoid the XY problem…

I’m using the plex_recently_added integration to pull recently added media from Plex, and then list card to display the entries in Lovelace. I’m trying to create this template sensor so that I can reformat and rearrange things in a way I like, e.g. having “$showtitle $episode - $episodetitle” in a title field, and arranging things so that there’s always 2 movies and 2 episodes in the list.

Here’s that template sensor (similarly broken):

- platform: template
  sensors:
    plex_recently_added_parsed:
      value_template: >-
        {{ states('sensor.plex_recently_added_movies') }}
      attribute_templates:
        data: >-
          {%- set titles = namespace(entries=[]) %}
          {% for media in state_attr('sensor.plex_recently_added_movies','data') %}
            {% if media.title %}
              {% set entry = {
                "title" : media.title,
                "poster" : media.poster,
                "added" : media.airdate,
                "released" : media.aired,
                "type" : "movie"
                }
              %}
            {% set titles.entries = titles.entries + [entry] %}
            {% endif %}
          {% endfor %}
          {% set episodes = namespace(entries=[]) %}
          {% for media in state_attr('sensor.plex_recently_added_episodes','data') %}
            {% if media.title %}
              {% set entry = {
                "title" : media.title + " " + media.number + ": " + media.episode,
                "poster" : media.poster,
                "added" : media.airdate,
                "released" : media.aired,
                "type" : "show"
                }
              %}
            {% set titles.entries = titles.entries + [entry] %}
            {% endif %}
          {% endfor %}
          {{ titles.entries }}

And a couple of screenshots for clarity:
What I want:

What I get:

Thanks!

Your test is flawed; it’s not actually checking the output of a template. The output of any Jinja2 template is a string. So if your goal is to generate a list from a template, it’s not possible.

Alright, thank you.

I’m thinking variables can do this now… Not 100% sure because I can’t tell if variables are always strings or what. Either way, I envision putting all that code into a variable as JSON, then extracting it in each field.

EDIT: Also, it looks like you can template the field names for services.

I haven’t experimented with (local) variables yet but, based on Frenck’s example, I assume that if the variable employs a template then its value is a string. Otherwise, if the variable is assigned a constant, then it’s type can be something other than a string.

Yeah, if it’s a string just have to do to_json and from_json appropriately. Then this should be doable as long as the number of fields are the same. It at least can reduce code redundancy.

The OP is using Template Sensors. Aren’t variables just for scripts and automations?

0.115 Variables

:man_shrugging: I’ve only briefly read about the change.

You did make me think about ways I might get HA to transform JSON into useful data, and it occurred to me to use an automation to call a shell command to call curl and post sensor data back to HA. It’s completely harebrained, but an early test suggests it just might work. Will report back.

P.S. Can we has a set_state service to make this slightly less kludgey plx? I know there’s a python script for that but still.

It’s a limitation of yaml and how it’s loaded. A python script with almost identical syntax would do what you want.

I think it’s probably about time I learn a bit of python. I always end up putting in more effort to work around my own limitations than it would take to address them. :stuck_out_tongue:

Do you use the MQTT integration? This can be done with an MQTT Sensor and an automation.

Oh, good idea. I do indeed. Looking into Python now but I will keep that in mind.

Thanks both for the help.

Well that was fairly straightforward. Here in case anybody else wants it.

recent_movies = hass.states.get('sensor.plex_recently_added_movies').attributes['data']
recent_episodes = hass.states.get('sensor.plex_recently_added_episodes').attributes['data']

attributes = {}
entries = []
attributes['entries'] = []
attributes['friendly_name'] = "Plex Recently Added Useful"

for item in recent_movies:
    if item.get('title'):
        entry = {
            "title" : item.get('title'),
            "poster" : item.get('poster'),
            "added" : item.get('airdate'),
            "released" : item.get('aired'),
            "type" : "movie"
        }
        entries.append(entry)

for item in recent_episodes:
    if item.get('title'):
        entry = {
            "title" : item.get('title') + "<br/>" + item.get('number') + "<br/>" + item.get('episode'),
            "poster" : item.get('poster'),
            "added" : item.get('airdate'),
            "released" : item.get('aired'),
            "type" : "show"
        }
        entries.append(entry)

attributes['entries'] = sorted(entries,key=lambda i: i['added'],reverse=True)
hass.states.set('sensor.plex_recently_added_parsed', 'Online', attributes)

And a screenshot of the card this enabled:

4 Likes