Sports Standings and Scores

@DhananjayRamachandra Welcome.

I’ll try to add some of my thoughts but others hopefully will chime in.

Here’s a quick overview:

  1. Almost all of the data in this thread comes from ESPN API endpoints (some data are pulled from other sites, but the bulk is ESPN. There are different ways to call the ESPN API (pre-season, post, etc.) and some of those are addressed in my github page as well as other github pages.
  2. The Data (either through REST or Python Scripts) pulls data from ESPN and stores them in sensors.
  3. ESPN Shuts the API’s down, this thread shuts down. So we are all incredibly thankful for ESPN providing the Data.
  4. For the dashboard builds we use a couple of add-ins that we customize: TeamTracker, Flex-Table, and Card-Mod. So make sure that they are installed.
  5. Dashboards use the data in the sensors and we customize team-tracker and flex-table with card-mod and additional customization/templates.
  6. In the dashboards we mostly use the decluttering-template because of the nature of repetitive calls (leagues/conferences/etc.)

A couple places that we try to discuss what we are doing, provide details pieces of the build including yamls (I split my sports sensors into different yamls), templates, dashboards we are using, python scripts, etc.
@kbrown01 github site - GitHub - kbrown01/SportStandingsScores: Sports Standings and Scores Sensors and Dashboard for Home Assistant
@bburwell (my) github site - GitHub - bburwell/HA-Sports-Scores: Home Assistant Sports Scores, Standings, Dashboards and Yaml's for Home Assistant

In the end have fun and create dashboards (you can always delete) and look at the logs :wink:

Bob - Sorry for not getting back to youu sooner, I’ve been traveling and am just now getting back to this.

I have the python files in a python_scripts directory and they seem to work fine and the .json files in my www directory and they populate using an automation. But what I do not see are the gpt sensors. And I have no idea why they aren’t being created because the sensors in the beginning of the yaml file are being created. Somewhere I’m missing something and just need to work through it. I’m overlooking something, just not sure what it is.

Great - sounds like you are close. When the python script runs it creates a .json file which it sounds like you have. Think of this file like an ESPN endpoint that we have used for other sports/statistics. We have to get that json file data into a sensor.

For each sport I break them out into their own sensor yaml file. For example MLB it has its own mlb_sensors.yaml file in the sensors subdirectory.

You will see a couple examples in there of how data gets put into the sensors that we name.

I would always make sure to go through the developers tab and the logs - here is an example in tools:

So for python script data you will see that the json files are grabbed locally like this (you can see the local IP address in the resource):

- platform: rest
  name: MLB AL Wild Card gpt
  unique_id: sensor.mlb_al_wild_card_gpt
  resource:  http://192.168.xxx.xxx:8123/local/mlb_al_wild_card_gpt.json
  value_template: "{{ now()}}"  
  json_attributes: 
   - events
   - series

If I am pulling them from a website it would look like this:

######################## Post Season Playoffs 
- platform: rest
  scan_interval: 604800
  name: MLB Playoffs WorldSeries
  unique_id: sensor.mlb_playoffs_worldseries
  #2024 Dataresource: https://site.api.espn.com/apis/site/v2/sports/baseball/mlb/scoreboard?dates=20241001-20241030
  resource: https://site.api.espn.com/apis/site/v2/sports/baseball/mlb/scoreboard?dates=20250929-20251101
  value_template: "{{ now() }}"
  json_attributes:
      - leagues
      - events

One last thing to check. When you first start out if you create a sensor then change/delete sometimes HA creates the changes as a sensor with a _2. Take a look at my troubleshooting section in github - mostly explains - but feel free to ask. Here is the link to the section: GitHub - bburwell/HA-Sports-Scores: Home Assistant Sports Scores, Standings, Dashboards and Yaml's for Home Assistant

First, I want to thank @bburwell, he has taken what I did originally and made it much better.

Side note: I refactored the Strength or Schedule view from dailyfaceoff.com to not use the plugin route for Flex Table. Posting here the relevant tidbits:

The sensor (uses multiscrape) so an include to multiscrape.yaml in configuration.yaml as::

multiscrape: !include multiscrape.yaml

Then the sensor itself to store the data:

  - name: SOS scraper
    resource_template: "https://www.dailyfaceoff.com/nhl-weekly-schedule/{{ (now().timestamp()+(0-now().weekday())*86400) | int | timestamp_custom('%Y-%m-%d') }}"
    scan_interval: 3600
    sensor:
      - unique_id: hockey_strength_of_schedule
        name: Hockey Strength of Schedule
        select: '#__NEXT_DATA__'
        value_template: '{{ now() }}'
        attributes:
          - name: sos
            select: '#__NEXT_DATA__'
            value_template: >
                {{ (value | from_json)['props']['pageProps'] }}

Now the decluttering template:

  sos_settings:
    card:
      type: custom:flex-table-card
      title: '[[title]]'
      css:
        table+: 'padding: 0px; width: 100%;'
        tbody tr:hover: 'background-color: lightgreen!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: '[[entity]]'
      sort_by: sos.dataRows-
      columns:
        - name: Games
          data: '[[attribute]]'
          modify: |-
            if (x[8] > 3 ){
                '<div style="display:none;">'+ x[8] + '</div>' + '<div style="background-color:lightgreen;text-align:center">' + x[8] + '</div>'; }
            else if (x[8] == 3) {
                '<div style="display:none;">'+ x[8] + '</div>' + '<div style="background-color:orange;text-align:center"">' + x[8] + '</div>'; }
            else {
                '<div style="display:none;">'+ x[8] + '</div>' + '<div style="background-color:red;color:white;text-align:center">' + x[8] +'</div>'}
        - name: Team
          data: '[[attribute]]'
          modify: >-
            '<div><img src="' + x[0].team.logo + '"
            style="height:20px;vertical-align:middle;">&nbsp;' + x[0].team.name
            + '&nbsp;' + '(' + x[0].team.wins + '-' + x[0].team.losses + '-' +
            x[0].team.overtimeLosses + ')' +'</div>'
        - name: Mon
          data: '[[attribute]]'
          modify: |-
            if (x[1] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[1].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[1].home == true ? "" : "@&nbsp;") + x[1].team.abbreviation + '&nbsp;' + '(' + x[1].team.wins + '-' + x[1].team.losses + '-' + x[1].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[1].home == true ? "" : "@&nbsp;") + x[1].team.abbreviation + '&nbsp;' + '(' + x[1].team.wins + '-' + x[1].team.losses + '-' + x[1].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Tues
          data: '[[attribute]]'
          modify: |-
            if (x[2] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[2].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[2].home == true ? "" : "@&nbsp;") + x[2].team.abbreviation + '&nbsp;' + '(' + x[2].team.wins + '-' + x[2].team.losses + '-' + x[2].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[2].home == true ? "" : "@&nbsp;") + x[2].team.abbreviation + '&nbsp;' + '(' + x[2].team.wins + '-' + x[2].team.losses + '-' + x[2].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Wed
          data: '[[attribute]]'
          modify: |-
            if (x[3] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[3].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[3].home == true ? "" : "@&nbsp;") + x[3].team.abbreviation + '&nbsp;' + '(' + x[3].team.wins + '-' + x[3].team.losses + '-' + x[3].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[3].home == true ? "" : "@&nbsp;") + x[3].team.abbreviation + '&nbsp;' + '(' + x[3].team.wins + '-' + x[3].team.losses + '-' + x[3].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Thur
          data: '[[attribute]]'
          modify: |-
            if (x[4] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[4].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[4].home == true ? "" : "@&nbsp;") + x[4].team.abbreviation + '&nbsp;' + '(' + x[4].team.wins + '-' + x[4].team.losses + '-' + x[4].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[4].home == true ? "" : "@&nbsp;") + x[4].team.abbreviation + '&nbsp;' + '(' + x[4].team.wins + '-' + x[4].team.losses + '-' + x[4].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Fri
          data: '[[attribute]]'
          modify: |-
            if (x[5] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[5].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[5].home == true ? "" : "@&nbsp;") + x[5].team.abbreviation + '&nbsp;' + '(' + x[5].team.wins + '-' + x[5].team.losses + '-' + x[5].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[5].home == true ? "" : "@&nbsp;") + x[5].team.abbreviation + '&nbsp;' + '(' + x[5].team.wins + '-' + x[5].team.losses + '-' + x[5].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Sat
          data: '[[attribute]]'
          modify: |-
            if (x[6] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[6].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[6].home == true ? "" : "@&nbsp;") + x[6].team.abbreviation + '&nbsp;' + '(' + x[6].team.wins + '-' + x[6].team.losses + '-' + x[6].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[6].home == true ? "" : "@&nbsp;") + x[6].team.abbreviation + '&nbsp;' + '(' + x[6].team.wins + '-' + x[6].team.losses + '-' + x[6].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Sun
          data: '[[attribute]]'
          modify: |-
            if (x[7] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[7].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[7].home == true ? "" : "@&nbsp;") + x[7].team.abbreviation + '&nbsp;' + '(' + x[7].team.wins + '-' + x[7].team.losses + '-' + x[7].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[7].home == true ? "" : "@&nbsp;") + x[7].team.abbreviation + '&nbsp;' + '(' + x[7].team.wins + '-' + x[7].team.losses + '-' + x[7].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Opp Strength
          data: '[[attribute]]'
          modify: x[0].team.strengthOfSchedule.averageOpponentStrength
        - name: Rank
          data: '[[attribute]]'
          modify: x[0].team.strengthOfSchedule.rank

