Real-Time Sports Scores w/ TeamTracker and TeamTracker-Card (Beta)

I’m going to jump in to ask for some help too. I just discovered that the API explorer is gone and I’m having no luck finding my team.

The Charlotte 49ers College Basketball team has switched to the NCAAF and I haven’t found the magic combination to bring up their data. Any pointers.

Thanks!

For college football and basketball, you need to specify a conference id unless your team is ranked. Conference USA is 12 for football, 11 for basketball.

Thank you!

I’ve been using a version of this to track the MLB standings for the AL East all season. It has worked flawlessly for the entire season until the last week or so. Now, it seems the data structure has changed and the values no longer match the columns in my table - but only for some of the teams. Have you noticed the same issue? And do you have any advice for how to adjust for this?

Can you send an image of what you are seeing?
Mine seems to be fine … so possibly you have some older code.

One possibility is that you still use the positional way to obtain stats. Once teams start clinching, the positions of the data changes so things like x.stats[10] will not work… I use decluttering and this is what I use for MLB you can see I use x.stats.find(y=>y.abbreviation == 'AWAY').displayValue:

  mlb_settings:
    card:
      type: custom:flex-table-card
      title: '[[title]]'
      css:
        table+: 'padding: 0px; width: 1600px;'
        tbody tr td:first-child: 'width: 20%;'
        tbody tr td:nth-child(n+2): 'width: 5%;'
        tbody tr:hover: 'background-color: green!important; color:white!important;'
        tbody tr td:nth-child(5): 'background-color: green; color: white;'
      card_mod:
        style:
          .: |
            ha-card {
              overflow: auto;
              }
          $: |
            .card-header {
               padding-top: 6px!important;
               padding-bottom: 4px!important;
               font-size: 14px!important;
               line-height: 14px!important;
               font-weight: bold!important;
             }
      entities:
        include: '[[entity]]'
      sort_by: entries-
      columns:
        - hidden: true
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'PCT').value
        - name: Team
          data: entries
          modify: >-
            '<div><img src="' + x.team.logos[0].href + '" style="height:
            20px;vertical-align:middle;">&nbsp;' + x.team.displayName + '</div>'
        - name: GP
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'GP').displayValue
        - name: W
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'W').displayValue
        - name: L
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'L').displayValue
        - name: PCT
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'PCT').value.toFixed(2)
        - name: GB
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'GB').displayValue
        - name: HOME
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'Home').displayValue
        - name: AWAY
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'AWAY').displayValue
        - name: RS
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'RS').displayValue
        - name: RA
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'RA').displayValue
        - name: DIFF
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'DIFF').displayValue
        - name: L10
          data: entries
          modify: x.stats.find(y=>y.shortDisplayName == 'L10').displayValue
        - name: STRK
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'STRK').displayValue

That is precisely what I’m doing, and I figured it had something to do with approaching the end of the regular season. Here is what I’m seeing:

I don’t remember whose code I coped, and I didn’t know there was “newer code”, but here is what I have:

decluttering_templates:
  mlb_settings:
    card:
      type: custom:flex-table-card
      title: '[[title]]'
      css:
        table+: 'padding: 0px; width: 1000px;'
        tbody tr td:first-child: 'width: 12%;'
        tbody tr td:nth-child(n+2): 'width: 5%;'
        tbody tr:hover: 'background-color: lightgreen!important;'
      card_mod:
        style: |
          ha-card {
              overflow: none;
              box-shadow: none;  
              background: none;
              border: none;
            }        
      entities:
        include: '[[entity]]'
      sort_by: entries-
      columns:
        - hidden: true
          data: entries
          modify: x.stats[16].value
        - name: Team
          data: entries
          modify: x.team.displayName
        - name: PLAYED
          data: entries
          modify: x.stats[7].displayValue
        - name: WON
          data: entries
          modify: x.stats[18].displayValue
        - name: LOST
          data: entries
          modify: x.stats[9].displayValue
        - name: PCT
          data: entries
          modify: x.stats[17].displayValue
        - name: GB
          data: entries
          modify: x.stats[6].displayValue
        - name: HOME
          data: entries
          modify: x.stats[33].displayValue
        - name: AWAY
          data: entries
          modify: x.stats[34].displayValue
        - name: FOR
          data: entries
          modify: x.stats[14].displayValue
        - name: AGAINST
          data: entries
          modify: x.stats[13].displayValue
        - name: DIFF
          data: entries
          modify: x.stats[11].displayValue
        - name: L10
          data: entries
          modify: x.stats[37].summary
        - name: STREAK
          data: entries
          modify: x.stats[15].displayValue

I’ll take a look at your code and se if I can figure out what I need to change. Thanks!

Yes, that is the older code.
If you give me a few hours, I will add the CLINCH flag display. I did it for NHL, it is pretty straightforward. For information, that data is “z”, “e” stuff here:

