Sports Standings and Scores

OK, you can try this as only inside your favorites template. Tell me if it works please. I have tested with:

Fav Home v non Fav Away
Fav Home v Fav Away
non Fav Home v Fav Away

It seems to work and not repeat entries.

  - type: custom:auto-entities
    unique: true
    show_empty: false
    card:
      type: custom:layout-card
      layout_type: masonry
    card_param: cards
    filter:
      template: >
        {% set ft = namespace(events=[]) %}
        {% set favs = namespace(fav=[]) %}
        {% for team in integration_entities("teamtracker") %}
          {% if team in state_attr('group.team_favorities','entity_id') %}
            {% if state_attr(team, "event_name") %}
              {% set ft.events = ft.events + [state_attr(team, "event_name")] %}
            {% endif %}
          {% endif %}
        {% endfor %}
        {% for event in ft.events | unique | list %}
          {% for team in integration_entities("teamtracker") %}
              {%- if state_attr(team, "event_name") == event and (state_attr(team, "team_homeaway") == "home" or state_attr(team, "league") == "NCAAM")-%}
                {% set favs.fav = favs.fav + [team] %}
              {% endif %}
          {% endfor %}
        {% endfor %}
        {%- for eid in favs.fav -%}
        {{{"type": "custom:teamtracker-card",
           "entity": eid,
            "home_side": "right"}}},
        {%- endfor -%}
      exclude:
        - entity_id: '*team_tracker*'
      unique: true
    sort:
      method: attribute
      attribute: date

What this does …

  1. Creates a unique list of games by the “event_name” for those in your favorites
  2. Goes through all the teams and grabs the home team only for the same event (unless it is NCAAM now for tournament)

I added the Lightning, Panthers, Capitals and Blues in my favorites.
Lighting and Panthers are away
Capitals are home
Wings and Blues play eachother

Yes it seems to be working. I don’t currently have any teams playing against each other.

1 Like

If anyone would like a new thing to drop into your tabs for NHL, here is a new one for starting goalies.

Sensor Setup:

##
## Starting Goalies
##
- platform: rest
  name: nhl_starting_goalies
  scan_interval: 3600
  resource: https://www.dailyfaceoff.com/_next/data/AARRTVjTYQ3P1ZXMqUh-M/starting-goalies.json
  value_template: "{{ value_json.pageProps.date }}"
  json_attributes_path: "$.pageProps"
  json_attributes:
    - data

Lovelace Card:

type: custom:flex-table-card
title: Starting Goalies
css:
  table+: 'padding: 0px; width: 1600px;'
  tbody tr:hover: 'background-color: green!important; color:white!important;'
card_mod:
  style: |
    ha-card {
        overflow: auto;
    }
    $: |
        .card-header {
           padding: 12px 0px 8px 4px!important;
           font-size: 16px!important;
           line-height: 18px!important;
           font-weight: bold!important;
         }
entities:
  include: sensor.nhl_starting_goalies
columns:
  - name: HOME
    data: data
    modify: >-
      '<div><img src="' + x.homeTeamLogoSvg + '" style="height:
      20px;vertical-align:middle;">&nbsp;' + x.homeTeamName + '</div>'
  - name: GOALIE
    data: data
    modify: x.homeGoalieName
  - name: RANK
    data: data
    modify: >-
      if(x.homeGoaliePositionRank === null ){'N/A'}else{x.homeGoaliePositionRank}
  - name: W
    data: data
    modify: x.homeGoalieWins
  - name: L
    data: data
    modify: x.homeGoalieLosses
  - name: OTL
    data: data
    modify: x.homeGoalieOvertimeLosses
  - name: SO
    data: data
    modify: x.homeGoalieShutouts
  - name: SVP
    data: data
    modify: x.homeGoalieSavePercentage
  - name: GAA
    data: data
    modify: x.homeGoalieGoalsAgainstAvg
  - name: AWAY
    data: data
    modify: >-
      '<div><img src="' + x.awayTeamLogoSvg + '" style="height:
      20px;vertical-align:middle;">&nbsp;' + x.awayTeamName + '</div>'
  - name: GOALIE
    data: data
    modify: x.awayGoalieName
  - name: RANK
    data: data
    modify: >-
      if(x.awayGoaliePositionRank == null ){'N/A'}else{x.awayGoaliePositionRank}
  - name: W
    data: data
    modify: x.awayGoalieWins
  - name: L
    data: data
    modify: x.awayGoalieLosses
  - name: OTL
    data: data
    modify: x.awayGoalieOvertimeLosses
  - name: SO
    data: data
    modify: x.awayGoalieShutouts
  - name: SVP
    data: data
    modify: x.awayGoalieSavePercentage
  - name: GAA
    data: data
    modify: x.awayGoalieGoalsAgainstAvg