And the result:

Perfect for NHL Fantasy Hockey players to visualize the upcoming week.

So I have been playing with the NCAAF College Bowls. I wanted to try to use Sensors/Template, but like before Template has a problem with size. So I had to go back to using python to make an ESPN call that then separates out All Bowls, Regular Bowls, CFP Playoffs and CFP National Championship into their own json files that I then pull into their respective sensors that I have added to the ncaaf_sensors.yaml file.

Here are the adds to the ncaaf_sensors.yaml file:

###########################NCAAF Bowl Games    
### NCAAF Bowl Games
- platform: rest
  name: NCAAF Regular Bowl Games
  unique_id: sensor.ncaaf_regular_bowl_games
  resource:  http://192.168.xxx.xxx:8123/local/cfb_regular_bowls.json
  value_template: "{{ now()}}"  
  json_attributes: 
   - events   

### CFP Bowl Games
- platform: rest
  name: NCAAF CFP Playoffs Bowl Games
  unique_id: sensor.ncaaf_cfp_playoffs_bowl_games
  resource:  http://192.168.xxx.xxx:8123/local/cfb_cfp_playoffs.json
  value_template: "{{ now()}}"  
  json_attributes: 
   - events
  
### CFP Championship Bowl Game
- platform: rest
  name: NCAAF CFP Championship Bowl Game
  unique_id: sensor.ncaaf_cfp_championship_bowl_game
  resource:  http://192.168.xxx.xxx:8123/local/cfb_championship.json
  value_template: "{{ now()}}"  
  json_attributes: 
   - events

