NFL game sensor (scores, possession, etc)

Thanks all for sharing your ESPN sensors and lovelace cards!

Question: For the REST sensors, I would like to add an automation to update frequently (every 5 seconds) during games. Will I need to include every sensor in the automation that falls under the single ESPN REST resource url, or will I be able to get away with just updating any single one of them and then the rest will ‘come along for the ride’ when the url gets pulled down for the one? I’m really hoping the REST sensor component is smart enough to update everything :crossed_fingers: :slight_smile:, otherwise that’s a LOT of sensors to add in, as I’m going to be tracking my wife’s, sister’s, and brother-in-law’s survivor pool teams each week.

I think one is sufficient.

1 Like

Can confirm, everything is updating wonderfully!

1 Like

How does your touchdown detector work?

Ok, I think I’ve settled on what I’m going with for my setup. I added timeouts, so here’s a screenshot of what my live score card currently looks like:

Rest Sensors:

Here’s the rest sensors that are pulling everything from ESPN. (This is set up for when I was watching Seattle, so you could just find and replace ‘SEA’ with whatever the short name of the team you want to track is.):

######################################
############NFL SENSORS############
######################################

########ESPN.COM JSON RETRIEVAL########

rest:
- resource: http://site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard
  scan_interval: 86400
  sensor:
########NFL SCORE SENSOR########
    - name: NFL Score
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% if competition.status.type.state != 'pre' or competition.status.type.state == 'post' %}
                  {% for competitor in competition["competitors"] %}
                    {% if  competitor.team.abbreviation == 'SEA' %}
                      {{ competitor.score }}
                    {% endif %}
                  {% endfor %}
                {% else %}
                  0
                {% endif %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL TOL SENSOR########  
    - name: NFL TOL
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation == 'SEA' %}
                    {% if competition.status.type.state == 'in' %}
                      {% if  competitor.homeAway == 'home' %}
                        {{ competition.situation.homeTimeouts }}
                      {% else %}
                        {{ competition.situation.awayTimeouts }}
                      {% endif %}
                    {% else %}
                      -
                    {% endif %}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL DISPLAY NAME SENSOR########  
    - name: NFL Display Name
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation == 'SEA' %}
                    {{ competitor.team.displayName }} ({{ competitor.records.0.summary }})
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL NAME ABBR SENSOR########  
    - name: NFL Name Abbr
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation == 'SEA' %}
                    {{ competitor.team.abbreviation }}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL NAME ID SENSOR########  
    - name: NFL Name ID
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation == 'SEA' %}
                    {{ competitor.team.id }}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL DISPLAY LOGO SENSOR########  
    - name: NFL Display Logo
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation == 'SEA' %}
                    {{ competitor.team.logo }}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL HOME AWAY SENSOR########  
    - name: NFL Home Away
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation == 'SEA' %}
                      {% if  competitor.homeAway == 'home' %}
                        Home
                      {% else %}
                        Away
                      {% endif %}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL OPPONENT SCORE SENSOR########
    - name: NFL Opponent Score
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% if competition.status.type.state != 'pre' or competition.status.type.state == 'post' %}
                  {% for competitor in competition["competitors"] %}
                    {% if  competitor.team.abbreviation != 'SEA' %}
                      {{ competitor.score }}
                    {% endif %}
                  {% endfor %}
                {% else %}
                  0
                {% endif %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL OPPONENT TOL SENSOR########  
    - name: NFL Opponent TOL
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation != 'SEA' %}
                    {% if competition.status.type.state == 'in' %}
                      {% if  competitor.homeAway == 'home' %}
                        {{ competition.situation.homeTimeouts }}
                      {% else %}
                        {{ competition.situation.awayTimeouts }}
                      {% endif %}
                    {% else %}
                      -
                    {% endif %}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL OPPONENT NAME SENSOR########  
    - name: NFL Opponent Name
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation != 'SEA' %}
                    {{ competitor.team.displayName }} ({{ competitor.records.0.summary }})
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL OPPONENT NAME ABBR SENSOR########  
    - name: NFL Opponent Name Abbr
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation != 'SEA' %}
                    {{ competitor.team.abbreviation }}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL OPPONENT NAME ID SENSOR########  
    - name: NFL Opponent Name ID
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation != 'SEA' %}
                    {{ competitor.team.id }}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL OPPONENT LOGO SENSOR########  
    - name: NFL Opponent Logo
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation != 'SEA' %}
                    {{ competitor.team.logo }}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL GAME STATUS SENSORS########
    - name: NFL Game Status
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% if competition.status.type.state == 'pre' %}
                    Pregame
                {% elif competition.status.type.state == 'post' %}
                    Final
                {% else %}
                    {{ competition.status.type.shortDetail }}
                {% endif %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL GAME CLOCK SENSOR########
    - name: NFL Game Clock
      value_template: >
        {% for event in value_json["events"] %}
          {% if 'SEA' in event.shortName %}
            {% for competition in event["competitions"] %}
                {{ competition.status.displayClock }}
            {% endfor %}
          {% endif %}
        {% endfor %}

########NFL GAME TIME SENSOR########
    - name: NFL Game Time
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {{ competition.date }}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL GAME CITY SENSOR########
    - name: NFL Game City
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {{ competition.venue.address.city }}, {{ competition.venue.address.state }}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL GAME VENUE SENSOR########  
    - name: NFL Game Venue
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {{ competition.venue.fullName }}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL GAME BROADCAST SENSOR########  
    - name: NFL Game Broadcast
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for broadcast in competition["broadcasts"] %}
                    {% for name in broadcast["names"] %}
                        {{ name }}
                    {% endfor %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL GAME LAST PLAY SENSOR########  
    - name: NFL Game Last Play
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {{ competition.situation.lastPlay.text }}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL GAME DOWN DISTANCE SENSOR########  
    - name: NFL Game Down Distance
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {{ competition.situation.downDistanceText }}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL GAME POSSESSION SENSOR########  
    - name: NFL Game Possession
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {{ competition.situation.possession }}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL GAME REDZONE SENSOR########  
    - name: NFL Game Redzone
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                {{ competition.situation.isRedZone }}
              {% endfor %}
            {% endif %}
          {% endfor %}

########NFL GAME ODDS SENSOR########  
    - name: NFL Game Odds
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'SEA' in event.shortName %}
              {% for competition in event["competitions"] %}
                ({{ competition.odds.0.details }})
              {% endfor %}
            {% endif %}
          {% endfor %}