Results:

Plugged into another tab, it looks like this:

Thats nice, but why I have only three goalies?

I copied the code from you above completely

There is only three games today! This is “Starting Goalies for Today”!!! WHen the site updates data sometime late tonight after the current games are over, it will have tomorrows games (which is nearly everyone).

And to note, you have six goalies listed there. Three games = Three home + Three away. It is listed head to head (Home goalie versus Away goalie).

I did add also a “PICK” that is based on only GAA now. I am looking for a good mathematical representation using GAA and SVP to denote whom should be the preferred goalie at the matchup.

Sorry, I misunderstood this statistic. Then of course it’s logical.

If we can still do something in the code so that such an output does not happen, the whole display will be destroyed:

And can we get the Code with the Pick?

Ein aktuell anderes Problem habe ich noch bei Overall.

With the code:

type: custom:decluttering-card
    template: nhl_settings
    variables:
      - title: Overall
      - entity: sensor.nhl_*_*
      - sort: x.stats.find(y=>y.shortDisplayName == 'PTS').value

the output is complete empty:

Devisional and Conference works fine.

Either rename the starting goalies sensor or add an exclude to not use it in the sensor. It by wildcard is including all nhl sensors and because it was named nhl_starting_goalies that is breaking the team stats

ok I understand, but how I must put the exclude in this code?

type: custom:decluttering-card
template: nhl_settings
variables:
  - title: Overall
  - entity: sensor.nhl_*_*
  - sort: x.stats.find(y=>y.shortDisplayName == 'PTS').value

Actually you put it right into the decluttering_template for nhl_settings. Find the entities part and add it there like this:

      entities:
        include: '[[entity]]'
        exclude: sensor.nhl_starting_goalies

This will exclude the nhl_starting_goalies sensor for anything using the nhl_settings template.

In witch part of the code you mean?

not in this?

type: custom:decluttering-card
template: nhl_settings
variables:
  - title: Overall
  - entity: sensor.nhl_*_*
  - sort: x.stats.find(y=>y.shortDisplayName == 'PTS').value

if it is not the part, then where is this part?

No. Look at the very top of the dashboard:

I see another issue with goalie data, need to protect against null values in more fields. I will fix this shortly.

thanks it works.

yes, this is what I write in this post:

And can you put your code with the pick? I think this is a really good idea.

Yes well it is a work in progress. Sometimes the website returns “0” wins, sometimes it returns null. So this fixes Wins, Losses, Shut Outs and OTL for home and away. I do not believe any others can break things.

This also has the simple code that draws the arrow based solely for now on GAA. Keep in mind that its not perfect. Like a goalie who hasn’t played a single game would have “0” and one that played will be larger. It is only an indicator.

type: custom:flex-table-card
title: Starting Goalies
css:
  table+: 'padding: 0px; width: 1600px;'
  tbody tr:hover: >-
    background-color: green!important;
    color:white!important;
  tbody tr td:nth-child(10): 'background-color: green; color: white;'
card_mod:
  style: |
    ha-card {
        overflow: auto;
    }
    $: |
        .card-header {
           padding: 12px 0px 8px 4px!important;
           font-size: 16px!important;
           line-height: 18px!important;
           font-weight: bold!important;
         }
entities:
  include: sensor.nhl_starting_goalies