### NCAAF All bowl Games
- platform: rest
  name: NCAAF All Bowl Games
  unique_id: sensor.ncaaf_all_bowl_games
  resource:  http://192.168.xxx.xxx:8123/local/cfb_all_bowls.json
  value_template: "{{ now()}}"  
  json_attributes: 
   - events
  • The Dashboard that I am using is called: Sanbox NCAAF Bowls (with NFL for testing)
    ** I am still working on changes that I will then most likely incorporate into the other playoffs that is why I have the NFL in there for testing. I am also looking at adding bowl logos but that most like will need to be added to the python files. ESPN doesnt populate bowl pngs that I can find. I will eventually put this into the college sports dashboard once I am happy with the decluttering changes - yea I know I called it SANbox :wink:
  • You will need to create an automation because it should update during the games with live data but no way to test yet and last years are finals.
  • The sensors above have also been added to the ncaaf_sensors.yaml on github.
  • I am using expander-card as I do in other areas.
  • You will see all bowl games on the left and then on the right the layout is Regular Bowls, CFP Playoffs and then CFP National Championship.

Here is what last year looks like:

This years bowls haven’t been selected yet so this is what it looks like today:

Please make suggestions, changes and I will try to incorporate when I have time.

I’m having another problem with the output of the overall table.

With this code:

