You should definitely do a write-up on how you did that scoreboard. That is phenomenal!
This is amazing work! im a bit lost looking for the bears… i see you use ss.xml but im not sniffing anything related to the Chicago Bears. - Tom mentioned he set up for buffalo… how did you find buffalo?
@jamesking210 CHI would be for the Bears.
Is anyone else having issues with their sensors updating in home assistant? It looks like the ss.xml link is still reporting Week 17’s scores from last year. When I try ss.json the sensors return an unavailable state. Thoughts?
Apparently, the NFL is no longer updating the xml link. Last year it would update on Wednesday for the week’s games. From what I could find, you now have to create an account (and pay) to get live data. Yeah, it sucks.
I’m not good enough with json / rest sensors to figure this out, but would it be possible to use the ESPN API? http://site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard
With some help, I was able to get the ESPN API working. I have this sensor for GB score:
- platform: rest
resource: http://site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard
name: Packers Score
value_template: >
{% for event in value_json["events"] %}
{% if 'GB' in event.shortName %}
{% for competition in event["competitions"] %}
{% if competition.status.type.state != 'pre' and competition.status.type.state != 'post' %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation == 'GB' %}
{{ competitor.score }}
{% endif %}
{% endfor %}
{% else %}
0
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
scan_interval: 3
My “score” automation triggers when the sensor updates with a condition that the score is not 0. I also have a google calendar automation that updates the scan interval from 86400 to 3 when the Packers are playing, and changes it back to 86400 when the game is over.
edit: damn… really wish I would have had more opportunities to test it out this week.
I feel guilty as a Saints fan telling you this, but I can assure you it worked really well!
Seriously, thank you.
Do you mind sharing how you set up your scan interval automation?
Sure, I can wipe away the tears and stop drinking for a few moments.
First, my score sensor is the only sensor with scan_interval values of 86400 / 3. So, I made two shell_commands. (game_on & game_over).
game_on: sed -i 's/scan_interval:\ 86400/scan_interval:\ 3/' /config/configuration.yaml
game_over: sed -i 's/scan_interval:\ 3/scan_interval:\ 86400/' /config/configuration.yaml
I’m also using docker, so you might have to edit the file location of configuration.yaml if you’re not.
Next, and add the calendar for your team in google calendar.
Back in HA, set up the google calendar integration. You should now have /config/google_calendars.yaml and you should have an entry similar to this in that file:
- cal_id: nfl_9_%47reen+%42ay+%50ackers#[email protected]
entities:
- device_id: green_bay_packers
ignore_availability: true
name: Green Bay Packers
track: false
Change track: false
to track: true
and restart HA. You should now see the game dates & times in your HA calendar.
So, the automations go something like this:
- alias: Game On
trigger:
- platform: state
entity_id: calendar.green_bay_packers
to: 'on'
from: 'off'
action:
- service: shell_command.game_on
- service: homeassistant.restart
mode: single
- alias: Game Over
trigger:
- platform: state
entity_id: calendar.green_bay_packers
from: 'on'
to: 'off'
action:
- service: shell_command.game_over
- service: homeassistant.restart
mode: single
And that should do it. At game time, the scan_interval will be updated to 3 or whatever you want, and HA will automatically restart to apply the changes. When the game is over, it’ll go back to 86400 (24 hours) and again, automatically restart to apply the changes.
Good luck with the rest of the season. I hope we can see you guys in the playoffs if we get our act together.
Thank you so much again to @D34DC3N73R for getting this going again. I was totally lost until you posted your sensor. Here are all the sensors I have made for the Saints using ESPN’s api:
***Edited my config below to follow @Jefe’s suggestion and make all sensors one API call. I told y’all I didn’t know what I was doing!
######################################
############SAINTS SENSORS############
######################################
########SAINTS SCORE SENSOR########
rest:
- resource: http://site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard
scan_interval: 86400
sensor:
- name: Saints Score
value_template: >
{% for event in value_json["events"] %}
{% if 'NO' in event.shortName %}
{% for competition in event["competitions"] %}
{% if competition.status.type.state != 'pre' or competition.status.type.state == 'post' %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation == 'NO' %}
{{ competitor.score }}
{% endif %}
{% endfor %}
{% else %}
0
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
########SAINTS DISPLAY NAME SENSOR########
- name: Saints Display Name
value_template: >
{% for event in value_json["events"] %}
{% if 'NO' in event.shortName %}
{% for competition in event["competitions"] %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation == 'NO' %}
{{ competitor.team.displayName }}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
########SAINTS OPPONENT SCORE SENSOR########
- name: Saints Opponent Score
value_template: >
{% for event in value_json["events"] %}
{% if 'NO' in event.shortName %}
{% for competition in event["competitions"] %}
{% if competition.status.type.state != 'pre' or competition.status.type.state == 'post' %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation != 'NO' %}
{{ competitor.score }}
{% endif %}
{% endfor %}
{% else %}
0
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
########SAINTS OPPONENT NAME SENSOR########
- name: Saints Opponent Name
value_template: >
{% for event in value_json["events"] %}
{% if 'NO' in event.shortName %}
{% for competition in event["competitions"] %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation != 'NO' %}
{{ competitor.team.displayName }}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
########SAINTS GAME STATUS SENSORS########
- name: Saints Game Status
value_template: >
{% for event in value_json["events"] %}
{% if 'NO' in event.shortName %}
{% for competition in event["competitions"] %}
{% if competition.status.type.state == 'pre' %}
Pregame
{% elif competition.status.type.state == 'post' %}
Final
{% else %}
{{ competition.status.displayClock }}, Q{{ competition.status.period }}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
########SAINTS GAME TIME SENSOR########
- name: Saints Game Time
value_template: >
{% for event in value_json["events"] %}
{% if 'NO' in event.shortName %}
{% for competition in event["competitions"] %}
{{ competition.date }}
{% endfor %}
{% endif %}
{% endfor %}
########SAINTS GAME CITY SENSOR########
- name: Saints Game City
value_template: >
{% for event in value_json["events"] %}
{% if 'NO' in event.shortName %}
{% for competition in event["competitions"] %}
{{ competition.venue.address.city }}, {{ competition.venue.address.state }}
{% endfor %}
{% endif %}
{% endfor %}
########SAINTS GAME VENUE SENSOR########
- name: Saints Game Venue
value_template: >
{% for event in value_json["events"] %}
{% if 'NO' in event.shortName %}
{% for competition in event["competitions"] %}
{{ competition.venue.fullName }}
{% endfor %}
{% endif %}
{% endfor %}
########SAINTS GAME BROADCAST SENSOR########
- name: Saints Game Broadcast
value_template: >
{% for event in value_json["events"] %}
{% if 'NO' in event.shortName %}
{% for competition in event["competitions"] %}
{% for broadcast in competition["broadcasts"] %}
{% for name in broadcast["names"] %}
{{ name }}
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
########SAINTS GAME INFO DISPLAY SENSOR########
sensor:
- platform: template
sensors:
saints_game_status_display:
value_template: >
{% if state_attr('calendar.new_orleans_saints', 'start_time') | as_timestamp - now() | as_timestamp < 259200 and state_attr('calendar.new_orleans_saints', 'start_time') | as_timestamp - now() | as_timestamp > -10800 %}
{{ states('sensor.saints_game_venue') }} - {{ states('sensor.saints_game_city') }} ({{ states('sensor.saints_game_broadcast') }})
{% else %}
{{ states('sensor.saints_game_venue') }} - {{ states('sensor.saints_game_city') }}
{% endif %}
Anyone should be able to change the sensors to their team by just replacing “NO” with whatever the abbreviation for their team is at: http://site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard
I am using all of those sensors to populate a custom Lovelace card:
I ended up making an automation in the UI that forces a refresh of the score/time sensors every 3 seconds during the game. Although I am using the google calendar setup like @D34DC3N73R does, I didn’t end up using their script because I didn’t want to have to restart HA. Here is that automation:
alias: Saints - NFL Scores - Update JSON/XML Every 3 Seconds During Game Only
description: ''
trigger:
- platform: state
entity_id: sensor.saints_game_status
from: Pregame
- platform: state
entity_id: calendar.new_orleans_saints
to: 'on'
from: 'off'
- platform: template
value_template: >-
{{ (state_attr('calendar.new_orleans_saints', 'start_time') | as_timestamp
- now() | as_timestamp) < 300 and
(state_attr('calendar.new_orleans_saints', 'start_time') | as_timestamp -
now() | as_timestamp) > 0 }}
condition:
- condition: or
conditions:
- condition: state
entity_id: calendar.new_orleans_saints
state: 'on'
- condition: not
conditions:
- condition: state
entity_id: sensor.saints_game_status
state: Final
- condition: template
value_template: >-
{{ (state_attr('calendar.new_orleans_saints', 'start_time') |
as_timestamp - now() | as_timestamp) < 300 and
(state_attr('calendar.new_orleans_saints', 'start_time') |
as_timestamp - now() | as_timestamp) > 0 }}
action:
- repeat:
until:
- condition: or
conditions:
- condition: state
entity_id: sensor.saints_game_status
state: Final
- condition: state
entity_id: calendar.new_orleans_saints
state: 'off'
for: '01:00:00'
sequence:
- service: homeassistant.update_entity
data: {}
target:
entity_id:
- sensor.saints_game_status
- sensor.saints_score
- sensor.saints_opponent_score
- delay:
hours: 0
minutes: 0
seconds: 3
milliseconds: 0
mode: single
Everything seems to be working well. (I REALLY don’t know what I’m doing.) Hopefully this is helpful for someone. I can confirm it worked in real time for yesterday’s game. (My touchdown celebration automations triggered every time before the extra point was kicked.)
using what i read here from ESPN’s i got what i needed with scoring… on the API i see isRedZone = “true” or “false” - is there a way to make a new sensor with just that true/false info from across the league? i plan on making an automation of when true, my lights will go red
Nice another Saints fan WHO DAT!!!
I just looked and it seems like the red zone sensor category is only visible while a game is active. I’m also not quite understanding, are you wanting a red zone sensor for just your team’s game, or are you trying to have your lights turn red when any team in any active game is in the red zone?
Either way, you’ll probably have to wait until Sunday to try to set up or test any of it, since right now the API is not showing any red zone categories.
I took a little bit different of a route to achieve this using Google Calendar. Rather than using the NFL api, I can create cards for any sport.
And if you want to be notified before a game starts, you can setup notifications X minutes before: https://smarthomepursuits.com/how-to-setup-google-calendar-event-notifications/
Looks great. Are the scores in the google calendar entry description updated in real time? That’s where you’re pulling those scores from, right?
Thanks to @D34DC3N73R and @davearneson for your contributions!
I converted the sensors to only call the API once per update (using the Steelers). This should be more efficient. I have the scan_interval set to 300 while testing. Code should be placed in the config file (or a package).
rest:
- resource: http://site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard
scan_interval: 300
sensor:
- name: Steelers Score
value_template: >
{% for event in value_json["events"] %}
{% if 'PIT' in event.shortName %}
{% for competition in event["competitions"] %}
{% if competition.status.type.state != 'pre' or competition.status.type.state == 'post' %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation == 'PIT' %}
{{ competitor.score }}
{% endif %}
{% endfor %}
{% else %}
0
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
- name: Steelers Display Name
value_template: >
{% for event in value_json["events"] %}
{% if 'PIT' in event.shortName %}
{% for competition in event["competitions"] %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation == 'PIT' %}
{{ competitor.team.displayName }}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
- name: Steelers Opponent Score
value_template: >
{% for event in value_json["events"] %}
{% if 'PIT' in event.shortName %}
{% for competition in event["competitions"] %}
{% if competition.status.type.state != 'pre' or competition.status.type.state == 'post' %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation != 'PIT' %}
{{ competitor.score }}
{% endif %}
{% endfor %}
{% else %}
0
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
- name: Steelers Opponent Name
value_template: >
{% for event in value_json["events"] %}
{% if 'PIT' in event.shortName %}
{% for competition in event["competitions"] %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation != 'PIT' %}
{{ competitor.team.displayName }}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
- name: Steelers Game Status
value_template: >
{% for event in value_json["events"] %}
{% if 'PIT' in event.shortName %}
{% for competition in event["competitions"] %}
{% if competition.status.type.state == 'pre' %}
Pregame
{% elif competition.status.type.state == 'post' %}
Final
{% else %}
{{ competition.status.displayClock }}, Q{{ competition.status.period }}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
- name: Steelers Game Time
value_template: >
{% for event in value_json["events"] %}
{% if 'PIT' in event.shortName %}
{% for competition in event["competitions"] %}
{{ competition.date }}
{% endfor %}
{% endif %}
{% endfor %}
- name: Steelers Game City
value_template: >
{% for event in value_json["events"] %}
{% if 'PIT' in event.shortName %}
{% for competition in event["competitions"] %}
{{ competition.venue.address.city }}, {{ competition.venue.address.state }}
{% endfor %}
{% endif %}
{% endfor %}
- name: Steelers Game Venue
value_template: >
{% for event in value_json["events"] %}
{% if 'PIT' in event.shortName %}
{% for competition in event["competitions"] %}
{{ competition.venue.fullName }}
{% endfor %}
{% endif %}
{% endfor %}
- name: Steelers Game Broadcast
value_template: >
{% for event in value_json["events"] %}
{% if 'PIT' in event.shortName %}
{% for competition in event["competitions"] %}
{% for broadcast in competition["broadcasts"] %}
{% for name in broadcast["names"] %}
{{ name }}
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
Yeah, that makes a lot more sense. I edited my config (and my previous post) to follow your suggestion.
Your scorecard inspired me to create something similar.
I use card-mod a lot but figured I’d post the code for anyone wanting something similar.
sensors + template sensors
rest:
- resource: http://site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard
scan_interval: 86400
sensor:
- name: Packers Score
value_template: >
{% for event in value_json["events"] %}
{% if 'GB' in event.shortName %}
{% for competition in event["competitions"] %}
{% if competition.status.type.state != 'pre' and competition.status.type.state != 'post' %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation == 'GB' %}
{{ competitor.score }}
{% endif %}
{% endfor %}
{% else %}
0
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
- name: Packers Display Name
value_template: >
{% for event in value_json["events"] %}
{% if 'GB' in event.shortName %}
{% for competition in event["competitions"] %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation == 'GB' %}
{{ competitor.team.shortDisplayName }}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
- name: Packers Display Logo
value_template: >
{% for event in value_json["events"] %}
{% if 'GB' in event.shortName %}
{% for competition in event["competitions"] %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation == 'GB' %}
{{ competitor.team.logo }}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
- name: Packers Opponent Score
value_template: >
{% for event in value_json["events"] %}
{% if 'GB' in event.shortName %}
{% for competition in event["competitions"] %}
{% if competition.status.type.state != 'pre' and competition.status.type.state != 'post' %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation != 'GB' %}
{{ competitor.score }}
{% endif %}
{% endfor %}
{% else %}
0
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
- name: Packers Opponent Name
value_template: >
{% for event in value_json["events"] %}
{% if 'GB' in event.shortName %}
{% for competition in event["competitions"] %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation != 'GB' %}
{{ competitor.team.shortDisplayName }}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
- name: Packers Opponent Logo
value_template: >
{% for event in value_json["events"] %}
{% if 'GB' in event.shortName %}
{% for competition in event["competitions"] %}
{% for competitor in competition["competitors"] %}
{% if competitor.team.abbreviation != 'GB' %}
{{ competitor.team.logo }}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
- name: Packers Game Status
value_template: >
{% for event in value_json["events"] %}
{% if 'GB' in event.shortName %}
{% for competition in event["competitions"] %}
{% if competition.status.type.state == 'pre' %}
Pregame
{% elif competition.status.type.state == 'post' %}
Final
{% else %}
Q{{ competition.status.period }}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
- name: Packers Game Clock
value_template: >
{% for event in value_json["events"] %}
{% if 'GB' in event.shortName %}
{% for competition in event["competitions"] %}
{{ competition.status.displayClock }}
{% endfor %}
{% endif %}
{% endfor %}
- name: Packers Game Time
value_template: >
{% for event in value_json["events"] %}
{% if 'GB' in event.shortName %}
{% for competition in event["competitions"] %}
{{ competition.date }}
{% endfor %}
{% endif %}
{% endfor %}
- name: Packers Game City
value_template: >
{% for event in value_json["events"] %}
{% if 'GB' in event.shortName %}
{% for competition in event["competitions"] %}
{{ competition.venue.address.city }}, {{ competition.venue.address.state }}
{% endfor %}
{% endif %}
{% endfor %}
- name: Packers Game Venue
value_template: >
{% for event in value_json["events"] %}
{% if 'GB' in event.shortName %}
{% for competition in event["competitions"] %}
{{ competition.venue.fullName }}
{% endfor %}
{% endif %}
{% endfor %}
- name: Packers Game Broadcast
value_template: >
{% for event in value_json["events"] %}
{% if 'GB' in event.shortName %}
{% for competition in event["competitions"] %}
{% for broadcast in competition["broadcasts"] %}
{% for name in broadcast["names"] %}
{{ name }}
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
sensor:
- platform: template
sensors:
packers_sb_score:
value_template: >
{{ states('sensor.packers_score') }}
friendly_name_template: >
{{ states('sensor.packers_display_name') }}
entity_picture_template: >-
{{ states('sensor.packers_display_logo') }}
packers_sb_opponent_score:
value_template: >
{{ states('sensor.packers_opponent_score') }}
friendly_name_template: >
{{ states('sensor.packers_opponent_name') }}
entity_picture_template: >-
{{ states('sensor.packers_opponent_logo') }}
sb_state_clock:
value_template: >
{{ states('sensor.packers_game_clock') }}
friendly_name_template: >
{{ states('sensor.packers_game_status') }}
sb_venue_date:
value_template: >
{{ as_timestamp(strptime(as_datetime(states.sensor.packers_game_time.state), '%Y-%m-%d %H:%M:%S%z')) | timestamp_custom("%A @ %-I:%M %p") }}
friendly_name_template: >
{{ states('sensor.packers_game_venue') }}
sb_city_broadcast:
value_template: >
{{ states('sensor.packers_game_broadcast') }}
friendly_name_template: >
{{ states('sensor.packers_game_city') }}
and the lovelace card
- type: entities
title: Scoreboard
entities:
- entity: sensor.packers_sb_score
style: |
hui-generic-entity-row {
font-size: 1.8em;
font-weight: 500;
text-transform: uppercase;
}
- entity: sensor.packers_sb_opponent_score
style: |
hui-generic-entity-row {
font-size: 1.8em;
font-weight: 500;
text-transform: uppercase;
}
- entity: sensor.sb_state_clock
style:
hui-generic-entity-row:
.: |
.text-content {
font-size: 1.2em;
}
$: |
state-badge {display:none;}
.text-content {
margin-left: 0px !important;
font-size: 1.2em;
}
- type: divider
- entity: sensor.sb_venue_date
style:
hui-generic-entity-row:
$: |
state-badge {display:none;}
.text-content {
margin-left: 0px !important;
}
- entity: sensor.sb_city_broadcast
style:
hui-generic-entity-row:
.: |
.text-content {
font-weight: 100;
}
$: |
state-badge {display:none;}
.text-content {
margin-left: 0px !important;
font-weight: 100;
}
Nice, that looks really great! I’m planning on keeping an eye on the game tonight so I can figure out what other information they have active during the game. (Possession, down and distance, last play, etc.)
I’ll post if I find anything interesting.