more splitting
This commit is contained in:
@@ -0,0 +1,221 @@
|
|||||||
|
import utils.image_utils as image_utils
|
||||||
|
from rgbmatrix import graphics
|
||||||
|
from scoreboard import Colors, data
|
||||||
|
from time import time, sleep
|
||||||
|
|
||||||
|
def get_scores(sport, league):
|
||||||
|
url = f"https://site.api.espn.com/apis/site/v2/sports/{sport}/{league}/scoreboard"
|
||||||
|
try:
|
||||||
|
resp = requests.get(url, timeout=5)
|
||||||
|
resp.raise_for_status()
|
||||||
|
games = []
|
||||||
|
for event in resp.json().get("events", []):
|
||||||
|
comp = event["competitions"][0]
|
||||||
|
teams = comp["competitors"]
|
||||||
|
home = next(t for t in teams if t["homeAway"] == "home")
|
||||||
|
away = next(t for t in teams if t["homeAway"] == "away")
|
||||||
|
status = event["status"]["type"]["shortDetail"]
|
||||||
|
games.append(
|
||||||
|
{
|
||||||
|
"league": league,
|
||||||
|
"away": away["team"]["abbreviation"].upper(),
|
||||||
|
"away_score": away["score"],
|
||||||
|
"home": home["team"]["abbreviation"].upper(),
|
||||||
|
"home_score": home["score"],
|
||||||
|
"status": status,
|
||||||
|
"id": event["id"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return games
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fetch error ({league}): {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_all_scores():
|
||||||
|
print('fetching game scores from espn')
|
||||||
|
games = []
|
||||||
|
games += get_scores("hockey", "nhl")
|
||||||
|
games += get_scores("football", "nfl")
|
||||||
|
games += get_scores("basketball", "nba")
|
||||||
|
games += get_scores("baseball", "mlb")
|
||||||
|
return games
|
||||||
|
|
||||||
|
def draw_all_games(canvas, games, start_index):
|
||||||
|
for i in range(4):
|
||||||
|
game_index = (start_index + i) % len(games)
|
||||||
|
game = games[game_index]
|
||||||
|
offset = i * 64
|
||||||
|
|
||||||
|
league = game["league"]
|
||||||
|
away_logo = image_utils.load_logo(league, game["away"])
|
||||||
|
home_logo = image_utils.load_logo(league, game["home"])
|
||||||
|
|
||||||
|
image_utils.draw_logo(canvas, away_logo, offset + 0, 0)
|
||||||
|
image_utils.draw_logo(canvas, home_logo, offset + 0, 16)
|
||||||
|
|
||||||
|
graphics.DrawText(
|
||||||
|
canvas,
|
||||||
|
data['fonts']['font_small'],
|
||||||
|
offset + 18,
|
||||||
|
11,
|
||||||
|
graphics.Color(*Colors.RED.value),
|
||||||
|
game["away"],
|
||||||
|
)
|
||||||
|
graphics.DrawText(
|
||||||
|
canvas,
|
||||||
|
data['fonts']['font_small'],
|
||||||
|
offset + 18,
|
||||||
|
27,
|
||||||
|
graphics.Color(*Colors.WHITE.value),
|
||||||
|
game["home"],
|
||||||
|
)
|
||||||
|
|
||||||
|
graphics.DrawText(
|
||||||
|
canvas,
|
||||||
|
data['fonts']['font'],
|
||||||
|
offset + 40,
|
||||||
|
13,
|
||||||
|
graphics.Color(*Colors.WHITE.value),
|
||||||
|
str(game["away_score"]),
|
||||||
|
)
|
||||||
|
graphics.DrawText(
|
||||||
|
canvas,
|
||||||
|
data['fonts']['font'],
|
||||||
|
offset + 40,
|
||||||
|
29,
|
||||||
|
graphics.Color(*Colors.WHITE.value),
|
||||||
|
str(game["home_score"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
if i < 3:
|
||||||
|
for row in range(32):
|
||||||
|
canvas.SetPixel(offset + 63, row, 40, 40, 40)
|
||||||
|
|
||||||
|
def draw_single_game(canvas, game):
|
||||||
|
league = game["league"]
|
||||||
|
home_logo = image_utils.load_logo(league, game["home"])
|
||||||
|
away_logo = image_utils.load_logo(league, game["away"])
|
||||||
|
|
||||||
|
image_utils.draw_logo(canvas, away_logo, 0, 0)
|
||||||
|
image_utils.draw_logo(canvas, home_logo, 0, 16)
|
||||||
|
|
||||||
|
graphics.DrawText(
|
||||||
|
canvas,
|
||||||
|
data['fonts']['font_small'],
|
||||||
|
18,
|
||||||
|
11,
|
||||||
|
graphics.Color(*Colors.WHITE.value),
|
||||||
|
game["away"],
|
||||||
|
)
|
||||||
|
graphics.DrawText(
|
||||||
|
canvas,
|
||||||
|
data['fonts']['font_small'],
|
||||||
|
18,
|
||||||
|
27,
|
||||||
|
graphics.Color(*Colors.WHITE.value),
|
||||||
|
game["home"],
|
||||||
|
)
|
||||||
|
|
||||||
|
graphics.DrawText(
|
||||||
|
canvas,
|
||||||
|
data['fonts']['font'],
|
||||||
|
40,
|
||||||
|
13,
|
||||||
|
graphics.Color(*Colors.WHITE.value),
|
||||||
|
str(game["away_score"]),
|
||||||
|
)
|
||||||
|
graphics.DrawText(
|
||||||
|
canvas,
|
||||||
|
data['fonts']['font'],
|
||||||
|
40,
|
||||||
|
29,
|
||||||
|
graphics.Color(*Colors.WHITE.value),
|
||||||
|
str(game["home_score"]),
|
||||||
|
)
|
||||||
|
graphics.DrawText(
|
||||||
|
canvas,
|
||||||
|
data['fonts']['font'],
|
||||||
|
55,
|
||||||
|
22,
|
||||||
|
graphics.Color(*Colors.WHITE.value),
|
||||||
|
str(game["status"])
|
||||||
|
)
|
||||||
|
|
||||||
|
def run_board(canvas, matrix):
|
||||||
|
|
||||||
|
# preferred games
|
||||||
|
current_preferred_game = 0
|
||||||
|
preferred_games = []
|
||||||
|
preferred_teams = [
|
||||||
|
("BUF", "nfl"),
|
||||||
|
("BUF", "nhl"),
|
||||||
|
("TOR", "mlb"),
|
||||||
|
("LAL", "nba"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# data
|
||||||
|
games = []
|
||||||
|
last_fetch = 0
|
||||||
|
current_page = 0
|
||||||
|
page_display_time = 8
|
||||||
|
last_switch = time()
|
||||||
|
show_preferred = True
|
||||||
|
|
||||||
|
while true:
|
||||||
|
now = time()
|
||||||
|
|
||||||
|
if now - last_fetch > 30 or len(games) <= 0:
|
||||||
|
games = get_all_scores()
|
||||||
|
last_fetch = now
|
||||||
|
|
||||||
|
if games:
|
||||||
|
canvas.Clear()
|
||||||
|
# clear bad preferred games out
|
||||||
|
if len(preferred_games) > 0:
|
||||||
|
for preferred_game in preferred_games:
|
||||||
|
shown_game = [g for g in games if preferred_game == g['id']]
|
||||||
|
if len(shown_game) <= 0 or "Final" in shown_game[0]['status']:
|
||||||
|
preferred_games.remove(preferred_game)
|
||||||
|
|
||||||
|
# get new preferred games
|
||||||
|
for game in games:
|
||||||
|
if (game['away'], game['league']) in preferred_teams or (game['home'], game['league']) in preferred_teams:
|
||||||
|
if 'Final' not in game['status'] and game['id'] not in preferred_games:
|
||||||
|
preferred_games.append(game['id'])
|
||||||
|
|
||||||
|
print(preferred_games)
|
||||||
|
if now - last_switch > page_display_time:
|
||||||
|
last_switch = now
|
||||||
|
|
||||||
|
if show_preferred and len(preferred_games) > 0:
|
||||||
|
single_preferred_game = next(
|
||||||
|
(g for g in games if g['id'] == preferred_games[current_preferred_game]), None
|
||||||
|
)
|
||||||
|
if single_preferred_game:
|
||||||
|
print(f'Showing preferred game {single_preferred_game["home"]} vs {single_preferred_game["away"]}')
|
||||||
|
draw_single_game(canvas, single_preferred_game)
|
||||||
|
|
||||||
|
current_preferred_game += 1
|
||||||
|
if current_preferred_game >= len(preferred_games):
|
||||||
|
show_preferred = False
|
||||||
|
current_preferred_game = 0
|
||||||
|
current_page = 0
|
||||||
|
else:
|
||||||
|
print(f'Showing all games page {current_page} / {len(games)}')
|
||||||
|
draw_all_games(canvas, games, current_page)
|
||||||
|
current_page += 4
|
||||||
|
if current_page >= len(games):
|
||||||
|
current_page = 0
|
||||||
|
if len(preferred_games) > 0:
|
||||||
|
show_preferred = True
|
||||||
|
else:
|
||||||
|
canvas.Clear()
|
||||||
|
|
||||||
|
print('No games available')
|
||||||
|
|
||||||
|
# no games available, just draw placeholder
|
||||||
|
graphics.DrawText(canvas, data["fonts"]["font"], 10, 22, graphics.Color(*Colors.RED.value), "No games today")
|
||||||
|
|
||||||
|
canvas = matrix.SwapOnVSync(canvas)
|
||||||
|
sleep(10)
|
||||||
|
|
||||||
+18
-227
@@ -1,13 +1,13 @@
|
|||||||
import requests
|
|
||||||
import os
|
import os
|
||||||
import utils.govee as govee
|
import utils.govee as govee
|
||||||
import utils.image_utils as image_utils
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from time import sleep, time
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from rgbmatrix import RGBMatrix, RGBMatrixOptions, graphics
|
from rgbmatrix import RGBMatrix, RGBMatrixOptions, graphics
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# modes
|
||||||
|
import modes.score_mode as score_mode
|
||||||
|
|
||||||
# --- Load environment vars ---
|
# --- Load environment vars ---
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
@@ -16,6 +16,20 @@ SCRIPT_DIR = Path(__file__).parent.resolve()
|
|||||||
ASSET_DIR = os.path.join(SCRIPT_DIR, "assets")
|
ASSET_DIR = os.path.join(SCRIPT_DIR, "assets")
|
||||||
LOGO_DIR = os.path.join(ASSET_DIR, "logos")
|
LOGO_DIR = os.path.join(ASSET_DIR, "logos")
|
||||||
|
|
||||||
|
# --- importable data dict ---
|
||||||
|
data = {
|
||||||
|
"paths": {
|
||||||
|
"SCRIPT_DIR": SCRIPT_DIR,
|
||||||
|
"ASSET_DIR": ASSET_DIR,
|
||||||
|
"LOGO_DIR": LOGO_DIR
|
||||||
|
},
|
||||||
|
"fonts": {
|
||||||
|
"font": graphics.Font().LoadFont(os.path.join(ASSET_DIR, "fonts/7x13.bdf")),
|
||||||
|
"font_small": graphics.Font().LoadFont(os.path.join(ASSET_DIR, "fonts/5x7.bdf")),
|
||||||
|
"font_big": graphics.Font().LoadFont(os.path.join(ASSET_DIR, "fonts/9x18.bdf"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# --- Matrix config ---
|
# --- Matrix config ---
|
||||||
options = RGBMatrixOptions()
|
options = RGBMatrixOptions()
|
||||||
options.rows = 32
|
options.rows = 32
|
||||||
@@ -30,17 +44,6 @@ options.brightness = 80
|
|||||||
matrix = RGBMatrix(options=options)
|
matrix = RGBMatrix(options=options)
|
||||||
canvas = matrix.CreateFrameCanvas()
|
canvas = matrix.CreateFrameCanvas()
|
||||||
|
|
||||||
# --- Font initialization ---
|
|
||||||
font = graphics.Font()
|
|
||||||
font_small = graphics.Font()
|
|
||||||
font_big = graphics.Font()
|
|
||||||
font.LoadFont(os.path.join(ASSET_DIR, "fonts/7x13.bdf"))
|
|
||||||
font_small.LoadFont(os.path.join(ASSET_DIR, "fonts/5x7.bdf"))
|
|
||||||
font_big.LoadFont(os.path.join(ASSET_DIR, "fonts/9x18.bdf"))
|
|
||||||
|
|
||||||
# --- Logo cache ---
|
|
||||||
logo_cache = {}
|
|
||||||
|
|
||||||
# --- Pre-built colors ---
|
# --- Pre-built colors ---
|
||||||
class Colors(Enum):
|
class Colors(Enum):
|
||||||
WHITE = (255, 255, 255)
|
WHITE = (255, 255, 255)
|
||||||
@@ -59,223 +62,11 @@ if os.environ['GOVEE_API_KEY']:
|
|||||||
# pygame.mixer.music.load(os.path.join(ASSET_DIR, filename))
|
# pygame.mixer.music.load(os.path.join(ASSET_DIR, filename))
|
||||||
# pygame.mixer.music.play()
|
# pygame.mixer.music.play()
|
||||||
|
|
||||||
# --- Fetch scores ---
|
|
||||||
def get_scores(sport, league):
|
|
||||||
url = f"https://site.api.espn.com/apis/site/v2/sports/{sport}/{league}/scoreboard"
|
|
||||||
try:
|
|
||||||
resp = requests.get(url, timeout=5)
|
|
||||||
resp.raise_for_status()
|
|
||||||
games = []
|
|
||||||
for event in resp.json().get("events", []):
|
|
||||||
comp = event["competitions"][0]
|
|
||||||
teams = comp["competitors"]
|
|
||||||
home = next(t for t in teams if t["homeAway"] == "home")
|
|
||||||
away = next(t for t in teams if t["homeAway"] == "away")
|
|
||||||
status = event["status"]["type"]["shortDetail"]
|
|
||||||
games.append(
|
|
||||||
{
|
|
||||||
"league": league,
|
|
||||||
"away": away["team"]["abbreviation"].upper(),
|
|
||||||
"away_score": away["score"],
|
|
||||||
"home": home["team"]["abbreviation"].upper(),
|
|
||||||
"home_score": home["score"],
|
|
||||||
"status": status,
|
|
||||||
"id": event["id"],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return games
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Fetch error ({league}): {e}")
|
|
||||||
return []
|
|
||||||
|
|
||||||
def get_all_scores():
|
|
||||||
print('fetching game scores from espn')
|
|
||||||
games = []
|
|
||||||
games += get_scores("hockey", "nhl")
|
|
||||||
games += get_scores("football", "nfl")
|
|
||||||
games += get_scores("basketball", "nba")
|
|
||||||
games += get_scores("baseball", "mlb")
|
|
||||||
return games
|
|
||||||
|
|
||||||
# --- Game drawing ---
|
|
||||||
def draw_all_games(canvas, games, start_index):
|
|
||||||
for i in range(4):
|
|
||||||
game_index = (start_index + i) % len(games)
|
|
||||||
game = games[game_index]
|
|
||||||
offset = i * 64
|
|
||||||
|
|
||||||
league = game["league"]
|
|
||||||
away_logo = image_utils.load_logo(league, game["away"])
|
|
||||||
home_logo = image_utils.load_logo(league, game["home"])
|
|
||||||
|
|
||||||
image_utils.draw_logo(canvas, away_logo, offset + 0, 0)
|
|
||||||
image_utils.draw_logo(canvas, home_logo, offset + 0, 16)
|
|
||||||
|
|
||||||
graphics.DrawText(
|
|
||||||
canvas,
|
|
||||||
font_small,
|
|
||||||
offset + 18,
|
|
||||||
11,
|
|
||||||
graphics.Color(*Colors.RED.value),
|
|
||||||
game["away"],
|
|
||||||
)
|
|
||||||
graphics.DrawText(
|
|
||||||
canvas,
|
|
||||||
font_small,
|
|
||||||
offset + 18,
|
|
||||||
27,
|
|
||||||
graphics.Color(*Colors.WHITE.value),
|
|
||||||
game["home"],
|
|
||||||
)
|
|
||||||
|
|
||||||
graphics.DrawText(
|
|
||||||
canvas,
|
|
||||||
font,
|
|
||||||
offset + 40,
|
|
||||||
13,
|
|
||||||
graphics.Color(*Colors.WHITE.value),
|
|
||||||
str(game["away_score"]),
|
|
||||||
)
|
|
||||||
graphics.DrawText(
|
|
||||||
canvas,
|
|
||||||
font,
|
|
||||||
offset + 40,
|
|
||||||
29,
|
|
||||||
graphics.Color(*Colors.WHITE.value),
|
|
||||||
str(game["home_score"]),
|
|
||||||
)
|
|
||||||
|
|
||||||
if i < 3:
|
|
||||||
for row in range(32):
|
|
||||||
canvas.SetPixel(offset + 63, row, 40, 40, 40)
|
|
||||||
|
|
||||||
def draw_single_game(canvas, game):
|
|
||||||
league = game["league"]
|
|
||||||
home_logo = image_utils.load_logo(league, game["home"])
|
|
||||||
away_logo = image_utils.load_logo(league, game["away"])
|
|
||||||
|
|
||||||
image_utils.draw_logo(canvas, away_logo, 0, 0)
|
|
||||||
image_utils.draw_logo(canvas, home_logo, 0, 16)
|
|
||||||
|
|
||||||
graphics.DrawText(
|
|
||||||
canvas,
|
|
||||||
font_small,
|
|
||||||
18,
|
|
||||||
11,
|
|
||||||
graphics.Color(*Colors.WHITE.value),
|
|
||||||
game["away"],
|
|
||||||
)
|
|
||||||
graphics.DrawText(
|
|
||||||
canvas,
|
|
||||||
font_small,
|
|
||||||
18,
|
|
||||||
27,
|
|
||||||
graphics.Color(*Colors.WHITE.value),
|
|
||||||
game["home"],
|
|
||||||
)
|
|
||||||
|
|
||||||
graphics.DrawText(
|
|
||||||
canvas,
|
|
||||||
font,
|
|
||||||
40,
|
|
||||||
13,
|
|
||||||
graphics.Color(*Colors.WHITE.value),
|
|
||||||
str(game["away_score"]),
|
|
||||||
)
|
|
||||||
graphics.DrawText(
|
|
||||||
canvas,
|
|
||||||
font,
|
|
||||||
40,
|
|
||||||
29,
|
|
||||||
graphics.Color(*Colors.WHITE.value),
|
|
||||||
str(game["home_score"]),
|
|
||||||
)
|
|
||||||
graphics.DrawText(
|
|
||||||
canvas,
|
|
||||||
font,
|
|
||||||
55,
|
|
||||||
22,
|
|
||||||
graphics.Color(*Colors.WHITE.value),
|
|
||||||
str(game["status"])
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- Main loop ---
|
# --- Main loop ---
|
||||||
def run():
|
def run():
|
||||||
global canvas
|
global canvas
|
||||||
games = []
|
|
||||||
last_fetch = 0
|
|
||||||
current_page = 0
|
|
||||||
page_display_time = 8
|
|
||||||
last_switch = time()
|
|
||||||
show_preferred = True
|
|
||||||
|
|
||||||
# preferred games
|
score_mode(canvas, matrix)
|
||||||
current_preferred_game = 0
|
|
||||||
preferred_games = []
|
|
||||||
preferred_teams = [
|
|
||||||
("BUF", "nfl"),
|
|
||||||
("BUF", "nhl"),
|
|
||||||
("TOR", "mlb"),
|
|
||||||
("LAL", "nba"),
|
|
||||||
]
|
|
||||||
|
|
||||||
while True:
|
|
||||||
now = time()
|
|
||||||
|
|
||||||
if now - last_fetch > 30 or len(games) <= 0:
|
|
||||||
games = get_all_scores()
|
|
||||||
last_fetch = now
|
|
||||||
|
|
||||||
if games:
|
|
||||||
canvas.Clear()
|
|
||||||
# clear bad preferred games out
|
|
||||||
if len(preferred_games) > 0:
|
|
||||||
for preferred_game in preferred_games:
|
|
||||||
shown_game = [g for g in games if preferred_game == g['id']]
|
|
||||||
if len(shown_game) <= 0 or "Final" in shown_game[0]['status']:
|
|
||||||
preferred_games.remove(preferred_game)
|
|
||||||
|
|
||||||
# get new preferred games
|
|
||||||
for game in games:
|
|
||||||
if (game['away'], game['league']) in preferred_teams or (game['home'], game['league']) in preferred_teams:
|
|
||||||
if 'Final' not in game['status'] and game['id'] not in preferred_games:
|
|
||||||
preferred_games.append(game['id'])
|
|
||||||
|
|
||||||
print(preferred_games)
|
|
||||||
if now - last_switch > page_display_time:
|
|
||||||
last_switch = now
|
|
||||||
|
|
||||||
if show_preferred and len(preferred_games) > 0:
|
|
||||||
single_preferred_game = next(
|
|
||||||
(g for g in games if g['id'] == preferred_games[current_preferred_game]), None
|
|
||||||
)
|
|
||||||
if single_preferred_game:
|
|
||||||
print(f'Showing preferred game {single_preferred_game["home"]} vs {single_preferred_game["away"]}')
|
|
||||||
draw_single_game(canvas, single_preferred_game)
|
|
||||||
|
|
||||||
current_preferred_game += 1
|
|
||||||
if current_preferred_game >= len(preferred_games):
|
|
||||||
show_preferred = False
|
|
||||||
current_preferred_game = 0
|
|
||||||
current_page = 0
|
|
||||||
else:
|
|
||||||
print(f'Showing all games page {current_page} / {len(games)}')
|
|
||||||
draw_all_games(canvas, games, current_page)
|
|
||||||
current_page += 4
|
|
||||||
if current_page >= len(games):
|
|
||||||
current_page = 0
|
|
||||||
if len(preferred_games) > 0:
|
|
||||||
show_preferred = True
|
|
||||||
else:
|
|
||||||
canvas.Clear()
|
|
||||||
|
|
||||||
print('No games available')
|
|
||||||
|
|
||||||
# no games available, just draw placeholder
|
|
||||||
graphics.DrawText(canvas, font, 10, 22, graphics.Color(*Colors.RED.value), "No games today")
|
|
||||||
|
|
||||||
canvas = matrix.SwapOnVSync(canvas)
|
|
||||||
sleep(10)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run()
|
run()
|
||||||
|
|||||||
Reference in New Issue
Block a user