type: grid
cards:
  - type: custom:decluttering-card
    template: nhl_settings
    variables:
      - title: Overall
      - entity: sensor.nhl_*_*
      - attribute: entries
      - excluded_entities:
          - sensor.nhl_starting_goalies
          - sensor.nhl_wildcard_standings
          - binary_sensor.nhl_east_atlantic
          - binary_sensor.nhl_east_metropolitan
          - binary_sensor.nhl_west_central
          - binary_sensor.nhl_west_pacific
          - sensor.nhl_po_games
          - sensor.nhl_po_amer_games
          - sensor.nhl_po_natl_games
          - sensor.nhl_po_amer_wc_games
          - sensor.nhl_po_natl_wc_games
          - sensor.nhl_po_amer_div_games
          - sensor.nhl_po_natl_div_games
          - sensor.nhl_po_amer_leag_games
          - sensor.nhl_po_natl_leag_games
          - sensor.nhl_po_world_game
          - sensor.nhl_po_tv_coverage
          - sensor.nhl_playoff_seeds
          - sensor.nhl_po_team_games
      - sort: x.stats.find(y=>y.shortDisplayName == 'PTS').value
    grid_options:
      columns: full
column_span: 4

I got only a blank site.

With the Conferance Code:

type: grid
cards:
  - type: custom:stack-in-card
    mode: vertical
    cards:
      - type: custom:decluttering-card
        template: nhl_settings
        variables:
          - title: Eastern
          - entity: sensor.nhl_east_*
          - attribute: entries
          - excluded_entities:
              - sensor.nhl_starting_goalies
              - sensor.nhl_wildcard
              - sensor.nhl_wildcard_standings
          - sort: x.stats.find(y=>y.shortDisplayName == 'PTS').value
    grid_options:
      columns: full
column_span: 4

I got the table.

I don´t know what is wrong for the overall table.

Check in template what is returned from this. If it is has entries not listed as excluded that should be, it could lead to errors.

Something like this:

        {%
          set nhl_sensors = states.sensor
          | selectattr('entity_id', 'contains', "nhl_")
          | map(attribute='entity_id')
          | list
        %}
        {{ nhl_sensors }}

For me yields:

[
  "sensor.nhl_wildcard",
  "sensor.nhl_standings",
  "sensor.nhl_east_atlantic",
  "sensor.nhl_east_metropolitan",
  "sensor.nhl_west_central",
  "sensor.nhl_west_pacific",
  "sensor.nhl_wildcard_standings",
  "sensor.nhl_starting_goalies"
]

Now, you may have a different list using @bburwell code with many other sensors, They key is to be sure you exclude what should not be included. It could also be that you have excluded something that does not exist.

Now that said, it is unclear to me what are the binary sensors. They could be but then my code above would need to include them. I do not use binary_sensor, but maybe @bburwell does.

thanks for your quick replay.

