Looping through an attribute derived from a JSON using Restful sensor

Is there a way to loop through an attribute derived from a JSON? For instance I want to get all the games attributes from this json file: https://statsapi.web.nhl.com/api/v1/schedule?startDate=2019-04-06&endDate=2019-04-06&hydrate=linescore

then under value_template I want to create a loop to cycle through all of them and find one that has attribute [team.name] = to my input_select and get it’s index number and all other info.

That data structure looks quite complex, so I won’t promise that this will be easy, but basically you can loop like this (I haven’t tested this with the actual json) to extract the section of the json you’re interested in. And then you may need another couple of template sensors to extract the relevant data:

value_template: >
  {% for entry in value_json.dates.games %}
    {% if entry.teams.home.team.name == 'my team' %}
      {{ entry.value }}
    {% endif %}
  {% endfor %}

I think you’ll need to set aside the idea of solving this with a value_template. There’s a 255-character limit for the data and your source easily exceeds it.

The workaround is to call an external script to do the processing and have it return the desired results. You may find this thread helpful because it has a nearly identical requirement:


EDIT
So very wrong …

See finity’s post below. Only state is limited to holding 255 characters, not attributes, and not the value_template’s ability to process the incoming data.

See suggestion made by lmamakos below for solution.

If you have a problem with a long JSON response fitting in as the value of an entity, you might look at this thread: Need help storing URL for use in generic IP camera (over 255 chars) for some ideas.

Thanks guys I’ll start looking into your recommendations and see how it goes!

the data itself is not limited to 255 characters. Only the final value that is stored in the “state” of the entity. Even attributes can be over 255 characters. Only the state is limited.

I used to use a rest call for my NWS alerts and the data I was parsing in the template was almost always longer than 255 characters and since the template always cut the data down to a few characters the state always showed the correct value.

I can show you my template but it won’t help you in using a loop thru the data. I always wanted to extract a specific value from the json no matter how many times the key value appeared.

1 Like

That did not work but I had another idea. For testing purposes I took data that had lots of games. In this case 15. I managed to pull the total games which is 15 with this code:

sensor:
  - platform: rest
    resource: https://statsapi.web.nhl.com/api/v1/schedule?startDate=2019-04-06&endDate=2019-04-06&hydrate=linescore
    name: nhl_total_games
    scan_interval: 
      hours: 24
    value_template: '{{ value_json.totalGames }}'

Now nhl_total_games = 15 how do I create another sensor to pull the game index number with my teams name out of there?

something like:

 - platform: template
    sensors:
      nhl_away_score:
        value_template: >
           {% for x <= nhl_total_games %}
               {% if states.sensor.nhl_game_status.attributes["dates"][0]["games"][x]["teams"]["away"]["team"]["name"] == 'my team' %}
                    {{ entry.value = x }}
               {% endif %}
          {% endfor %}

What I’m offering isn’t a complete solution but, perhaps, one step closer to it.

You don’t need to have separate sensors, one to get the total number of games, and another to process the data using the ‘total games’ value. It can be done in one shot.

This is just to demonstrate that totalGames can be acquired then used to control the iterations of the for-loop. The result will be 15 team names playing away games (not what you want but it’s just something for the loop to do). You’ll need to modify what the loop does to suit your needs (extracting the details of your chosen team’s away games and storing them in an attribute).

sensor:
  - platform: rest
    resource: https://statsapi.web.nhl.com/api/v1/schedule?startDate=2019-04-06&endDate=2019-04-06&hydrate=linescore
    name: nhl_teams_away
    scan_interval: 
      hours: 24
    value_template: >-
      {% for x in range(value_json.totalGames) %}
        {{ value_json["dates"][0]["games"][x]["teams"]["away"]["team"]["name"] }}
      {% endfor %}

Ah nice even better will try it later today. Thanks!

is there a way to create a counter variable, and make this sensors value_template = that counter which will actually be the x value of when the loop detects the name.

Something like this but not sure of the format:

