Value_template to iterate over list of json

I have this list of json objects I’m pulling from an external api. Pulling the entire list gives me a max character error. Which is fine, cause all I’m interested are in two fields of each of the objects. Been beating my head over the keyboard trying to figure out the correct jinja2 to iterate over this and grab the fields. Any help would save my keyboard from a bloody death.

I can get this to work in the template tool

{% set json_val = {list of json below here} %}

{% for cp in json_val%}
  {{ cp['name'] }}{{" "}}{{ cp['value'] }}
{% endfor %}}

Here is the list.

{
      ".id":"1",
      "name":"speed3",
      "type":"R",
      "value":"0"
   },
   {
      ".id":"2",
      "name":"speed4",
      "type":"R",
      "value":"20"
   },
   {
      ".id":"3",
      "name":"b-temp",
      "type":"C",
      "value":"34"
   },
   {
      ".id":"4",
      "name":"p-val1",
      "type":"V",
      "value":"26.5"
   },
   {
      ".id":"5",
      "name":"p-val2",
      "type":"V",
      "value":"52.8"
   },
   {
      ".id":"6",
      "name":"p-cur1",
      "type":"C",
      "value":"110"
   },
   {
      ".id":"7",
      "name":"p-cur2",
      "type":"C",
      "value":"0.2"
   }

The error the yaml check is giving me:

Invalid config for [sensor.rest]: invalid template (TemplateSyntaxError: expected token ':', got '}') for dictionary value @ data['value_template']. Got '< {%- for cp in [{ value_json }]-%} {{ cp[\'name\'] }}{{" "}}{{ cp[\'value\'] }} {%- endfor -%}'. (See ?, line ?).```

try:

{% for i in range(json_val | length) %}
  {{ json_val[i].name }}, {{ json_val[i].value }}
{% endfor %}

Pretty sure you will have to use square bracket notation there. “value” refers to the whole received payload.

It worked in the template editor when I tested it.

But if not then use the square brackets.

Yeah the template editor does not have the same automatic assignment of value and value_json.

Well that’s interesting.

It makes it hard to test things then.

I just tried to change {{ json_val[i].value }} to {{ json_val[i][value] }} in the editor to try it out and it gave me an error that “value” was undefined.

so I don’t know how to test a template in the editor that has a field called “value” that you want to extract data from.

Try

{{ json_val[i]['value'] }}
1 Like

yeah, that works.

stupid quotation marks. :wink:

So, that worked in allowing my yaml to build. Many thanks to everyone!

Here is a silly question. How do I display the various names separately? When I was looking for just the first element, I can display no issues. Is there an integration that allows us to display a grouping of values?

This is what I’ve got now, yaml builds, but just showing a single graph.

- platform: rest
  name: "Stats API"
  authentication: basic
  username: !secret m_user
  password: !secret m_pass
  resource: !secret m_url
  method: GET
  scan_interval: 60
  verify_ssl: false
  force_update: true
  value_template: "{% for i in range(json_val | length) %}
  {{ json_val[i]['name']}}, {{ json_val[i]['value']}}
  json_attributes:
  - name
  - value
{% endfor %}"

Ideally, I’d like to have the ability to do something like my thermostats.

In the template, I can get this to work

{% for cp in json_val%}
  {% if cp['name'] == 'p-val1' %}
    {{ cp['value'] }}
  {% endif %}
{% endfor %}}

why is this not working in the yaml?

value_template: "{% for i in range(json_val | length) %}
  {% if json_val[i]['name'] == 'p-val1' %}
    {{ json_val[i]['name'] }}, {{ json_val[i]['value'] }}
  {% endif %}
  {% endfor %}"

I hope this isn’t the cleanest way, but now I’m wondering why this is returning a 0, when my manual curl to the API is returning non-zero values.

Try formatting it like this:

value_template: >
  {% for i in range(json_val | length) %}
    {% if json_val[i]['name'] == 'p-val1' %}
      {{ json_val[i]['name'] }}, {{ json_val[i]['value'] }}
    {% endif %}
  {% endfor %}

That didn’t work for me. but did some tinkering and got it to work.

value_template: >-
       {% for sensor in value_json %}
         {% if sensor.name == "p-val1" %}
           {{ sensor.value }}
         {% endif %}
       {% endfor %}

I fully admit my approach to this is garbage since I will have to make multiple api calls to get the data. But now that I know this is possible, onto to a more efficient solution. I’ll cross that bridge tomorrow. Thanks again for the help.

1 Like
value_template: >
  {{ value_json | selectattr('name', 'eq', 'p-val1')
    | map(attribute='value') | first | default('') }}

Alternative:

value_template: >
  {% set x = value_json | selectattr('name', 'eq', 'p-val1') | list %}
  {{ x[0]['value'] if x != [] else '' }}

EDIT

Correction. Changed dot to bracket notation as per tom_l’s post below.

1 Like

Again, pretty sure this

Needs to be:

x[0]['value']

“value” is the the whole returned result, like “value_json” it has special meaning in a value_template.

1 Like

Excellent! This at least keeps me from having to iterate through the list, albeit a very small list.