Template Sensors:

And here are template sensors to process that data for my lovelace card:

#####################
###### Sensors ######
#####################

sensor:
########NFL SCOREBOARD DISPLAY SENSORS########
- platform: template
  sensors:
    nfl_sb_score:
      value_template: >
        {{ states('sensor.sb_nfl_tol') }} {{ states('sensor.nfl_score') }} 
      friendly_name_template: >
        {{ states('sensor.nfl_display_name') }} {{ states('sensor.sb_possession_display_nfl') }}
      entity_picture_template: >-
        {{ states('sensor.nfl_display_logo') }}
    nfl_sb_opponent_score:
      value_template: >
        {{ states('sensor.sb_nfl_opponent_tol') }} {{ states('sensor.nfl_opponent_score') }} 
      friendly_name_template: >
        {{ states('sensor.nfl_opponent_name') }} {{ states('sensor.sb_possession_display_nfl_opponent') }}
      entity_picture_template: >-
        {{ states('sensor.nfl_opponent_logo') }}
    sb_nfl_tol:
      value_template: >
        {% if states('sensor.nfl_tol') == '3' %}
            •••
        {% elif states('sensor.nfl_tol') == '2' %}
            ••
        {% elif states('sensor.nfl_tol') == '1' %}
            •
        {% else %}
            
        {% endif %}
      friendly_name_template: >
        {{ states('sensor.nfl_name_abbr') }} TO
    sb_nfl_opponent_tol:
      value_template: >
        {% if states('sensor.nfl_opponent_tol') == '3' %}
            •••
        {% elif states('sensor.nfl_opponent_tol') == '2' %}
            ••
        {% elif states('sensor.nfl_opponent_tol') == '1' %}
            •
        {% else %}
            
        {% endif %}
      friendly_name_template: >
        {{ states('sensor.nfl_name_abbr') }}
    sb_possession_display_nfl:
      value_template: >
        {% if states('sensor.nfl_game_possession') == states('sensor.nfl_name_id') %}
            🏈
        {% else %}
            
        {% endif %}
      friendly_name_template: >
        {{ states('sensor.nfl_name_abbr') }}
    sb_possession_display_nfl_opponent:
      value_template: >
        {% if states('sensor.nfl_game_possession') == states('sensor.nfl_opponent_name_id') %}
            🏈
        {% else %}
            
        {% endif %}
      friendly_name_template: >
        {{ states('sensor.nfl_opponent_name_abbr') }}
    sb_venue_status_nfl:
      value_template: >
        {{ states('sensor.nfl_game_status') }}
      friendly_name_template: >
        {{ states('sensor.nfl_game_venue') }}
    sb_city_odds_down_nfl: 
      value_template: >
        {% if states('sensor.nfl_game_status') == 'Pregame' %}
            {{ states('sensor.nfl_game_odds') }}
        {% elif states('sensor.nfl_game_status') == 'Final' %}
            
        {% else %}
            {{ states('sensor.nfl_game_down_distance') }}
        {% endif %}
      friendly_name_template: >
        {{ states('sensor.nfl_game_city') }}
    nfl_redzone:
      value_template: >
        {% if states('sensor.nfl_game_redzone') == 'True' %}
          {% if states('sensor.nfl_game_possession') == states('sensor.nfl_name_id') %}
            True
          {% else %}
            False    
          {% endif %}
        {% else %}
          False
        {% endif %}