with your code I got this list:

 "sensor.nhl_playoff_west_2nd_round_gpt",
  "sensor.nhl_playoff_east_final_gpt",
  "sensor.nhl_playoff_west_final_gpt",
  "sensor.nhl_playoff_east_2nd_round_gpt",
  "sensor.nhl_stanley_cup_final_gpt",
  "sensor.nhl_playoff_east_1st_round",
  "sensor.nhl_playoff_west_1st_round",
  "sensor.nhl_starting_goalies",
  "sensor.nhl_playoff_east_1st_round_gpt",
  "sensor.nhl_playoff_west_1st_round_gpt",
  "sensor.nhl_wildcard",
  "sensor.nhl_standings",
  "sensor.nhl_playoffs_stanleycup",
  "sensor.nhl_east_atlantic",
  "sensor.nhl_east_metropolitan",
  "sensor.nhl_west_central",
  "sensor.nhl_west_pacific",
  "sensor.nhl_wildcard_standings",
  "sensor.nhl_playoff_filtered_events",
  "sensor.nhl_po_games",
  "sensor.nhl_po_amer_games",
  "sensor.nhl_po_natl_games",
  "sensor.nhl_po_amer_wc_games",
  "sensor.nhl_po_natl_wc_games",
  "sensor.nhl_po_amer_div_games",
  "sensor.nhl_po_natl_div_games",
  "sensor.nhl_po_amer_leag_games",
  "sensor.nhl_po_natl_leag_games",
  "sensor.nhl_po_world_game",
  "sensor.nhl_po_tv_coverage",
  "sensor.nhl_playoff_seeds",
  "sensor.nhl_po_team_games"

Now I have changes my code for the overall like this:

type: grid
cards:
  - type: custom:decluttering-card
    template: nhl_settings
    variables:
      - title: Overall
      - entity: sensor.nhl_*_*
      - attribute: entries
      - excluded_entities:
          - sensor.nhl_starting_goalies
          - sensor.nhl_wildcard_standings
          - binary_sensor.nhl_east_atlantic
          - binary_sensor.nhl_east_metropolitan
          - binary_sensor.nhl_west_central
          - binary_sensor.nhl_west_pacific
          - sensor.nhl_po_games
          - sensor.nhl_po_amer_games
          - sensor.nhl_po_natl_games
          - sensor.nhl_po_amer_wc_games
          - sensor.nhl_po_natl_wc_games
          - sensor.nhl_po_amer_div_games
          - sensor.nhl_po_natl_div_games
          - sensor.nhl_po_amer_leag_games
          - sensor.nhl_po_natl_leag_games
          - sensor.nhl_po_world_game
          - sensor.nhl_po_tv_coverage
          - sensor.nhl_playoff_seeds
          - sensor.nhl_po_team_games
          - sensor.nhl_playoff_west_2nd_round_gpt
          - sensor.nhl_playoff_east_final_gpt"
          - sensor.nhl_playoff_west_final_gpt
          - sensor.nhl_playoff_east_2nd_round_gpt
          - sensor.nhl_stanley_cup_final_gpt
          - sensor.nhl_playoff_east_1st_round
          - sensor.nhl_playoff_west_1st_round
          - sensor.nhl_starting_goalies
          - sensor.nhl_playoff_east_1st_round_gpt
          - sensor.nhl_playoff_west_1st_round_gpt
          - sensor.nhl_wildcard
          - sensor.nhl_standings
          - sensor.nhl_playoffs_stanleycup
          - sensor.nhl_playoff_filtered_events
          - sensor.nhl_po_games
          - sensor.nhl_po_amer_games
          - sensor.nhl_po_natl_games
          - sensor.nhl_po_amer_wc_games
          - sensor.nhl_po_natl_wc_games
          - sensor.nhl_po_amer_div_games
          - sensor.nhl_po_natl_div_games
          - sensor.nhl_po_amer_leag_games
          - sensor.nhl_po_natl_leag_games
          - sensor.nhl_po_world_game
          - sensor.nhl_po_tv_coverage
          - sensor.nhl_playoff_seeds
          - sensor.nhl_po_team_games
      - sort: x.stats.find(y=>y.shortDisplayName == 'PTS').value
    grid_options:
      columns: full
column_span: 4

But I also got with this code the blank site.

EDIT:
I don´t know where the binary sensors from.

When I look at it they are unavailable.

Those are listed as “binary_sensor” not “sensor”.

In the list of sensors returned, they are just sensor, Try changing those 4 to “sensor” as they exist.