value_template: >-
  {% for x in range(value_json.totalGames) %}
    {%  if (value_json["dates"][0]["games"][x]["teams"]["home"]["team"]["name"] == states.input_select.nhl_fav_team.state) OR (value_json["dates"][0]["games"][x]["teams"]["away"]["team"]["name"] == states.input_select.nhl_fav_team.state) %}
      x
    {% endif %}
  {% endfor %}

nhl_teams_away should actually be nhl_teams_index…

Wrap the lone x (the loop index) in double braces:

      {{x}}
    {% endif %}
  {% endfor %}

When the loop’s if gets a match, {{x}} will report the value of the loop index.

Be advised that range(value_json.totalGames) is zero-based. If totalGames is 15, the loop counts from 0 to 14 so x will be one less than what you may expect. Therefore what you may want to display is {{x+1}}.

Also be aware that the scope of x is limited to within the loop. If you want to calculate a value within the loop for use outside the loop, it requires creating a (global) variable with greater scope. I won’t open that can of worms any further unless you say you need a global variable.

The OR did not work so I did:

sensor:
  - platform: rest
    resource: https://statsapi.web.nhl.com/api/v1/schedule
    name: nhl_teams_index
    scan_interval: 
      hours: 24
    value_template: >-
      {% for x in range(value_json.totalGames) %}
        {%  if value_json["dates"][0]["games"][x]["teams"]["home"]["team"]["name"] == states.input_select.nhl_fav_team.state %}
          {{ x }}
        {%  elif value_json["dates"][0]["games"][x]["teams"]["away"]["team"]["name"] == states.input_select.nhl_fav_team.state %}
          {{ x }}
        {% else %}
          No Game
        {% endif %}

Wanted to add a “No Game” if it doesn’t detect anything but it doesn’t work.

When there is no game it outputs it twice: No Game No Game
When there are 2 games it does the following:
When the game is at index 0 it outputs: 0 No Game
When the game is at index 1 it outputs: No Game 1

Also am I doing this correctly:

nhl_home_score:
        value_template: >-
          {% if states('sensor.nhl_teams_index') == 'No Game' %}
            No Game
          {% else %}
            {{ states.sensor.nhl_teams_index.attributes.dates[0]["games"][sensor.nhl_teams_index]["teams"]["home"]["score"] }}
          {% endif %}

OK got it to work instead of No Game I made it == ‘’ since the loop outputs an empty field if nothing is found…

But this is a no go:

{{ states.sensor.nhl_teams_index.attributes.dates[0][“games”][sensor.nhl_teams_index][“teams”][“home”][“score”] }}

Seems I can’t use a sensor within a sensor.

If you want to use the state (the value) of sensor.nhl_team_index, you have to get the state. Just dropping sensor.nhl_team_index into the template won’t get its state.

This gets an entity’s state (you used this elsewhere):

states('sensor.nhl_team_index')

If you need to use it several times, assign it to a variable and then use the variable in the template.

{% set z = states('sensor.nhl_team_index')  %}

Where would this initializing go? Under a sensor in a sensors value_template?

This worked:

{{ states.sensor.nhl_teams_index.attributes.dates[0]["games"][states('sensor.nhl_team_index')|int]["teams"]["home"]["score"] }}

But would have been nicer to use the

{% set z = states('sensor.nhl_team_index') %}

But I can’t figure out where I am to initialize the z.

{% set z = states('sensor.nhl_team_index') | int %}
{{ states.sensor.nhl_teams_index.attributes.dates[0]["games"][z]["teams"]["home"]["score"] }}

so everywhere I use this z variable I’ll have to initialize it again? or is this a global declaration even though its inside a sensor?

The variable’s scope is limited to within the template its defined. For example:

 value_template: >
   {% set z = states('sensor.nhl_team_index') | int %}
   ... do more stuff with z ....

If this value_template is part of a sensor, then z is only valid within the value_template and nowhere else.

OK cool, I like this way it’s cleaner, I’ll change my code to reflect this.

Thanks everyone for your help! My setup now works!