Lovelace Card:

Here’s the updated code for the relevant parts of the card: (requires button-card and lovelace-card-mod )

type: vertical-stack
cards:
  - type: markdown
    content: >
      # <center> {{ as_timestamp(states('sensor.nfl_game_time')) |
      timestamp_custom("%A, %B %-d") }} 

      ## <center>{{ as_timestamp(states('sensor.nfl_game_time')) |
      timestamp_custom(" %-I:%M %p") }} ({{ states('sensor.nfl_game_broadcast')
      }})
  - type: entities
    entities:
      - entity: sensor.nfl_sb_score
        card_mod:
          style: |
            hui-generic-entity-row {
              font-size: 1.2em;
              font-weight: 350;
            }
      - entity: sensor.nfl_sb_opponent_score
        card_mod:
          style: |
            hui-generic-entity-row {
              font-size: 1.2em;
              font-weight: 350;
            }
      - type: divider
      - entity: sensor.sb_venue_status_nfl
        card_mod:
          style:
            hui-generic-entity-row:
              $: |
                state-badge {display:none;}
                .text-content {
                  margin-left: 0px !important;
                }
      - entity: sensor.sb_city_odds_down_nfl
        card_mod:
          style:
            hui-generic-entity-row:
              .: |
                .text-content {
                  font-weight: 100;
                }
              $: |
                state-badge {display:none;}
                .text-content {
                  margin-left: 0px !important;
                  font-weight: 100;
                      }
  - type: conditional
    conditions:
      - entity: sensor.nfl_game_status
        state_not: Pregame
      - entity: sensor.nfl_game_status
        state_not: Final
    card:
      type: custom:button-card
      name: |
        [[[return `<div style='display:flex'>
           <marquee>
           ${states['sensor.nfl_game_last_play'].state}
           </marquee>`]]]
      styles:
        card:
          - padding: 8px
          - font-size: 15px
  - type: horizontal-stack
    cards:
      - type: button
        tap_action:
          action: call-service
          service: homeassistant.update_entity
          service_data: {}
          target:
            entity_id:
              - sensor.nfl_game_status
        icon: mdi:football-helmet
        icon_height: 50px
        name: Update Sensors

*I also added a red zone sensor in there, but Saints played miserably today, so didn’t get to test it until a later game. I also didn’t put the red zone status in the card.

2 Likes

Finally we’re getting back to the original purpose of this whole thread, lol.

Touchdown Detector:

This is definitely not the only way to do this. (I noticed there is a ‘scoreValue’ variable in the ESPN api, which identifies how much the score has just changed.) The method I use below is basically a holdover from how we in this thread were doing it when using the NFL.com api.

First, I created a helper input boolean in the UI and called it “NFL Touchdown Detector”

