Thank you so much
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.
that sounds really good.
I would like to take this opportunity to thank you for your great work here.
Thank you!
I have successfully created a sensor that yields all the Wildcard information for the NHL. I am going to put the sensors in here. I am going to be out on a trip and not sure I will have time to work on this for a week. But you could learn by the examples of how the whole solution works and attempt to plug it in. I just may not be responsive to questions for a bit.
IMPORTANT NOTE: I chose to call it nhl_wildcard so if you use this, you will need to eliminate that entity in the same way as nhl_starting_goalies was done. Otherwise, you can select a different name.
as in:
entities:
include: '[[entity]]'
exclude:
- sensor.nhl_starting_goalies
- sensor.nhl_wildcard
- sensor.nhl_wildcard_standings
When I get back after a few weeks, I am going to standardize this better and use variables to pass in both the includes and excludes.
The sensor that gets data from the ESPN web API is as follows. It is a REST sensor that is just like the other REST sensors except it grabs two attributes. One contains the top three teams in each Division, the other has all the remainder teams in Wildcard order.
##
## NHL Wildcard
##
- platform: rest
scan_interval: 36000
name: NHL Wildcard
unique_id: sensor.nhl_wildcard
resource: 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
value_template: "{{ now() }}"
json_attributes:
- children
- overall
Now the second sensor is a template sensor that beaks these out into 6 attributes. Top three for each division plus the wildcard for each conference.
###
### NHL Wildcard
###
- name: NHL Wildcard Standings
unique_id: sensor.nhl_wildcard_standings
state: "{{ now() }}"
attributes:
east_atlantic_top: "{{ state_attr('sensor.nhl_wildcard','overall')[0]['children'][0]['standings']['entries'] }}"
east_metropolitan_top: "{{ state_attr('sensor.nhl_wildcard','overall')[0]['children'][1]['standings']['entries'] }}"
east_wildcard: "{{ state_attr('sensor.nhl_wildcard','children')[0]['standings']['entries'] }}"
west_central_top: "{{ state_attr('sensor.nhl_wildcard','overall')[1]['children'][0]['standings']['entries'] }}"
west_pacific_top: "{{ state_attr('sensor.nhl_wildcard','overall')[1]['children'][1]['standings']['entries'] }}"
west_wildcard: "{{ state_attr('sensor.nhl_wildcard','children')[1]['standings']['entries'] }}"
This second sensor can be used not to create flex tables in the exact same manner as the others as the fields inside are the same. The only changes would be getting the right attribute for the right table but the names are obvious.
The second sensor has all the information to be able to draw this as done in ESPN web site:
That looks good. Iām still curious about the code for the output
if s.o is interested in German Bundesliga Standing here my config:
config configuration.yaml
- platform: rest
scan_interval: 36000
name: Bundesliga Standing
unique_id: sensor.bundesliga_standing
resource: https://site.web.api.espn.com/apis/v2/sports/soccer/ger.1/standings
value_template: "{{ now() }}"
json_attributes:
- children
template:
- sensor:
- name: soccer_german_bundesliga
state: 'standing'
attributes:
standings: >-
{{ state_attr('sensor.bundesliga_standing','children')[0].standings.entries }}
card config:
custom:flex-table-card needed!
type: custom:flex-table-card
title: Standings
css:
table+: 'padding: 0px; width: 100%;'
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;
}
sort_by: entries-
entities:
include: sensor.soccer_german_bundesliga
columns:
- name: P.
data: standings
modify: |
x.stats[10].displayValue
- name: Team
data: standings
modify: "'<div><img src=\"' + x.team.logos[0].href + '\" style=\"height: 20px;vertical-align:middle;\"> ' + x.team.displayName + '</div>'"
- name: G
data: standings
modify: |
x.stats[0].displayValue
- name: DIFF
data: standings
modify: |
x.stats[8].displayValue
- name: Pts.
data: standings
modify: |
x.stats[2].displayValue
Result:
I completed a overhaul of the solution and will post tonight an update to GITHUB. This includes handling NHL Wildcard:
I would note that ESPN also slightly modified the data. They now have two fields ā āAverage Point Differentialā and āGoal Differentialā that use the same field name. The GUI shows the average point differential as the goal differential is easy since it is āGF - GAā
UPDATE
Changed files are posted to GITHUB. This adds the Wildcard sensors for NHL and also starting goalies. However, as stated in previous thread the starting goalies will need to change as the data source URL now changes daily.
NOTE: There are changes also in the decluttering template for NHL to pass in a list of ignored entities because of naming conventions. You should replace all the entire NHL tab or examine how variables are passed to ensure a functional panel.
By the way, the website changed the link and it broke starting goalies. I may need to think through how best to get the data such that it does not break. You can change the sensor for the new link for now:
- platform: rest
name: nhl_starting_goalies
scan_interval: 3600
resource: https://www.dailyfaceoff.com/_next/data/hIErXNiLxFhcIi3lzX7SH/starting-goalies.json
value_template: "{{ value_json.pageProps.date }}"
json_attributes_path: "$.pageProps"
json_attributes:
- data
It appears as if this now changes daily. I will need to examine alternate methods to do this or understand how that key can be found.
Is it possible to clean up the Wildcard tab and sensor even more by separating or removing the teams that have already been eliminated (denoted by an āeā in the Clinch column)? That way only the teams actually in the wildcard hunt are shown. But then take that a step further and show the current wildcard spot holders and another section labeled āIn The Huntā which shows all the remaining teams not yet eliminated? Not sure if itās possible with how the data comes from ESPN, or if itās just display and styling adjustments.
Currently if you look at the sensor, I organized the data as:
- Top three in each division
- Rest in order for each conference
I was trying to get the 1,2,3 numbering scheme of each one, but time was limited and I wanted to get this out to folks.
I think that it is totally possible to eliminate the āeā 's and changing the labels is all in the code for the dashboard YAML. Let me see what I can do on that one.
How good are you at modifying things? Comfortable with or ?
In looking at the sensor as it is, one would need to bust the Wildcard into 3 groups.
- Top 2 = Current Wildcard
- Next ones without an āeā = In the Hunt
- āeā 's = Golfing
Splitting 1 to 2+3 is easy, the attribute URL would be:
{{ state_attr('sensor.nhl_wildcard','children')[0]['standings']['entries'][:2] }}
and
{{ state_attr('sensor.nhl_wildcard','children')[0]['standings']['entries'][3:] }}
Which is give me the top 2 (by adding [:2]
at the end. And 3 to end (by adding [3:]
)
I will need to think through the āeāsā now
In other words, this (without getting rid of eās) gives you a start:
###
### NHL Wildcard
###
- name: NHL Wildcard Standings
unique_id: sensor.nhl_wildcard_standings
state: "{{ now() }}"
attributes:
east_atlantic_top: "{{ state_attr('sensor.nhl_wildcard','overall')[0]['children'][0]['standings']['entries'] }}"
east_metropolitan_top: "{{ state_attr('sensor.nhl_wildcard','overall')[0]['children'][1]['standings']['entries'] }}"
east_wildcard: "{{ state_attr('sensor.nhl_wildcard','children')[0]['standings']['entries'][:2] }}"
east_hunt: "{{ state_attr('sensor.nhl_wildcard','children')[0]['standings']['entries'][3:] }}"
west_central_top: "{{ state_attr('sensor.nhl_wildcard','overall')[1]['children'][0]['standings']['entries'] }}"
west_pacific_top: "{{ state_attr('sensor.nhl_wildcard','overall')[1]['children'][1]['standings']['entries'] }}"
west_wildcard: "{{ state_attr('sensor.nhl_wildcard','children')[1]['standings']['entries'][:2] }}"
west_hunt: "{{ state_attr('sensor.nhl_wildcard','children')[1]['standings']['entries'][3:] }}"
Of course, if you want āIn the Huntā you would need to add those to the dashboard.yaml. I will look in a bit and see if I can separate that into two ā hunt and eliminated.
So I now have this:
Iāll play around with this a bit. Iām fairly comfortable modifying things or running with an idea, but itās the getting started that can be tough for me. Will play around with this some tonight.
Iām glad you got it done so quickly. I have now adopted everything and the TAB wildcard also works in the adopted dashboard.
But I have distributed everything in individual views. But with wildcard something doesnāt work for me and it looks like this:
This is my code:
type: custom:stack-in-card
mode: vertical
cards:
- type: custom:decluttering-card
template: nhl_settings
variables:
- title: Eastern Atlantic
- entity: sensor.nhl_wildcard_standings
- attribute: east_atlantic_top
- excluded_entities:
- sensor.nhl_starting_goalies
- sort: x.stats.find(y=>y.shortDisplayName == 'PTS').value
- type: custom:decluttering-card
template: nhl_settings
variables:
- title: Eastern Metropolitan
- entity: sensor.nhl_wildcard_standings
- attribute: east_metropolitan_top
- excluded_entities:
- sensor.nhl_starting_goalies
- sort: x.stats.find(y=>y.shortDisplayName == 'PTS').value
- type: custom:decluttering-card
template: nhl_settings
variables:
- title: Eastern Wildcard
- entity: sensor.nhl_wildcard_standings
- attribute: east_wildcard
- excluded_entities:
- sensor.nhl_starting_goalies
- sort: x.stats.find(y=>y.shortDisplayName == 'PTS').value
- type: custom:decluttering-card
template: nhl_settings
variables:
- title: Western Central
- entity: sensor.nhl_wildcard_standings
- attribute: west_central_top
- excluded_entities:
- sensor.nhl_starting_goalies
- sort: x.stats.find(y=>y.shortDisplayName == 'PTS').value
- type: custom:decluttering-card
template: nhl_settings
variables:
- title: Western Pacific
- entity: sensor.nhl_wildcard_standings
- attribute: west_pacific_top
- excluded_entities:
- sensor.nhl_starting_goalies
- sort: x.stats.find(y=>y.shortDisplayName == 'PTS').value
- type: custom:decluttering-card
template: nhl_settings
variables:
- title: Western Wildcard
- entity: sensor.nhl_wildcard_standings
- attribute: west_wildcard
- excluded_entities:
- sensor.nhl_starting_goalies
- sort: x.stats.find(y=>y.shortDisplayName == 'PTS').value
What make i wrong?
There are two sensors. A REST sensor.nhl_wiidcard and a template sensor.nhl_wildcard_standings.
Make sure you grabbed the code for both. I will guess you missed the REST one a which gets the raw data and then the template one has no data because itās data comes from the REST one.
Check on developer tab and make sure both sensors exist and have data/attributes
This should be [2:]
otherwise the first team in the hunt (ex. Calgary in the west) gets removed.
I have this working:
For removing eliminated teams, can we look at the clinch column value and if thereās an āeā for a value, donāt display that row of data? Or look at the value and if it does contain an āeā place those in a separate section at the bottom under āOut Of The Playoffsā or just āEliminatedā
The other thing I was thinking of which might help the other sports too is have a secondary sort. For NHL points are first, but if two teams are tied in points, tiebreaker goes to the team with fewer games played (higher points percentage), then the most Regulation wins (RW column), then the most Regulation and Overtime wins excluding shootouts (ROW column). EDIT: This I think is actually handled by the ESPN data, so disregard this request.
Iād love to be able to click on a column header and sort by that, but I think thatās beyond YAML capability and more HTML or CSS.
Great pickup, thanks.
On sorting ā¦ you can do that by sorting in flex-table using multiple columns. i.e:
sort_by: [battery+, name-]
would pass in a list (guessing here, untested and not complete):
- sort: [x.stats.find(y=>y.shortDisplayName == 'PTS').value, x.stats.find(y=>y.abbreviation == 'RW').displayValue]
I would note that the data is already sorted that way from ESPN ā¦ however ā¦ you may want to implemented multi-sort in other ones like āOverallā.
I am looking today at how to do the āeā .
UPDATE:
I am close to being able to split the hunt into two, those eliminated and those āstill in the huntā. I will add attributes for these as hunt and eliminated. You can then chose if you want just the hunt or whether you wish a full view including the eliminated.
It is like this and based on the fact that clincher only exists in the āeā teams. It does not in the āhuntā teams.
{% set eteams = namespace(eteam=[]) %}
{% for team in state_attr('sensor.nhl_wildcard','children')[0]['standings']['entries'][2:] %}
{% for stat in team['stats'] %}
{% if stat.name == 'clincher' %}
{% set eteams.eteam = eteams.eteam + [team] %}
{% endif %}
{% endfor %}
{% endfor %}
{{ eteams.eteam }}
UPDATE 2
This is nearly done. I will implement the changes in the full dashboard but those experienced with the implementation could use this to get all the categories ā top 3, two current wildcards, those still in the hunt, and those eliminated.
###
### NHL Wildcard
###
- name: NHL Wildcard Standings
unique_id: sensor.nhl_wildcard_standings
state: "{{ now() }}"
attributes:
east_atlantic_top: "{{ state_attr('sensor.nhl_wildcard','overall')[0]['children'][0]['standings']['entries'] }}"
east_metropolitan_top: "{{ state_attr('sensor.nhl_wildcard','overall')[0]['children'][1]['standings']['entries'] }}"
east_wildcard: "{{ state_attr('sensor.nhl_wildcard','children')[0]['standings']['entries'][:2] }}"
east_hunt: >
{% set hteams = namespace(hteam=[]) %}
{% for team in state_attr('sensor.nhl_wildcard','children')[0]['standings']['entries'][2:] %}
{% for stat in team['stats'] | selectattr('name','eq','clincher') %}
{% else %}
{% set hteams.hteam = hteams.hteam + [team] %}
{% endfor %}
{% endfor %}
{{ hteams.hteam }}
east_eliminated: >
{% set eteams = namespace(eteam=[]) %}
{% for team in state_attr('sensor.nhl_wildcard','children')[0]['standings']['entries'][2:] %}
{% for stat in team['stats'] %}
{% if stat.name == 'clincher' %}
{% set eteams.eteam = eteams.eteam + [team] %}
{% endif %}
{% endfor %}
{% endfor %}
{{ eteams.eteam }}
west_central_top: "{{ state_attr('sensor.nhl_wildcard','overall')[1]['children'][0]['standings']['entries'] }}"
west_pacific_top: "{{ state_attr('sensor.nhl_wildcard','overall')[1]['children'][1]['standings']['entries'] }}"
west_wildcard: "{{ state_attr('sensor.nhl_wildcard','children')[1]['standings']['entries'][:2] }}"
west_hunt: >
{% set hteams = namespace(hteam=[]) %}
{% for team in state_attr('sensor.nhl_wildcard','children')[1]['standings']['entries'][2:] %}
{% for stat in team['stats'] | selectattr('name','eq','clincher') %}
{% else %}
{% set hteams.hteam = hteams.hteam + [team] %}
{% endfor %}
{% endfor %}
{{ hteams.hteam }}
west_eliminated: >
{% set eteams = namespace(eteam=[]) %}
{% for team in state_attr('sensor.nhl_wildcard','children')[1]['standings']['entries'][2:] %}
{% for stat in team['stats'] %}
{% if stat.name == 'clincher' %}
{% set eteams.eteam = eteams.eteam + [team] %}
{% endif %}
{% endfor %}
{% endfor %}
{{ eteams.eteam }}
The other thing I saw mentioned previously was a symbol/text key or legend. I created a markdown card to add it, but now working on formatting so it is similar to how the NHL displays it (see the bottom of this website NHL Hockey Standings | NHL.com):
- type: markdown
title: Legend
content: >
x - Clinched Playoff spot
p - Presidents' Trophy
GP - Games Played
W - Wins (worth two points)
L - Losses (worth zero points)
OT - OT/Shootout losses (worth one point)
PTS - Points
P% - Points Percentage
RW - Regulation Wins
ROW - Regulation plus Overtime Wins
GF - Goals For
GA - Goals Against
DIFF - Goal Differential
HOME - Home record
AWAY - Away Record
S/O - Record in games decided by Shootout
L10 - Record in last ten games
STRK - Streak