Looping through an attribute derived from a JSON using Restful sensor

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!

You’re welcome! Always fun to help others succeed.

1 Like

So I thought it was working but it just takes the first game in the json file no matter what the index is set in hassio…

Here is my nhl_stats.yaml that I have in a package folder:

nhl_stats.yaml (16.1 KB)

It shows when there is a No Game but when there is a game no matter the index it shows the content under index 0.

Funny part is even if I replace the {{ states.sensor.nhl_teams_index.attributes.dates[0][“games”][states(‘sensor.nhl_team_index’)|int][“teams”][“home”][“score”] }} with a static number such as 1 it still goes to the first one no matter what, as if it only works with 0.

Seems like it uses

“games”: [
{
“gamePk”: 2018030214,

as a key value for each game. How can I create a value_template that will only extract all the games value under a specific key value

For instance we keep the for loop looking to match the name but then we just keep all the values under the key connected to that particular game rather then the whole json.

ok so if I do:

{{ states.sensor.nhl_teams_index.attributes.dates[0][“games”][ 1 ][“teams”][“home”][“score”] }} it does take the 2nd record rather than the first one.

So something is wrong with:

{{ states.sensor.nhl_teams_index.attributes.dates[0][“games”][ states(‘sensor.nhl_team_index’)|int ][“teams”][“home”][“score”] }}