Here’s the automation that turns on the boolean when a touchdown is scored by my team:

alias: NFL - Input Boolean Control - Turn On/Off Touchdown Tracker Input Boolean
description: Turns on input boolean for one minute if team score changes by 6+ points
trigger:
  - platform: state
    entity_id: sensor.nfl_score
condition:
  - condition: template
    value_template: |-
      {{ trigger.to_state is not none and trigger.from_state is not none and
               trigger.to_state.state|int > (trigger.from_state.state|int + 5)
            }}
action:
  - service: input_boolean.turn_on
    data: {}
    entity_id: input_boolean.nfl_touchdown_detector
  - delay: '00:03:00'
  - service: input_boolean.turn_off
    data: {}
    entity_id: input_boolean.nfl_touchdown_detector
mode: single

Win Detector:

I also have a “win detector,” which uses another helper input boolean called “NFL Win Detector”:

alias: >-
  NFL - Input Boolean Control - Turn On/Off Win Input Boolean
description: Turns on input boolean for five minutes when team wins
trigger:
  - platform: state
    entity_id: sensor.nfl_game_status
    to: Final
condition:
  - condition: template
    value_template: >-
      {{ states("sensor.nfl_score")|int >
      states("sensor.nfl_opponent_score")|int }}
action:
  - service: input_boolean.turn_on
    data: {}
    entity_id: input_boolean.nfl_win_detector
  - delay: '00:05:00'
  - service: input_boolean.turn_off
    data: {}
    entity_id: input_boolean.nfl_win_detector
mode: single

I use the on/off state of these input boolean helpers to trigger any automations.

Input Boolean Reset Automation:

**It doesn’t hurt to also go ahead and make a built-in reset function to make sure your input booleans are off when they should be. This one below just turns them all off when HA starts.

alias: NFL - Input Boolean Control - All NFL Booleans Reset on HA Restart
description: ''
trigger:
  - platform: homeassistant
    event: start
condition: []
action:
  - service: input_boolean.turn_off
    data: {}
    entity_id: input_boolean.nfl_touchdown_detector
  - service: input_boolean.turn_off
    data: {}
    entity_id: input_boolean.nfl_win_detector
  - delay: '00:00:30'
  - service: homeassistant.update_entity
    data: {}
    entity_id: sensor.nfl_game_status
mode: single

Update Automation for During Game

Just a reminder, in order for these to actually be live, you need to be forcing the rest sensors to update. I have mine set to update every 3 seconds during the game, which is determined by the status of the google calendar @D34DC3N73R and @djbrooks022 mentioned above. You don’t want the rest sensors taking up resources by updating all of the time while games aren’t active.

Here’s how I have set up my automation:

alias: Saints - NFL Scores - Update JSON/XML Every 3 Seconds During Game Only
description: ''
trigger:
  - platform: state
    entity_id: sensor.nfl_game_status
    from: Pregame
  - platform: state
    entity_id: calendar.new_orleans_saints
    to: 'on'
    from: 'off'
  - platform: template
    value_template: >-
      {{ (state_attr('calendar.new_orleans_saints', 'start_time') | as_timestamp
      - now() | as_timestamp) < 300 and
      (state_attr('calendar.new_orleans_saints', 'start_time') | as_timestamp -
      now() | as_timestamp) > 0 }}
condition:
  - condition: or
    conditions:
      - condition: state
        entity_id: calendar.new_orleans_saints
        state: 'on'
      - condition: not
        conditions:
          - condition: state
            entity_id: sensor.nfl_game_status
            state: Final
      - condition: template
        value_template: >-
          {{ (state_attr('calendar.new_orleans_saints', 'start_time') |
          as_timestamp - now() | as_timestamp) < 300 and
          (state_attr('calendar.new_orleans_saints', 'start_time') |
          as_timestamp - now() | as_timestamp) > 0 }}
action:
  - repeat:
      until:
        - condition: or
          conditions:
            - condition: state
              entity_id: sensor.nfl_game_status
              state: Final
            - condition: state
              entity_id: calendar.new_orleans_saints
              state: 'off'
              for: '01:00:00'
      sequence:
        - service: homeassistant.update_entity
          data: {}
          target:
            entity_id:
              - sensor.nfl_game_status
              - sensor.nfl_score
              - sensor.nfl_opponent_score
        - delay:
            hours: 0
            minutes: 0
            seconds: 3
            milliseconds: 0
