Sports Standings and Scores

Do you have anything else in mind towards the playoff tree?

Something like that:

1 Like

Yes, you would need to implement custom Javascript since a mobile device is touch or possibly it could be done in CSS pure by using :hover and :active.

I do not think I can do it this year. I will be out of country for next few weeks.
I did a brief check and it looks like the data would be available here:

https://site.web.api.espn.com/apis/v2/sports/hockey/nhl/standings?seasontype=3&type=0&level=1

seasontype = 3 is playoffs
level = 1 is overall standings

However, there is no data right now because it has not started so itā€™s hard to know what will be in there.
Or possibly it could just be extracted from teamtracker although it may not have what I would think we would want ā€¦ like the current head-to-head standings (Tampa leads Toronto 2 - 1).

Once things get started I can take a look and possibly have something before the end.

Another option may be using scrape and getting this data. I like this presentation and we could make it much prettier with logos and such.

Iā€™m not sure what you mean exactly. What should I do exactly?

Ok I understand. Then weā€™ll have to wait and see.

@kbrown01 it looks like ESPN changed their data a little bit. both NFL and MLB the standings donā€™t match the headings. Iā€™m seeing the win percentage in the wins column, streak in the ties column, and a few other oddities with the data being displayed.

I will have to look at it when I get back from Europe.

At the Moment I get this Warnings in the logs:

State attributes for sensor.nhl_west_central exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored
State attributes for sensor.nhl_wildcard_standings exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored
State attributes for sensor.nhl_east_metropolitan exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored
State attributes for sensor.nhl_west_pacific exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored
State attributes for sensor.nhl_east_atlantic exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored

I have big problems at the moment with my homeassistant. Maybe it has to do with the warnings

Those warnings are HA saying the data in the entity and attributes is much bigger than expected and not all of it will be saved to the database, only a portion. It also tells you that trying to save and recall that much data from the database can cause performance issues.

Honestly, thereā€™s no reason to keep the historical data of these sensors so exclude them from your recorder and restart HA.

How can I exclude the historical data from record?

But my database is external on a server, so must I exclude it? So is there an performance issue?

you exclude it through configuration of the recorder integration. My database is external too. I did not notice any performance issues.

So I must not exclude the historical?

Sorry for the delay, I have been on vacation. Replace the NFL and MLB templates in your decluttering_templates with these:

  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
  nfl_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: 6%;'
        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;
             }
      sort_by: entries-
      entities:
        include: '[[entity]]'
      columns:
        - hidden: true
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'PCT').value.toFixed(2)
        - 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 == 'L').value + x.stats.find(y=>y.abbreviation == 'W').value + x.stats.find(y=>y.abbreviation == 'T').value
        - name: W
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'W').value
        - name: L
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'L').value
        - name: T
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'T').value
        - name: PCT
          data: entries
          modify: x.stats.find(y=>y.abbreviation == 'PCT').value.toFixed(2)
        - name: HOME
          data: entries
          modify: x.stats.find(y=>y.shortDisplayName == 'HOME').displayValue
        - name: AWAY
          data: entries
          modify: x.stats.find(y=>y.shortDisplayName == 'AWAY').displayValue
        - name: DIV
          data: entries
          modify: x.stats.find(y=>y.shortDisplayName == 'DIV').displayValue
        - name: CONF
          data: entries
          modify: x.stats.find(y=>y.shortDisplayName == 'CONF').displayValue
        - name: PF
          data: entries
          modify: x.stats.find(y=>y.shortDisplayName == 'PF').displayValue
        - name: PA
          data: entries
          modify: x.stats.find(y=>y.shortDisplayName == 'PA').displayValue
        - name: DIFF
          data: entries
          modify: x.stats.find(y=>y.shortDisplayName == 'DIFF').displayValue
        - name: STRK
          data: entries
          modify: x.stats.find(y=>y.shortDisplayName == 'STRK').displayValue

This fixes the MLB and NFL standings.
I have not yet implemented the tooltip for these but will do so in a bit.

2 Likes

Yep, that fixes those sports. Thanks! and no worries on the delay. this is minor compared to a vacation.

I think since the playoffs only errors are displayed for starting goalies:

Can this still be fixed, or is there nothing left in the playoffs?

@compoundbow83 ā€¦ The website changed the key value in the URL. I just changed my sensor to this and restarted:

- platform: rest
  name: nhl_starting_goalies
  unique_id: sensor.nhl_starting_goalies
  scan_interval: 3600
  resource: https://www.dailyfaceoff.com/_next/data/I2SkdVYELbkzO4_ZY9rw8/starting-goalies.json
  value_template: "{{ value_json.pageProps.date }}"
  json_attributes_path: "$.pageProps"
  json_attributes:
    - data

and it gets the data now:

Now that I am back before end of playoffs I will look for a way to try and obtain that link properly. It is the source system where the JSON is obtained changes the ā€œI2SkdVYELbkzO4_ZY9rw8ā€ key every so often and it is unclear where that can be obtained.

Note in the sensor above I added the unique_id. This will avoid HA creating duplicate sensors with ā€œ_2ā€ at the end.

By the way, this is how I get this information so if you get that in the future you can do the same:

  1. Surf your browser to Starting Goalies - 2023-05-04 - Daily Faceoff
  2. Open up the developer tab and select the network
  3. in the search box enter starting-goalies.json
  4. refresh
  5. right click and copy the link address
  6. use this link in your sensor

1 Like

Thank you for the fast fix

Changed again:

https://www.dailyfaceoff.com/_next/data/5YkqpzlRN6hS5J3CvBaJb/starting-goalies.json

1 Like

And the next one:
https://www.dailyfaceoff.com/_next/data/KN4hBpt_cfILOG1wLIrf_/starting-goalies.json

1 Like

LOL. I did find that in the main page I can find the string. WHat I am trying to do now is to set up a scrape sensor that can scrape the page and get the value into a sensor, then we can have two sensors ā€“ one that stores the key triggered likely once a day and then one that uses the value (state) of that sensor to get the JSON.

I need to ā€œphone a friendā€ as he is expert on scraping for his help.

And so it seems to work.

I set up a scrape sensor in YAML like this:

In configuration.yaml:

scrape: !include scrape.yaml

In scrape.yaml:

  - resource: https://www.dailyfaceoff.com/starting-goalies
    sensor:
      - name: Starting Goalie BuildID
        unique_id: sensor.starting_goalie_buildid
        select: '#__NEXT_DATA__'
        value_template: >
            {{ value | regex_findall('buildId":\s?"([a-zA-Z0-9_-]{1,99})"') | first }}

This yields a sensor like this:

Now on to put this together. So I changed the sensor for starting goalies to use this value. NOTE: THis may take a few reboots after it is all finished to get the sensor to use the resource_template.

##
## Starting Goalies
##
- platform: rest
  name: nhl_starting_goalies
  unique_id: sensor.nhl_starting_goalies
  scan_interval: 3600
  resource_template: >
    https://www.dailyfaceoff.com/_next/data/{{states('sensor.starting_goalie_buildid')}}/starting-goalies.json
  value_template: "{{ value_json.pageProps.date }}"
  json_attributes_path: "$.pageProps"
  json_attributes:
    - data

So hopefully for now and in the future, the ā€œbuildIdā€ is read in a scrape sensor from the main page and then used to select the JSON file that displays the starting goalies.

NOTE: Right now as written this will extract the ā€œbuildIdā€ from the web page for characters 0-9, A-Z, a-z and _ ā€¦ if we find it can contain other characters like +,- and such, we may need to tweak that regex command