A while back, @kbrown01 changed from using the numbers to using the abbreviations:
x.stats.find(y=>y.abbreviation == ‘L’).displayValue

Oh, that is really odd. The Blue Jays and Yankees seem to have the old order. The others have a new order.

Exactly, the issue you are having is that for teams that have Clinched (or are Eliminated) from the Playoffs, ESPN adds this:

      - name: clincher
        displayName: Clincher
        shortDisplayName: CLINCH
        description: Clinched Playoff Berth
        abbreviation: CLINCH
        type: clincher
        value: 3
        displayValue: z

So you could add a new column after the first hidden column like this:

        - name: C
          data: entries
          modify: >-
            if(typeof x.stats.find(y=>y.abbreviation == 'CLINCH') !==
            'undefined' ){x.stats.find(y=>y.abbreviation ==
            'CLINCH').displayValue}else{'-'}

NOTE: you must use the if here because if the CLICH field does not exists yet (as it doesn’t for teams who haven’t or are eliminated), it will be an error.

I follow NHL mostly and NFL, so I had not done all the updates on MLB or NBA including some form of Playoff. For your use, I will post here code for NHL which you can use to study.

Decluttering Template:

  nhl_settings:
    card:
      type: custom:flex-table-card
      title: '[[title]]'
      css:
        table+: 'padding: 0px; width: 1600px;'
        tbody tr td:first-child: 'width: 2%;'
        tbody tr td:nth-child(2): 'width: 20%;'
        tbody tr td:nth-child(n+3): 'width: 5%;'
        tbody tr:hover: 'background-color: green!important; color:white!important;'
        tbody tr td:nth-child(7): 'background-color: green; color: white;'
      card_mod:
        style:
          .: |
            ha-card {
              overflow: auto;
              }
          $: |
            .card-header {
               padding-top: 6px!important;
               padding-bottom: 4px!important;
               font-size: 14px!important;
               line-height: 14px!important;
               font-weight: bold!important;
             }
      entities:
        include: '[[entity]]'
        exclude: '[[excluded_entities]]'
      sort_by: entries-
      columns:
        - hidden: true
          data: '[[attribute]]'
          modify: '[[sort]]'
        - name: >-
            <div title="Clinch Indicator:&#10; * : Presidents Trophy&#10; x :
            Playoff Berth&#10; - : In The Hunt&#10; e : Eliminated">C</div>
          data: '[[attribute]]'
          modify: >-
            if(typeof x.stats.find(y=>y.abbreviation == 'CLINCH') !==
            'undefined' ){x.stats.find(y=>y.abbreviation ==
            'CLINCH').displayValue}else{'-'}
        - name: Team
          data: '[[attribute]]'
          modify: >-
            '<div><a href="' + x.team.links[0].href + '" target="_blank"><img
            src="' + x.team.logos[0].href + '" style="height:
            20px;vertical-align:middle;"></a>&nbsp;' + x.team.displayName +
            '</div>'
        - name: <div title="Games Played">GP</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'GP').displayValue
        - name: <div title="Wins">W</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'W').displayValue
        - name: <div title="Losses">L</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'L').displayValue
        - name: <div title="Overtime/Shootout Losses">OTL</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'OTL').displayValue
        - name: <div title="Points">PTS</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'PTS').displayValue
        - name: <div title="Regulation Wins">RW</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'RW').displayValue
        - name: <div title="Regulation and Overtime Wins">ROW</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'ROW').displayValue
        - name: <div title="Shootout Wins">SOW</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'SOW').displayValue
        - name: <div title="Shootout Losses">SOL</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'SOL').displayValue
        - name: <div title="Home Record">HOME</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'HOME').displayValue
        - name: <div title="Away Record">AWAY</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'AWAY').displayValue
        - name: <div title="Goals For">GF</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'GF').displayValue
        - name: <div title="Goals Against">GA</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'GA').displayValue
        - name: <div title="Game Average Goal Differential">DIFF</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'DIFF').displayValue
        - name: <div title="Last 10 Games">L10</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'L10').summary
        - name: <div title="Current Streak">STRK</div>
          data: '[[attribute]]'
          modify: x.stats.find(y=>y.abbreviation == 'STRK').displayValue

Using that template:

                                  - type: custom:decluttering-card
                                    template: nhl_settings
                                    variables:
                                      - title: Eastern Atlantic
                                      - entity: sensor.nhl_east_atlantic
                                      - attribute: entries
                                      - excluded_entities:
                                          - sensor.nhl_starting_goalies
                                          - sensor.nhl_wildcard
                                          - sensor.nhl_wildcard_standings
                                      - sort: >-
                                          x.stats.find(y=>y.shortDisplayName ==
                                          'PTS').value

