Template rest sensor attributes list

I have a mealie instance that I’m trying to pull the shopping list items from into a rest sensor via template. My ultimate end goal is to get this data into a to-do list with an automation so I can sync the to-do list with Google Keep. I’m not sure you can do a template to-do object so I’m starting with a sensor. I’m getting hung up on a few things and I can’t seem to get past how to get the items into an array inside of the attributes list of the sensor.

Something like this is what I’m after:

items:
  - item: "1x Soy Sauce"
  - item: "2x Milk"
  - item: "5x Bread"

The rest api outputs something like the following in json format:

{
    "listname":"Costco"
    "listItems":[
        {
           "id":1,
           "display":"1x Soy Sauce",
        }
        {
           "id":1,
           "display":"2x Milk",
        }
        {
           "id":1,
           "display":"5x Bread",
        }
    ]
}

I’m trying to get the value of display for each item in the listItems variable into the sensors attributes. My sensor entity looks like this so far:

  - platform: rest
    resource: "http://ip:port/api/groups/shopping/lists/id"
    method: GET
    name: Mealie shopping list
    headers:
      Authorization: "Bearer tokenhere"
    value_template: "None"
    attribute_templates: >
      {% set ns = namespace(bl=[]) %}
      {% for i in value_json['listItems'] %}
        {% set ns.bl = ns.bl + [i['display']}] %}
      {% endfor %}
      {{ ns.bl }}
    force_update: true
    scan_interval: 15

My only issue is that I’m unsure how to get the data into the attributes as a list. Thank you for the help you can provide.

You can’t template the entire field in the rest platform.

Make a rest sensor that has all the items, then make a template sensor from that.

  - platform: rest
    resource: "http://ip:port/api/groups/shopping/lists/id"
    method: GET
    name: Mealie shopping list
    headers:
      Authorization: "Bearer tokenhere"
    value_template: "OK"
    json_attributes:
    - listname
    - listItems

If you want to make a todo list from these items, you can do that. Otherwise you can make a select entity that has a dropdwon of all the items. Or just a sensor with an attribute that has all the items.

e.g.

template:
- sensor:
  - name: Items
    state: >
      {{ state_attr('mealie_shopping_list', 'listItems') | default([], True) | count }}
    attributes:
      items: >
       {{ state_attr('mealie_shopping_list', 'listItems') | default([], True) | map(attribute='display') | list }}
1 Like

Thank you for the help. The examples worked great. The last thing that is throwing me for a loop is deduping the data that is going to go into the todo list. For some reason it’s still being added into the todo list each time. I’m trying to compare between two lists and it’s not working. Not sure what I’m doing wrong here as I’ve not done comparison between a list and a todo list. There really isn’t many examples out there either.

alias: Mealie Shopping List Sync
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.mealie_shopping_list
    attribute: listItems
condition: []
action:
  - service: todo.get_items
    metadata: {}
    data: {}
    response_variable: existinglist
    target:
      entity_id: todo.shopping_list
  - repeat:
      for_each: >-
        {{state_attr('sensor.mealie_shopping_list', 'listItems') | default([],
        True) | map(attribute='display') | list }} 
      sequence:
        - if:
            - condition: template
              value_template: >-
                {% set existing = (existinglist.values() | list)[0]['items'] |
                map(attribute='summary') | list %}

                {% if repeat.item not in existing %}
                  true
                {% endif %}
          then:
            - service: todo.add_item
              metadata: {}
              data:
                item: "{{ repeat.item }}"
              target:
                entity_id: todo.shopping_list
              enabled: true
mode: single

1 Like

It looks like I got it. Changed the if statement to this:

                {% if repeat.item in existing %}
                  false
                {% else %}
                  true
                {% endif %}
1 Like

Sorry if I am a bit slow to understand, but does this mean that it is not even possible to use value templates for rest sensor attributes?

I have this sensor which uses a value template for the state value:

- platform: rest
  name: Trash
  method: GET
  icon: "mdi:trash-can"
  resource: https://portal-api.kredslob.dk/api/calendar/address/07469584376925736
  headers:
    user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
  value_template: >
    {% set pickups = value_json[0]["plannedLoads"] %}
    {% set expected = ["Restaffald", "Madaffald"] %}
    {% set expected_join = expected | join(",") %}
    {% set filtered_list = pickups | selectattr("fractions", "equalto", expected) | list %}
    {% set time = filtered_list | map(attribute="date") | sort | first %}

    {% if time is defined %}
      {% set days_left = (strptime(time, "%Y-%m-%dT%H:%M:%S%z").date() - now().date()).days %}
      {% if days_left == 0 %}
        i dag
      {% elif days_left == 1 %}
        i morgen
      {% else %}
        {{ days_left }} dage
      {% endif %}
    {% else %}
      {{ states('sensor.restaffald') }}
    {% endif %}
  json_attributes:
     - plannedLoads
  unique_id: skrald-restaffald-mad
  scan_interval: 21600