columns:
  - name: HOME
    data: data
    modify: >-
      '<div><img src="' + x.homeTeamLogoSvg + '"
      style="height:
      20px;vertical-align:middle;">&nbsp;' +
      x.homeTeamName + '</div>'
  - name: GOALIE
    data: data
    modify: x.homeGoalieName
  - name: RANK
    data: data
    modify: >-
      if(x.homeGoaliePositionRank === null
      ){'N/A'}else{x.homeGoaliePositionRank}
  - name: W
    data: data
    modify:  >-
      if(x.homeGoalieWins === null
      ){'N/A'}else{x.homeGoalieWins}
  - name: L
    data: data
    modify: >-
      if(x.homeGoalieLosses === null
      ){'N/A'}else{x.homeGoalieLosses}
  - name: OTL
    data: data
    modify: >-
      if(x.homeGoalieOvertimeLosses === null
      ){'N/A'}else{x.homeGoalieOvertimeLosses}
  - name: SO
    data: data
    modify: >-
      if(x.homeGoalieShutouts === null
      ){'N/A'}else{x.homeGoalieShutouts}
  - name: SVP
    data: data
    modify: Number(x.homeGoalieSavePercentage).toFixed(3)
  - name: GAA
    data: data
    modify: Number(x.homeGoalieGoalsAgainstAvg).toFixed(2)
  - name: PICK
    data: data
    modify: |-
      switch(true){
        case (x.homeGoalieGoalsAgainstAvg == 0) || (x.awayGoalieGoalsAgainstAvg == 0) :
          '<div style="text-align:center;"><ha-icon icon="mdi:crosshairs-question"></div>';
          break;
        case (x.homeGoalieGoalsAgainstAvg - x.awayGoalieGoalsAgainstAvg) > 0:
          '<div style="text-align:center;"><ha-icon icon="mdi:arrow-right"></div>';
          break;
        case (x.homeGoalieGoalsAgainstAvg - x.awayGoalieGoalsAgainstAvg) < 0:
          '<div style="text-align:center;"><ha-icon icon="mdi:arrow-left"></div>';
          break;
        default:
          '<div style="text-align:center;"><ha-icon icon="mdi:arrow-all"></div>';
        }
  - name: AWAY
    data: data
    modify: >-
      '<div><img src="' + x.awayTeamLogoSvg + '"
      style="height:
      20px;vertical-align:middle;">&nbsp;' +
      x.awayTeamName + '</div>'
  - name: GOALIE
    data: data
    modify: x.awayGoalieName
  - name: RANK
    data: data
    modify: >-
      if(x.awayGoaliePositionRank == null
      ){'N/A'}else{x.awayGoaliePositionRank}
  - name: W
    data: data
    modify:  >-
      if(x.awayGoalieWins === null
      ){'N/A'}else{x.awayGoalieWins}
  - name: L
    data: data
    modify: >-
      if(x.awayGoalieLosses === null
      ){'N/A'}else{x.awayGoalieLosses}
  - name: OTL
    data: data
    modify: >-
      if(x.awayGoalieOvertimeLosses === null
      ){'N/A'}else{x.awayGoalieOvertimeLosses}
  - name: SO
    data: data
    modify: >-
      if(x.awayGoalieShutouts === null
      ){'N/A'}else{x.awayGoalieShutouts}
  - name: SVP
    data: data
    modify: Number(x.awayGoalieSavePercentage).toFixed(3)
  - name: GAA
    data: data
    modify: Number(x.awayGoalieGoalsAgainstAvg).toFixed(2)

Thank you so much :blush:

A nother question. Do you make the something with playoff seeds?
Like you write in this post:

Not yet. I was working on extracting full NHL hockey fantasy stats for leagues. Or possibly like you wanted … a player tracker that just gives me the stats for players.

I am reviewing Yahoo Sports as their APIs are well documented. I might b able to just get the PLayoff seeding from there (or a scrape). Probably a few weeks before I can get to those tasks.

I should note that the ESPN data does have SEED in it, but it is not correct. It is merely done by conference and does not account for NHL-style (top 3 teams in each Division and then the two best of the remaining in the Conference).

UPDATE: Just you caused me to look, I found out the method to get wildcard team data. So now it is a matter of creating a wildcard sensor and a few other things. I will try to do this later today. This is the link that would deliver just wildcard teams (top two are the current ones, the remainder are currently out of contention). This would need to be combined with top three in each division to give the current picture for Wildcard.

https://site.web.api.espn.com/apis/v2/sports/hockey/nhl/standings?region=us&lang=en&contentorigin=espn&type=3&level=2&sort=playoffseed%3Aasc%2Cpoints%3Adesc%2Cgamesplayed%3Aasc%2Crotwins%3Adesc&seasontype=2

that sounds really good.