mode: single

Hope this helps!

2 Likes

It does! Thank you.

I just can’t get that damn possession football to show up on the Lovelace card. I was trying to find the issues while being pissed off at the Chiefs defense and drinking beer. So instead of breaking my entire HA setup, I waited until today.

I added a win probability conditional card to my setup. Still trying to work out some of the kinks, but I have it set up to use team colors, and switching to alternate team colors when my dark mode is active.

light mode / team colors

dark mode / alt team colors

If anyone is interested I can post the sensors / lovelace card.

2 Likes

Good work! I would love to see the code for that.

I still have to work out some logic for when the value isn’t available during game time, but this is what I have so far.

The card uses mini graph card. If you want team colors it also requires lovelace card templater, which requires lovelace card tools.

rest sensors

########PACKERS HOME/AWAY SENSOR########
    - name: Packers Home/Away
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'GB' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation == 'GB' %}
                    {% if competitor.homeAway == 'home' %}
                      Home
                    {% else %}
                      Away
                    {% endif %}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

########PACKERS WIN PROBABILITY SENSOR########
    - name: Probability Home
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'GB' in event.shortName %}
              {% for competition in event["competitions"] %}
                {{ competition.situation.lastPlay.probability.homeWinPercentage }}
              {% endfor %}
            {% endif %}
          {% endfor %}

    - name: Probability Away
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'GB' in event.shortName %}
              {% for competition in event["competitions"] %}
                {{ competition.situation.lastPlay.probability.awayWinPercentage }}
              {% endfor %}
            {% endif %}
          {% endfor %}

########PACKERS TEAM COLORS########
    - name: Packers Color
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'GB' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation == 'GB' %}
                    #{{ competitor.team.color }}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

    - name: Packers Alt Color
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'GB' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation == 'GB' %}
                    #{{ competitor.team.alternateColor }}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

    - name: Packers Opponent Color
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'GB' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation != 'GB' %}
                    #{{ competitor.team.color }}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

    - name: Packers Opponent Alt Color
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'GB' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% for competitor in competition["competitors"] %}
                  {% if  competitor.team.abbreviation != 'GB' %}
                    #{{ competitor.team.alternateColor }}
                  {% endif %}
                {% endfor %}
              {% endfor %}
            {% endif %}
          {% endfor %}

template sensors

sensor:
########PACKERS SCOREBOARD DISPLAY SENSORS########
  - platform: template
    sensors:
      [...]
      packers_win_probability:
        value_template: >
          {% if states('sensor.packers_home_away') == 'Home' %}
            {{ states('sensor.probability_home') | float * 100 }}
          {% else %}
            {{ states('sensor.probability_away') | float * 100 }}
          {% endif %}
        friendly_name_template: >
          {{ states('sensor.packers_display_name') }}
      opponent_win_probability:
        value_template: >
          {% if states('sensor.packers_home_away') == 'Home' %}
            {{ states('sensor.probability_away') | float * 100 }}
          {% else %}
            {{ states('sensor.probability_home') | float * 100 }}
          {% endif %}
        friendly_name_template: >
          {{ states('sensor.packers_opponent_name') }}

lovelace card

- type: conditional
  conditions:
    - entity: sensor.packers_game_status
      state_not: Pregame
    - entity: sensor.packers_game_status
      state_not: Final
  card:
    type: 'custom:card-templater'
    card:
      type: 'custom:mini-graph-card'
      name: WIN PROBABILITY
      icon: 'mdi:percent'
      hours_to_show: 3
      points_per_hour: 120
      aggregate_func: last
      animate: true
      entities:
        - entity: sensor.packers_win_probability
          color_template: >
            {% if states('input_boolean.dark_mode') == 'on' %}
             {{ states('sensor.packers_alt_color') }}
            {% else %}
             {{ states('sensor.packers_color') }}
            {% endif %}
        - entity: sensor.opponent_win_probability
          color_template: >
            {% if states('input_boolean.dark_mode') == 'on' %}
             {{ states('sensor.packers_opponent_alt_color') }}
            {% else %}
             {{ states('sensor.packers_opponent_color') }}
            {% endif %}