Yes I know there are binary_sensors. But I don’t know where they come from.

Where I must changing those 4 to “sensor”

Have you any idea, how to fix my overall table?

EDIT:
I got it. I think I forgot an exclude.

This Code works:

type: grid
cards:
  - type: custom:decluttering-card
    template: nhl_settings
    variables:
      - title: Overall
      - entity: sensor.nhl_*_*
      - attribute: entries
      - excluded_entities:
          - sensor.nhl_playoff_west_2nd_round_gpt
          - sensor.nhl_playoff_east_final_gpt
          - sensor.nhl_playoff_west_final_gpt
          - sensor.nhl_playoff_east_2nd_round_gpt
          - sensor.nhl_stanley_cup_final_gpt
          - sensor.nhl_playoff_east_1st_round
          - sensor.nhl_playoff_west_1st_round
          - sensor.nhl_starting_goalies
          - sensor.nhl_playoff_east_1st_round_gpt
          - sensor.nhl_playoff_west_1st_round_gpt
          - sensor.nhl_wildcard
          - sensor.nhl_standings
          - sensor.nhl_playoffs_stanleycup
          - sensor.nhl_wildcard_standings
          - sensor.nhl_playoff_filtered_events
          - sensor.nhl_po_games
          - sensor.nhl_po_amer_games
          - sensor.nhl_po_natl_games
          - sensor.nhl_po_amer_wc_games
          - sensor.nhl_po_natl_wc_games
          - sensor.nhl_po_amer_div_games
          - sensor.nhl_po_natl_div_games
          - sensor.nhl_po_amer_leag_games
          - sensor.nhl_po_natl_leag_games
          - sensor.nhl_po_world_game
          - sensor.nhl_po_tv_coverage
          - sensor.nhl_playoff_seeds
          - sensor.nhl_po_team_games
      - sort: x.stats.find(y=>y.shortDisplayName == 'PTS').value
    grid_options:
      columns: full
column_span: 4

Thank you so much

I do not use binary sensors for sports

It looks like the CFP Playoffs and Bowl Games for 2025-2026 are starting to populate. I have updated the Sandbox NCAAF Bowls on my github.

In the decluttering template I have 2 templates - sports_playoffs and sports_playoffsv2. I am working to have the v2 display more information especially during live bowls - but still a work in progress. You can see from this image sports_playoff on the left and sports_playoffv2 on the right. Not alot to see yet but will update as bowls start to be played.

You can change to either one by changing the template being called. Heres a section that you can see where in my Sandbox - CFP dashboard. template: sports_playoffs or sports_playoffsv2

- type: custom:expander-card
                                        child-margin-top: 0.6em
                                        padding: 0
                                        title: CFP Playoff Bowl Games
                                        title-card-button-overlay: true
                                        title-card-clickable: true
                                        expanded: false
                                        cards:
                                          - type: custom:decluttering-card
                                            template: sports_playoffsv2
                                            variables:
                                              - title: CFP Playoff Bowl Games
                                              - color: '#FFD700'
                                              - entity: sensor.ncaaf_cfp_playoffs_bowl_games
                                              - events: events
                                              - show_rankings: true
                                              - show_series: false

Also the CFP playoff teams are populated as well:

Bro, I love this! but I can’t get it to work. I created the sensor in multiscrape exactly as you indicated (I can see all the info in atrributes already):

- name: SOS scraper
  resource_template: "https://www.dailyfaceoff.com/nhl-weekly-schedule/{{ (now().timestamp()+(0-now().weekday())*86400) | int | timestamp_custom('%Y-%m-%d') }}"
  scan_interval: 3600
  sensor:
    - unique_id: hockey_strength_of_schedule
      name: Hockey Strength of Schedule
      select: '#__NEXT_DATA__'
      value_template: '{{ now() }}'
      attributes:
        - name: sos
          select: '#__NEXT_DATA__'
          value_template: >
            {{ (value | from_json)['props']['pageProps'] }}