You can see here a few things.

  1. the variables include the attribute you wish to use (in most cases this is entries).
  2. You can also pass in a set of excluded entities because in divisional and overall, the code would try to get sensor.nhl_*_* and if you had a sensor like sensor.nhl_starting_goalies it would grab that sensor and this would break the card.
  3. It also allows you to pass in the sort so you can decide how you wish to sort and use the same template.
  4. It redoes how the name of the field is displayed (in a
    ) so you can add a title which results in a tooltip if you mouse over it.

@jeffcrum … if you track it through it is probably sorted as specified. The key is the x.stats[16].value is a is a different column for those with “x” or “e” than it is for those without. Who knows but it is likely two different columns, one could be “WON” and and the other “LOSSES”

Yeah. I am working and didn’t have time to do that. Just noting an observation that I saw.

Here is a simple decluttering template without all the bells and whistles in the NHL one.

  mlb_settings:
    card:
      type: custom:flex-table-card
      title: '[[title]]'
      css:
        table+: 'padding: 0px; width: 1600px;'
        tbody tr td:first-child: 'width: 2%;'
        tbody tr td:nth-child(2): 'width: 20%;'
        tbody tr td:nth-child(n+3): 'width: 5%;'
        tbody tr:hover: 'background-color: green!important; color:white!important;'
        tbody tr td:nth-child(6): 'background-color: green; color: white;'
      card_mod:
        style:
          .: |
            ha-card {
              overflow: auto;
              }
          $: |
            .card-header {
               padding-top: 6px!important;
               padding-bottom: 4px!important;
               font-size: 14px!important;
               line-height: 14px!important;
               font-weight: bold!important;
             }
      entities:
        include: '[[entity]]'
      sort_by: entries-
      columns:
        - hidden: true
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'PCT').value
        - name: C
          data: entries
          modify: >-
            if(typeof x.stats.find(y=>y.abbreviation == 'CLINCH') !==
            'undefined' ){x.stats.find(y=>y.abbreviation ==
            'CLINCH').displayValue}else{'-'}
        - name: Team
          data: entries
          modify: >-
            '<div><img src="' + x.team.logos[0].href + '" style="height:
            20px;vertical-align:middle;">&nbsp;' + x.team.displayName + '</div>'
        - name: GP
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'GP').displayValue
        - name: W
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'W').displayValue
        - name: L
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'L').displayValue
        - name: PCT
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'PCT').value.toFixed(2)
        - name: GB
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'GB').displayValue
        - name: HOME
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'Home').displayValue
        - name: AWAY
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'AWAY').displayValue
        - name: RS
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'RS').displayValue
        - name: RA
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'RA').displayValue
        - name: DIFF
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'DIFF').displayValue
        - name: L10
          data: entries
          modify: x.stats.find(y=>y.shortDisplayName == 'L10').displayValue
        - name: STRK
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'STRK').displayValue

For those interested in seeing what is going on, you can paste this into Developer Tools Template.

{%- for team in states.sensor.mlb_american_west.attributes.entries %}

{{ team.team.displayName }}
{%- set ns = namespace(count=0) -%}
{%- for stat in team.stats %}
{{ ns.count }} : {{ stat.abbreviation }} : {{ stat.displayName }} : {{ stat.displayValue }}
 x.stats.find(y=>y.abbreviation == '{{ stat.abbreviation }}').displayValue
  {%- set ns.count = ns.count + 1 -%}
{%- endfor -%}
{%- endfor -%}

You can see that both the Angels and Athletics have a CLINCH field defined. But, the other three do not. So, everything after number 4 is shifted one.

This shows the number, abbreviation, display name, and display value for each stat. It also builds the line using the abbreviation that can go in the modify statements.

This clearly shows why it makes sense to use the abbreviation instead of numbers.

LOVE this integration - i have a new problem, too many active game cards concurrently.

Is there a way to use the size of the PRE or POST cards for an “active” game so it’s smaller with less information and shows just teams, inning, score, time, etc?

WHat way are you laying out the card in the view? You need to tell us.
If you are using my integration it is using masonry layout.

Apologies for my lack of specificity. I’m using the team tracker card and looking for a more compact version of the team tracker card when the game is in progress. A compact version that is the same size as pre or post would be great!

I would think everything should scale. Like putting it into a custom:layout-card with 4 columns or maybe even 5

Thanks for the thought, unfortunately the current “in game” card has too much data to scale into a “compact” form, see example below:

My preference is to have a “minimal in game” card based on the current “in game” card that cuts off everything after the inning. this would give me the minimum info on the event. same idea for basketball and football.

I tried to add a Pull Request but got denied as i’m not a contributor.

That is not displaying anything that you could not make in a separate card/set of cards. All the data is in the teamtracker sensor.

Like I use declutter and card_mod for color changes when in the red zone. Also have light scenes and TTS announcements on game start and TDs.