1 Like

oh and btw, if you want your last play button card to display the full card width, even if the info is shorter, you can add this:

card_mod:
  style: 
    div#container: |
      div#name {
        width: 100%;
      }
2 Likes

Awesome, thanks. I definitely have no idea what I’m doing!

LOL, I think you and D34DC3N73R have both done awesome work! My wife was very excited by the possession and timeout indicators last night during the Packers/Lions game.

I noticed a lot of log errors (many thousands) concerning the ‘situation’ key being missing in the json while I was setting up the newest sensors yesterday. As a temporary workaround I disabled logging for that component for anything but a fatal error in my configuration.yaml:

logger:
  #default: info
  default: warn
  logs:
    homeassistant.helpers.template: fatal

But long term I’d like to keep template error logging at its default level and try to figure out how to prevent these templates from causing the error. I haven’t looked into it much yet, but. I’m pretty sure the situation key isn’t available except during live games, so we’d need to catch that condition and handle creating those state differently.

Yes, those are only available during the game. With a scan interval of 86400 (24 hours), I get 5 of these errors per day with all the sensors.

 ERROR (MainThread) [homeassistant.helpers.template] Template variable error: 'dict object' has no attribute 'situation' when rendering '{% for event in value_json["events"] %}

I guess you’d get many more if you’re tracking more than one team, and one of the games was live.

Off the top of my head, it would be possible to include each of the problem sensors in a txt file for each team and inject them into the configuration.yaml at game time. But, that would require restarting HA for them to take effect.

Another option (which I haven’t tested at all) would be to set up separate resource blocks in rest: for each team. I think that would stop HA from trying to pull stats so frequently for games that are not happening. But, you’d still get 5 errors per day per team.

I might go the txt file route. FWIW, a HA restart isn’t necessary, there are services for reloading rest and template sensors:

service: rest.reload

and

service: template.reload

They’re available as buttons under the Server Controls in in Configuration, or as services you can call in developer tools or via scripts/automations/etc.

If I get ambitious (and find a few hours to kill), I might still try to build a template that won’t balk at the missing situation key, but I can live with what I’ve got. I kept the 86400 seconds as scan interval and then use an automation to manually update when I care about the live info, I’ll just keep it switched off the rest of the time.

Thanks again for everything!

This should get rid of the errors. I haven’t tested it during a game yet, but I think it should parse the new info from the json feed when the game is live.

    - name: Packers Game Possession
      value_template: >
          {% for event in value_json["events"] %}
            {% if 'GB' in event.shortName %}
              {% for competition in event["competitions"] %}
                {% if competition.status.type.state == 'pre' or competition.status.type.state == 'post' %}
                  {% set situation = {'possession': 'null'} %}
                {% else %}
                  {{ competition.situation.possession }}
                {% endif %}
              {% endfor %}
            {% endif %}
          {% endfor %}
2 Likes

I added a sensor that allows you to easily define the abbreviation for all of the sensors at once.

rest:
- resource: http://site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard
  scan_interval: 86400
  sensor:
    - name: My Team
      value_template: >
        {% set my = { "team": 'GB' } %}
        {{ my.team }}
    [...]

Then you can replace the abbreviation in the sensors with states.sensor.my_team.state
So

{% if 'GB' in event.shortName %}

becomes

{% if states.sensor.my_team.state in event.shortName %}

We should really start a github repo to track changes.

1 Like

We should really start a github repo to track changes.

Yah, it seems like that would be useful. At this point I imagine it would be relatively easy to wrap all the work you’ve all done as a custom component as well. In the meantime, I would be happy to spin up a new repo and all all as contributors.

2 Likes

I’d personally be hesitant to release a custom component using an unofficial API. But I do think it’d be nice to have a repo to consolidate all the info and submit PRs.

Yah… I’m thinking I will require the user to enter the API endpoint, so that it isn’t my responsibility. That said, I have an initial version working with this as a sensor, where the state is the game state, and a bunch of stuff is available as attributes. I need to work on making the polling interval smart (and fix the bug with timeouts), but so far it is a nice start.

It’s a PITA to add new attributes, but if there are any that seem essential, let me know and I can add before sharing the component.

1 Like