And I changed '[[entity]]' to the name of the created sensor sensor.hockey_strength_of_schedule

entities:
        include: '[[entity]]'

In addition to changing all the '[[attribute]]' to the attribute sos in all the lines data: '[[attribute]]' Do you know what I might be doing wrong?

You should post the code that is not working instead of a list of items you ‘think’ you changed in case you missed some :slight_smile:

Yes, please post the code. The “older” SOS page used to use JS functions I wrote. I did rewrite that later to remove the functions. Possibly that is it.

Yes @anon60850888 / @kbrown01, you’re absolutely right, sorry — here’s the full code. You can find the strength calendar code starting from line 2 and the label card from line 617 decluttering_templates: sos_settings: card: type: custom:flex-tab - Pastebin.com"

My decluttering is:

  sos_settings:
    card:
      type: custom:flex-table-card
      title: '[[title]]'
      css:
        table+: 'padding: 0px; width: 100%;'
        tbody tr:hover: 'background-color: lightgreen!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: '[[entity]]'
      sort_by: sos.dataRows-
      columns:
        - name: Games
          data: '[[attribute]]'
          modify: |-
            if (x[8] > 3 ){
                '<div style="display:none;">'+ x[8] + '</div>' + '<div style="background-color:lightgreen;text-align:center">' + x[8] + '</div>'; }
            else if (x[8] == 3) {
                '<div style="display:none;">'+ x[8] + '</div>' + '<div style="background-color:orange;text-align:center"">' + x[8] + '</div>'; }
            else {
                '<div style="display:none;">'+ x[8] + '</div>' + '<div style="background-color:red;color:white;text-align:center">' + x[8] +'</div>'}
        - name: Team
          data: '[[attribute]]'
          modify: >-
            '<div><img src="' + x[0].team.logo + '"
            style="height:20px;vertical-align:middle;">&nbsp;' + x[0].team.name
            + '&nbsp;' + '(' + x[0].team.wins + '-' + x[0].team.losses + '-' +
            x[0].team.overtimeLosses + ')' +'</div>'
        - name: Mon
          data: '[[attribute]]'
          modify: |-
            if (x[1] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[1].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[1].home == true ? "" : "@&nbsp;") + x[1].team.abbreviation + '&nbsp;' + '(' + x[1].team.wins + '-' + x[1].team.losses + '-' + x[1].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[1].home == true ? "" : "@&nbsp;") + x[1].team.abbreviation + '&nbsp;' + '(' + x[1].team.wins + '-' + x[1].team.losses + '-' + x[1].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Tues
          data: '[[attribute]]'
          modify: |-
            if (x[2] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[2].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[2].home == true ? "" : "@&nbsp;") + x[2].team.abbreviation + '&nbsp;' + '(' + x[2].team.wins + '-' + x[2].team.losses + '-' + x[2].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[2].home == true ? "" : "@&nbsp;") + x[2].team.abbreviation + '&nbsp;' + '(' + x[2].team.wins + '-' + x[2].team.losses + '-' + x[2].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Wed
          data: '[[attribute]]'
          modify: |-
            if (x[3] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[3].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[3].home == true ? "" : "@&nbsp;") + x[3].team.abbreviation + '&nbsp;' + '(' + x[3].team.wins + '-' + x[3].team.losses + '-' + x[3].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[3].home == true ? "" : "@&nbsp;") + x[3].team.abbreviation + '&nbsp;' + '(' + x[3].team.wins + '-' + x[3].team.losses + '-' + x[3].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Thur
          data: '[[attribute]]'
          modify: |-
            if (x[4] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[4].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[4].home == true ? "" : "@&nbsp;") + x[4].team.abbreviation + '&nbsp;' + '(' + x[4].team.wins + '-' + x[4].team.losses + '-' + x[4].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[4].home == true ? "" : "@&nbsp;") + x[4].team.abbreviation + '&nbsp;' + '(' + x[4].team.wins + '-' + x[4].team.losses + '-' + x[4].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Fri
          data: '[[attribute]]'
          modify: |-
            if (x[5] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[5].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[5].home == true ? "" : "@&nbsp;") + x[5].team.abbreviation + '&nbsp;' + '(' + x[5].team.wins + '-' + x[5].team.losses + '-' + x[5].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[5].home == true ? "" : "@&nbsp;") + x[5].team.abbreviation + '&nbsp;' + '(' + x[5].team.wins + '-' + x[5].team.losses + '-' + x[5].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Sat
          data: '[[attribute]]'
          modify: |-
            if (x[6] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[6].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[6].home == true ? "" : "@&nbsp;") + x[6].team.abbreviation + '&nbsp;' + '(' + x[6].team.wins + '-' + x[6].team.losses + '-' + x[6].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[6].home == true ? "" : "@&nbsp;") + x[6].team.abbreviation + '&nbsp;' + '(' + x[6].team.wins + '-' + x[6].team.losses + '-' + x[6].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Sun
          data: '[[attribute]]'
          modify: |-
            if (x[7] === null ){
              ''
            } else {
              if (x[0].team.strengthOfSchedule.strength > x[7].team.strengthOfSchedule.strength){
                '<div style="background-color:lightcoral;text-align:center">' + (x[7].home == true ? "" : "@&nbsp;") + x[7].team.abbreviation + '&nbsp;' + '(' + x[7].team.wins + '-' + x[7].team.losses + '-' + x[7].team.overtimeLosses + ')' + '</div>'
              } else {
                '<div style="background-color:lightgreen;text-align:center">' + (x[7].home == true ? "" : "@&nbsp;") + x[7].team.abbreviation + '&nbsp;' + '(' + x[7].team.wins + '-' + x[7].team.losses + '-' + x[7].team.overtimeLosses + ')' + '</div>'
              }
            }
        - name: Opp Strength
          data: '[[attribute]]'
          modify: x[0].team.strengthOfSchedule.averageOpponentStrength
        - name: Rank
          data: '[[attribute]]'
          modify: x[0].team.strengthOfSchedule.rank