Since it could not figure out how to use a value template for the attributes, I created a new template sensor:

    sensor:
      - name: "Restaffald Afhentning"
        state: >
          {% set pickups = state_attr('sensor.restaffald', 'plannedLoads') %}
          {% if pickups %}
            {% set expected = ["Restaffald", "Madaffald"] %}
            {% set filtered_list = pickups | selectattr("fractions", "equalto", expected) | list %}
            {% set time = filtered_list | map(attribute="date") | sort | first %}
            {% if time %}
              {% set days_left = (strptime(time, "%Y-%m-%dT%H:%M:%S%z").date() - now().date()).days %}
              {% if days_left == 0 %}
                i dag
              {% elif days_left == 1 %}
                i morgen
              {% else %}
                {{ days_left }} dage
              {% endif %}
            {% else %}
              unknown
            {% endif %}
          {% else %}
            unknown
          {% endif %}
        attributes:
          next_pickup_date: >
            {% set pickups = state_attr('sensor.restaffald', 'plannedLoads') %}
            {% if pickups %}
              {% set expected = ["Restaffald", "Madaffald"] %}
              {% set filtered_list = pickups | selectattr("fractions", "equalto", expected) | list %}
              {% set time = filtered_list | map(attribute="date") | sort | first %}
              {{ time if time else 'unknown' }}
            {% else %}
              unknown
            {% endif %}
          friendly_name: "Next pickup date"

This works, but I would much rather only have one sensor for this to avoid confusion and because I have many similar sensors that I do not want to create both a rest sensor and template sensor for. Is this possible?

- platform: rest
  name: Trash
  method: GET
  icon: "mdi:trash-can"
  resource: https://portal-api.kredslob.dk/api/calendar/address/07469584376925736
  headers:
    user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
  value_template: >
    {% set pickups = value_json["plannedLoads"] %}
    {% set expected = ["Restaffald", "Madaffald"] %}
    {% set expected_join = expected | join(",") %}
    {% set filtered_list = pickups | selectattr("fractions", "equalto", expected) | list %}
    {% set time = filtered_list | map(attribute="date") | sort | first %}

    {% if time is defined %}
      {% set days_left = (strptime(time, "%Y-%m-%dT%H:%M:%S%z").date() - now().date()).days %}
      {% if days_left == 0 %}
        i dag
      {% elif days_left == 1 %}
        i morgen
      {% else %}
        {{ days_left }} dage
      {% endif %}
    {% else %}
      {{ states('sensor.restaffald') }}
    {% endif %}
  json_attributes:
     - plannedLoads
  unique_id: skrald-restaffald-mad
  scan_interval: 21600

Thanks for the swift reply! I am, however, not sure I understand what this shows? Is is not the same rest sensor that I posted above (with no value template for the attribute)?

I fixed the template so that it works as a single entity.

Hmm. As far as I can tell, the only difference between the rest sensor YAML I posted and what you posted above is that is now says

{% set pickups = value_json["plannedLoads"] %}

rather than

{% set pickups = value_json[0]["plannedLoads"] %}

But this just results in the sensor not being available (not working).

What I aim to do is to use a value template for the plannedLoads attribute similiar to what I did with the template sensor I created above.

The template sensor works, provides the correct state and has the correct attribute, but I would like to avoid having to make the tamplate sensor altogether and just just a value template for the attribute of the rest sensor. Hope that makes sense?

If the template I provided isn’t working, then there’s errors in your logs. Please post them. Otherwise removing the [0] should work based on your entity and template entity.

Logger: homeassistant.helpers.template
Source: helpers/template.py:2748
First occurred: December 1, 2024 at 9:51:20 PM (3 occurrences)
Last logged: 12:54:08 PM

Template variable warning: 'dict object' has no attribute 'position' when rendering '{{ value_json.position }}'
Template variable warning: 'list object' has no attribute 'plannedLoads' when rendering '{% set pickups = value_json["plannedLoads"] %} {% set expected = ["Restaffald", "Madaffald"] %} {% set expected_join = expected | join(",") %} {% set filtered_list = pickups | selectattr("fractions", "equalto", expected) | list %} {% set time = filtered_list | map(attribute="date") | sort | first %} {% if time is defined %} {% set days_left = (strptime(time, "%Y-%m-%dT%H:%M:%S%z").date() - now().date()).days %} {% if days_left == 0 %} i dag {% elif days_left == 1 %} i morgen {% else %} {{ days_left }} dage {% endif %} {% else %} {{ states('sensor.restaffald') }} {% endif %}'

Your original sensor should work then with the [0]. Try that again and look for errors. You should not need the additional attribute at all or template entity.

So either your rest sensor should be working without the template entity, or mine should be.

My original rest sensor using the [0] works and looks like this in Home Assistant

As can be seen, the attribute is called plannedLoads and gives me a long list of information and dates.

What I would like to achieve with a value_template in the rest sensor is this:

(This what my template sensor looks like)

That’s not possible. You can’t template attributes for rest sensors. Your only option is to use a template entity.

Ok. I thought that might the case, just wanted to be sure before making a lot of double rest+template sensors. Thank you for your time.