The state will be PRE, IN, POST, or NOT_FOUND.
Hi guys, is it possible to add some kind of identifier on the card for the corresponding team when thereās a power play event? I saw in the API http://site.api.espn.com/apis/site/v2/sports/hockey/nhl/summary?event=GAMEID that the event is registered as:
{
"id": "401802564000006850",
"sequenceNumber": "165",
"type": {
"id": "509",
"text": "Penalty",
"abbreviation": "penalty"
},
"text": "Brandon Carlo Tripping against Barrett Hayton",
"awayScore": 1,
"homeScore": 2,
"period": {
"number": 2,
"displayValue": "2nd"
},
"clock": {
"displayValue": "13:05"
},
"scoringPlay": false,
"scoreValue": 0,
"modified": "2025-11-06T02:34Z",
"team": {
"id": "21"
},
"participants": [
{
"athlete": {
"id": "3904175",
"displayName": "Brandon Carlo",
"shortName": "B. Carlo",
"headshot": {
"href": "https://a.espncdn.com/i/headshots/nhl/players/full/3904175.png",
"alt": "Brandon Carlo"
}
},
"type": "penalized",
"ytdGoals": 0
},
{
"athlete": {
"id": "4352699",
"displayName": "Barrett Hayton",
"shortName": "B. Hayton",
"headshot": {
"href": "https://a.espncdn.com/i/headshots/nhl/players/full/4352699.png",
"alt": "Barrett Hayton"
}
},
"ytdAssists": 2
}
],
"wallclock": "2025-11-06T01:30:23Z",
"shootingPlay": true,
"coordinate": {
"x": -76,
"y": 14
},
"strength": {
"id": "701",
"text": "Even Strength",
"abbreviation": "even-strength"
}
},
As of last season, the scoreboard API didnāt have a PP indicator. I will check again and also look at the API you listed. If itās not in the scoreboard API, it wonāt be quick.
@timblazing recently shared a Custom Mushroom Template Badge that I wanted to pass along.
Anyone looking for a compact display should check it out.
type: custom:mushroom-template-badge
entity: sensor.pittsburgh_steelers
icon: mdi:football
content: >
{% set raw_date = state_attr(entity, 'date') %}
{% set team_score = (state_attr(entity, 'team_score') | int(0)) %}
{% set opp_score = (state_attr(entity, 'opponent_score') | int(0)) %}
{% set winner = state_attr(entity, 'team_winner') %}
{% set clock = state_attr(entity, 'clock') %}
{% set quarter = state_attr(entity, 'quarter') %}
{# ----- POST ----- #}
{% if clock == 'Final' %}
{% if winner %}
W {{ team_score }}-{{ opp_score }}
{% elif winner == false %}
L {{ team_score }}-{{ opp_score }}
{% else %}
{{ team_score }}-{{ opp_score }}
{% endif %}
{# ----- IN ----- #}
{% elif team_score > 0 or opp_score > 0 %}
{% if clock %}
{% if 'half' in clock | lower %}
{{ team_score }}-{{ opp_score }} | HALFTIME
{% else %}
{{ team_score }}-{{ opp_score }} | {{ clock }}
{% endif %}
{% else %}
{% if quarter %}
{% set q = quarter | int %}
{% if q == 1 %}
{{ team_score }}-{{ opp_score }} | 1st
{% elif q == 2 %}
{{ team_score }}-{{ opp_score }} | 2nd
{% elif q == 3 %}
{{ team_score }}-{{ opp_score }} | 3rd
{% elif q == 4 %}
{{ team_score }}-{{ opp_score }} | 4th
{% else %}
{{ team_score }}-{{ opp_score }} | OT
{% endif %}
{% else %}
{{ team_score }}-{{ opp_score }}
{% endif %}
{% endif %}
{# ----- PRE ----- #}
{% elif raw_date %}
{% set dt = as_datetime(raw_date) %}
{% set local = as_local(dt) %}
{% set today = as_local(now()).date() %}
{% if local.date() == today %}
Today at {{ local.strftime('%-I:%M %p') }}
{% else %}
{{ local.strftime('%A at %-I:%M %p') }}
{% endif %}
{# ----- BYE / NOT_FOUND ----- #}
{% else %}
BYE
{% endif %}
label: >
{%- set event = state_attr(entity, 'event_name') or '' -%}
{%- set raw_date = state_attr(entity, 'date') -%}
{%- if raw_date -%}
{{ event }}
{%- else -%}
{{ '' }}
{%- endif -%}
color: |
{% set winner = state_attr(entity, 'team_winner') %}
{% if winner == true %}
green
{% elif winner == false %}
red
{% else %}
grey
{% endif %}
picture: |
{{ state_attr(entity, 'team_logo') }}
I added possession using an asterisk before the home team or after the away team.
{{ '<p style="text-align: start"; "font-weight: bold"><tt>' }}
{%- set ns = namespace(holdleague='') -%}
{%- set teams = integration_entities("teamtracker") | expand | selectattr('state', 'eq', 'IN') | selectattr('attributes.team_homeaway', 'eq', 'away') | sort(attribute='attributes.league,attributes.date,attributes.team_abbr') | map(attribute='entity_id') | list -%}
{%- for team in teams -%}
{%- if state_attr(team, 'league') != ns.holdleague -%}
{{ '' if loop.first else '<br>' }}
{%- set ns.holdleague = state_attr(team, 'league') %}
{{ state_attr(team, 'league')~'<br>' }}
{%- endif %}
{%- set team_possession = '*' if state_attr(team, 'possession') == state_attr(team, 'team_id') else ' ' -%}
{%- set opponent_possession = '*' if state_attr(team, 'possession') == state_attr(team, 'opponent_id') else ' ' -%}
{%- set teamscore = (' ' if state_attr(team, 'team_score') | length < 2 else '')~state_attr(team, 'team_score') %}
{%- set opponentscore = state_attr(team, 'opponent_score')~(' ' if state_attr(team, 'opponent_score') | length < 2 else '') %}
{%- set teamabbr = state_attr(team, 'team_abbr')~(' ' if state_attr(team, 'team_abbr') | length < 3 else '') %}
{%- set opponentabbr = state_attr(team, 'opponent_abbr')~(' ' if state_attr(team, 'opponent_abbr') | length < 3 else '') %}
{{ ' '~team_possession~teamabbr~' @ '~opponentabbr~opponent_possession~' '~' '~teamscore~'-'~opponentscore~' '~state_attr(team, 'clock') | replace('Rain Delay', 'RD') | replace('Delayed', 'Del')~'<br>' }}
{%- endfor %}
{{ '</tt></p>' }}
Admittedly, since itās a lot of copy/paste, I used AI to clean up this YAML code. However, I canāt seem to get it to only show the home game instead of showing home and away team, duplicating the card. What am I missing, any suggestions? Code and screenshot below.
type: horizontal-stack
cards:
- type: vertical-stack
cards:
- type: markdown
content: |
## š Atlantic Division š„
šØ
- type: custom:teamtracker-card
entity: sensor.bos_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.buf_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.det_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.fla_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.mtl_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.ott_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.tbl_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.tor_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: vertical-stack
cards:
- type: markdown
content: |
## š Metropolitan Division š„
šØ
- type: custom:teamtracker-card
entity: sensor.car_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.cbj_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.njd_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.nyi_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.nyr_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.phi_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.pit_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.wsh_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: vertical-stack
cards:
- type: markdown
content: |
## š Central Division š„
šØ
- type: custom:teamtracker-card
entity: sensor.ari_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.chi_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.col_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.dal_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.min_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.nsh_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.stl_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.wpg_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: vertical-stack
cards:
- type: markdown
content: |
## š Pacific Division š„
šØ
- type: custom:teamtracker-card
entity: sensor.ana_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.cgy_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.edm_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.lak_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.sjs_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.sea_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.van_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
- type: custom:teamtracker-card
entity: sensor.vgk_team_tracker
can_interval: 1
filter:
- attribute: team_homeaway
value: home
grid_options:
columns: 48
rows: auto
I would use the auto-entitites card.
If you rename your sensors using a naming convention similar to the following you should be able to filter and group them the way you want.
sensor.tt_nhl_metro_car
sensor.tt_nhl_metro_cbj
etc.
This should get you started.
type: custom:auto-entities
unique: true
show_empty: false
card:
type: custom:layout-card
layout_type: masonry
card_param: cards
filter:
template: |
{%- for team in integration_entities("teamtracker") -%}
{%- if "sensor.tt_nhl_metro" in team -%}
{%- if not is_state(team, "NOT_FOUND")
and state_attr(team, "team_homeaway") == "home" -%}
{{{"type": "custom:teamtracker-card",
"show_league": true,
"entity": team }}},
{%- endif -%}
{%- endif -%}
{%- endfor -%}
sort:
method: attribute
attribute: date
Hello, and thanks for this beautiful integration. One question, how to know who is on serve in Tennis Sports? Itās important for me to know and to show in the card.
Thanks!
I just checked and the API doesnāt return this info. Sorry.
Is there a way to calculate it based on the score and who is considered Home and Away?
@vasqued2 as always fantastic work on the tt and card.
I donāt know if this is a feature request or if something that doesnāt make sense to do and we should just wait for the ESPN Olympic scoreboard API to update with 2026 data.
My question is does a feature request make sense to add dates? Default if no date range is there to just use scoreboard but if it does exist append. Specifically something like this:
## Group C
- platform: teamtracker
league_id: XXX
sport_path: hockey
league_path: olympics-mens-ice-hockey
team_id: USA
name: United States
date_range: 20260201-20260222
Background
I know that I can get to mens & womens Olympic hockey data through these links: [https://site.api.espn.com/apis/site/v2/sports/hockey/olympics-mens-ice-hockey/scoreboard]
[https://site.api.espn.com/apis/site/v2/sports/hockey/olympics-womens-ice-hockey/scoreboard]
but they show 2022 results
I also know that I can get the upcoming 2026 games if I append the dates to the scoreboard link [https://site.api.espn.com/apis/site/v2/sports/hockey/olympics-mens-ice-hockey/scoreboard?dates=20260201-20260222] and the status within the data returned is correct with pre -
"status": {
"clock": 0,
"displayClock": "0:00",
"period": 0,
"type": {
"id": "1",
"name": "STATUS_SCHEDULED",
"state": "pre",
"completed": false,
"description": "Scheduled",
"detail": "Wed, February 11th at 10:40 AM EST",
"shortDetail": "2/11 - 10:40 AM EST"
}
and if I use my python script I can get it to display in HA just not using your TT card.
but if I try to show USA I get nothing because TT is going to the scoreboard link and it doesnāt contain that information
I also assume that if I wanted to display previous years I could then just append previous year dates so for example if I wanted to see results from 2022 or 2018 etc. I could just create a new tt sensor from the 2022 games as well: ?dates=20220209-20220220 which then tt would use the whole link: https://site.api.espn.com/apis/site/v2/sports/hockey/olympics-mens-ice-hockey/scoreboard?dates=20220209-20220220
Not a burning need, but thought I would ask.
If would also be interesting if we could use that for other sports like NFL.
https://site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard?dates=20250904-20260208
Can anyone help me with the Data for Millwall in the English championship Iāve tried MIL and the league as. eng.2 and the sport as soccer ??
Basically, choose Custom on the first screen and enter mil for the team, then on the second screen, sport path will be soccer and league path is eng.2
Itās working for me. What is your api_url and api_message.
Hi
Itās {ācodeā:400,āmessageā:āFailed to get events endpoint.ā}
This is an interesting idea and I like the thought. I do some date logic to look about a week into the future but generally assumed the API defaulted to the future dates once the future dates were added to the schedule. Thatās clearly not the case.
Thereās a couple things I need to think through.
First and most important, I honor ESPNās limit on the number of competitions returned by the API. I do this for a couple reasons. First, while a competition is in progress, the API gets called every 5 seconds. I donāt want to call the API that frequently and get the results of tons of competitions and run the risk of getting ESPNās attention and triggering some sort of block, either at a client level or the sensor itself attracting attention. Secondly, there is also a limit to the amount of data HA can practically parse before the next call 5 seconds later. As the number of competitions returned increase, this would become more of a concern.
Since the number of competitions in a date range would likely exceed ESPNās limit. The practical reality is this would work for the first couple competitions in the range, and then the later ones would get truncated off the API response and you wouldnāt get the most recent results.
I could probably get around this by using either the start of the date range or todayās date, whichever is farther in the future. This wouldnāt allow the back-dating for past events like you talked about though.
Iām wondering if I could do something where if the event returned by default is more than like a month old, I look much farther into the future than I do today. The API limit would prevent a ton of responses and using a larger future date range would pick up the future events that I didnāt realize were populated and available for retrieval.
I will play around with it. I think the biggest problem is the future competitions that arenāt pulled back by default. Let me know your thoughts and suggestions.
What is the api_url? Either you have a bad URL, which could be because you have a typo or are using caps instead of lower case, or the URL is being blocked by your firewall or something else.
Cheers mate, I could have sworn I did it all in Lowercase but it was on my phone so maybe it defaulted to capital at the start. Itās working now cheers
Glad to hear it!!! See you in 2 weeks when we beat yāall!!! ![]()