which gives:

I’m not sure if this is the best place to post this, but I’ve not been able to find the answer on any other discussion boards. The rest sensor, resource: http://192.168.xxx.xxx:8123/local/somefile.json, does not create the sensor nor populate it. The rest sensor that uses the espn link works fine, it’s just the local call that I’m having the problem with. I have tried everyway I can think of to get this to work including disabling duckdns, adblock, and nginx with no luck. The only log entry I’ve seen related to it said the Rest sensor could not parse the json file, but that has cleared itsalf as well. If anyone has run across this I would appreciate any guidance you might have.

Lubo - the ip should be the IP of your HA system - so something like http://192.168.1.2:8123/local/somefile.json

I am guessing you are trying to use my python file to pull data from ESPN into a json file which is the first part of the process. Here is the logic:

  1. Python file is run and pulls data from ESPN into a json file or json files that are placed in the /config/www directory.
  2. Then I setup RESTful sensors to grab the data in the json files and put them into the sensor. I do this for a couple reasons. Primarily because Home Assistant Templates have size issues and can only hold so much data before they fail/break. Other is that I want to organize the data - eg. All NCAAF bowls in a sensor, non-cfp bowl games, CFP bowl games, etc… Here is an example of the NCAAF Bowl Game Sensor I have: `### NCAAF Bowl Games
  1. I put 192.168.xxx.xxx - so that you can put your own HA IP number in there and not run into problems using mine. I am old so I use IP’s but you could probably use the DNS name if that is configured in your house.

Correct, I’m using the same code after decluttering_templates: and in the tab where I add the card I use the following:

                    - attributes:
                        label: Calendar
                        icon: mdi:clock-start
                      card:
                        type: custom:decluttering-card
                        template: sos_settings
                        variables:
                          - title: Calendar
                          - attribute: sos
                          - entity: sensor.hockey_strength_of_schedule

I get the titles but not the information, I don’t know if I might have something wrong in the card code.