399 Commits
v2 ... v2.3

Author SHA1 Message Date
Chuck
19edd9ace0 Merge development branch into main - resolved conflict in ncaa_fb_managers.py 2025-09-12 19:21:28 -04:00
Chuck
0982ef78dd clean config 2025-09-12 19:18:20 -04:00
Chuck
5695d8e017 minor fixes 2025-09-12 19:09:43 -04:00
Chuck
06ad446925 update stock call method 2025-09-12 18:57:39 -04:00
Chuck
6b5a9cdff7 disable calendar for test 2025-09-12 18:56:05 -04:00
Chuck
efb66118e4 full test of most display modes 2025-09-12 18:53:38 -04:00
Chuck
2444aa2fc9 manual buffer on odds ticker to finish the scroll 2025-09-12 18:52:27 -04:00
Chuck
93f6173efa apply leaderboard duration logic to odds manager 2025-09-12 18:49:33 -04:00
Chuck
dc81d48ab1 new TAANDM logo 2025-09-12 18:46:34 -04:00
Chuck
5c32be929e shorten buffer for one perfect loop 2025-09-12 18:43:15 -04:00
Chuck
105f60f57e disable odds 2025-09-12 18:40:00 -04:00
Chuck
a52130cedb brute forcing math for scroll speed 2025-09-12 18:39:31 -04:00
Chuck
d08e7953f2 improve math on dynamic duration for leaderboard 2025-09-12 18:34:35 -04:00
Chuck
d7544b04dd add rankings to odds ticker team names 2025-09-12 18:32:33 -04:00
Chuck
0291540df4 update width calculation for leaderboard duration. Reduce log spam 2025-09-12 18:27:52 -04:00
Chuck
27b9b0267b current x postion tracking update for leaderboard 2025-09-12 18:21:10 -04:00
Chuck
cffef0d161 leaderboard debugging 2025-09-12 18:14:37 -04:00
Chuck
b5cb71b68d enable loop for scrolling dynamic displays 2025-09-12 18:12:02 -04:00
Chuck
7685586508 web ui updates for leaderboard and odds manager timeout if APi call limit is hit 2025-09-12 18:08:46 -04:00
Chuck
b8aaa56b4b Add NCAA football logo download script and update team abbreviations
- Added download_espn_ncaa_fb_logos.py script to download logos from ESPN API
- Downloaded 50 NCAA football team logos to test/ncaaFBlogos/
- Updated all_team_abbreviations.txt with current ESPN team data
- Updated various team logo files (MLB, NBA, NFL, NHL, NCAAF)
2025-09-12 18:01:43 -04:00
Chuck
4aa307c8dd dynamic duration buffer adjustment 2025-09-12 17:57:06 -04:00
Chuck
12b99024a4 leaderboard spacing update 2025-09-12 17:54:40 -04:00
Chuck
22f0e29315 leaderboard spacing calculation update 2025-09-12 17:45:52 -04:00
Chuck
6eeba92350 disable dynamic duration leaderboard 2025-09-12 17:40:52 -04:00
Chuck
286ba2b044 disable loop 2025-09-12 17:39:20 -04:00
Chuck
4b5a1e41d8 update font for leaderboard 2025-09-12 17:34:33 -04:00
Chuck
008705b75c re-enable two leagues for leaderboard 2025-09-12 17:29:51 -04:00
Chuck
5937f968ef change duration buffer on odds ticker 2025-09-12 17:28:11 -04:00
Chuck
4fe5547bf8 test with just one league for leaderboard 2025-09-12 17:25:25 -04:00
Chuck
96f6749516 change width draw logic in leaderboard display 2025-09-12 17:21:20 -04:00
Chuck
bc3883df14 config manager reductions to reduce overhead 2025-09-12 17:15:45 -04:00
Chuck
32b1b8020a specific leaderboard logging 2025-09-12 15:39:20 -04:00
Chuck
9280295ed3 leaderboard debugging 2025-09-12 15:19:03 -04:00
Chuck
e5a29d4668 dynamic duration for odds ticker has larger buffer 2025-09-12 15:15:22 -04:00
Chuck
4cfaa5ca59 reduce logging for leaderboard dynamic duration 2025-09-12 15:13:13 -04:00
Chuck
6f894a587b league data key added to leaderboard image calculation 2025-09-12 15:10:17 -04:00
Chuck
35eb9cbdb5 better handling for png transparency in broadcast logos 2025-09-12 15:08:22 -04:00
Chuck
2d41c5ca31 leaderboard improvements and timing update 2025-09-12 15:06:08 -04:00
Chuck
14f7a8b502 improce caching for leaderboard 2025-09-12 15:02:33 -04:00
Chuck
5101795cbf handle special characters in team names (TA&M A&M) 2025-09-12 14:55:18 -04:00
Chuck
6d0632acee logo downloader for FCS teams is more robust 2025-09-12 14:50:19 -04:00
Chuck
9298eff554 smoother leaderboard scrolling 2025-09-12 13:37:19 -04:00
Chuck
335ab8cce0 update leaderboard data sources for other sports and font sizes 2025-09-12 13:35:01 -04:00
Chuck
32daced427 update logic on odds ticker dynamic duration 2025-09-12 12:10:50 -04:00
Chuck
153edcc2e1 update record & rank logic, update leaderboard font and logo sizes 2025-09-12 12:08:46 -04:00
Chuck
548bc00e00 use correct AP Poll top 25 for NCAAFB 2025-09-12 11:50:51 -04:00
Chuck
f8ab022da9 add dynamic duration to leaderboard 2025-09-10 22:54:24 -04:00
Chuck
cd80745dcb update height references 2025-09-10 22:32:25 -04:00
Chuck
56dfbda40a update leaderboard layout 2025-09-10 22:12:33 -04:00
Chuck
591555c3c7 make sure leaderboard is scrolling horizontally to show all teams 2025-09-10 21:56:29 -04:00
Chuck
bbabad3135 adjustment on leaderboard 2025-09-10 21:28:30 -04:00
Chuck
3329822a46 update tnt logo 2025-09-10 18:21:03 -04:00
Chuck
413a1fa38c update cbs logo 2025-09-10 18:19:11 -04:00
Chuck
3ee7821353 update some broadcast logos and fix multiple stacked panels logic 2025-09-10 18:13:42 -04:00
Chuck
20a816f3e6 update sports logo 2025-09-10 17:01:05 -04:00
Chuck
457f9f9eb5 better error handling and correct image call for top 25 2025-09-10 16:45:34 -04:00
Chuck
39519dbfff enable leaderboard for testing 2025-09-10 13:20:15 -04:00
Chuck
61a56560f3 adjust odds manager mlb spacing 2025-09-10 13:19:45 -04:00
Chuck
c1ccd6f44a fix leaderboard manager import 2025-09-10 13:16:42 -04:00
Chuck
2123f78dad adjust spacing in Odds Manager ticker when Baseball is live, to reduce space between graphic and gameplay stats 2025-09-10 13:12:57 -04:00
Chuck
a1914980c8 Update issue templates 2025-09-04 23:03:10 -04:00
ChuckBuilds
a3dbc6a4a8 standardize config init across displays 2025-09-04 22:24:02 -04:00
ChuckBuilds
8a0fdb005d update UTC timezone logic to check config settings for all managers 2025-09-04 22:18:01 -04:00
Scott Raynor
f13ad238eb Add ability to try to download NCAA football logos not found in the assets folder from the ESPN API. (#15)
Co-authored-by: J. Scott Raynor <jsraynor@gmail.com>
2025-09-01 13:33:35 -04:00
ChuckBuilds
92071237c1 listing all missing team logos 2025-08-19 17:40:09 -05:00
ChuckBuilds
52c2d61dcf Fix odds ticker black display issue when returning to rotation
- Reset display start time when force_clear is True or when starting fresh
- Reset scroll position for clean start when display is reset
- Add check for old display start time and reset if it's more than 2x dynamic duration
- Prevents the odds ticker from staying black when it comes back into rotation
- Ensures proper state management between display sessions
2025-08-18 21:50:38 -05:00
ChuckBuilds
73036c33cb Reduce spacing around bases diamond for tighter layout
- Moved bases to right edge of odds column to be closer to inning indicator
- Reduced horizontal spacing from 10px to 8px between bases
- Reduced vertical spacing from 8px to 6px for more compact diamond
- Updated cluster width from 26px to 24px to match tighter spacing
- Adjusted positioning offset from 13px to 12px for proper centering
- Bases now positioned closer to the inning indicator for better visual flow
2025-08-18 21:46:57 -05:00
ChuckBuilds
d6eb7a778c Update odds ticker bases to match MLB manager style
- Changed from circular bases to diamond-shaped bases (polygons)
- Increased base size from 6px to 8px to match MLB manager
- Increased spacing from 8px to 10px for better visibility
- Added proper cluster positioning and sizing calculations
- Shifted bases down 2 pixels from center for better positioning
- Increased minimum width to 30px to accommodate larger base cluster
- Now uses same diamond-shaped base style as MLB manager for consistency
2025-08-18 21:41:14 -05:00
ChuckBuilds
62b50cc06f fix display start time on odds ticker and added amazon prime video logo to broadcast 2025-08-18 21:35:54 -05:00
ChuckBuilds
05bee6ce84 Replace odds text section with centered graphical bases for baseball
- Removed text-based odds display for baseball live games entirely
- Graphical bases now replace the entire odds section (not just overlay it)
- Bases are properly centered vertically on the display (height // 2)
- Bases are centered horizontally within the odds column width
- Creates cleaner, more focused display with bases as the main visual element
2025-08-18 21:31:58 -05:00
ChuckBuilds
2c2d24c0a8 Fix missing datetime variables for baseball live games
- Added back day_text, date_text, and time_text variables for baseball live games
- These variables are needed for the datetime display section
- Shows inning (▲5), count (2-1), and outs (2 outs) in the datetime column
- Fixes the 'cannot access local variable' error that was occurring
2025-08-18 21:01:39 -05:00
ChuckBuilds
b252229e03 adjust live bases on the odds ticker 2025-08-18 20:55:50 -05:00
ChuckBuilds
8f7aeee546 Fix graphical base positioning and remove old text display
- Removed old text-based bases display code that was still showing
- Fixed positioning calculation for graphical bases to center properly
- Added bounds checking to prevent bases from overlapping off display
- Bases are now properly centered in the odds column with appropriate spacing
- Cleaned up baseball live game display to show only count, outs, and graphical bases
2025-08-18 20:44:48 -05:00
ChuckBuilds
b7fa2f1df6 Add graphical base indicators to odds ticker for baseball live games
- Added _draw_base_indicators() method similar to MLB manager
- Replaced text-based bases display with graphical diamond representation
- Shows diamond outline with filled circles for occupied bases
- Displays count and outs as text while showing bases graphically
- Creates more visual and intuitive representation of game state
- Uses smaller size (6px) and spacing (8px) appropriate for odds ticker
2025-08-18 19:54:13 -05:00
ChuckBuilds
ba3b79dd72 adjust spacing on live game scores 2025-08-18 19:48:14 -05:00
ChuckBuilds
e4e058ff97 Fix outs pluralization in odds ticker live baseball games
- Changed outs display to use proper pluralization:
  - '1 out' for single out
  - '2 outs', '3 outs' for multiple outs
- This makes the live game information more grammatically correct and readable
2025-08-18 19:47:23 -05:00
ChuckBuilds
0b42cec902 Fix odds ticker mid-scroll cutoff issue
- Modified calculate_dynamic_duration() to add extra buffer time when looping is enabled
- Added 20% extra buffer for looping to ensure smooth transitions
- Added logic to detect when display is ending and reset scroll position for clean transitions
- Added display start time tracking to manage duration properly
- This prevents the odds ticker from cutting off mid-scroll when switching modes
2025-08-18 19:46:20 -05:00
ChuckBuilds
35ad842ba1 adjust spacing on live odds outs 2025-08-18 19:43:27 -05:00
ChuckBuilds
08cf4152f7 Improve odds ticker live game display formatting
- Removed parentheses around scores for live games (e.g., 'Team 5' instead of 'Team (5)')
- Improved bases section for baseball games:
  - Changed from '1', '2', '3' to '1B', '2B', '3B' for clarity
  - Changed from '---' to 'Empty' when no bases are occupied
  - This makes it much clearer what the information represents
- Live games now show cleaner, more readable score format
2025-08-18 19:42:30 -05:00
ChuckBuilds
71a392737e Add comprehensive debug logging for odds ticker dynamic duration
- Added debug logging to _fetch_upcoming_games() to track data fetching
- Added debug logging to _create_ticker_image() to track image creation
- Added logging for favorite teams, odds filtering, and game counts
- Added logging for total_scroll_width calculation
- This will help identify why dynamic duration is falling back to minimum
2025-08-18 19:26:12 -05:00
ChuckBuilds
2b93eafcdf improve odds ticker dynamic duration 2025-08-18 19:23:20 -05:00
ChuckBuilds
3c1706d4e8 Fix odds ticker dynamic duration timing issue
- Modified get_dynamic_duration() to trigger update when total_scroll_width is 0
- This ensures the dynamic duration is calculated with actual data before being used
- Prevents fallback to minimum duration (30s) when odds ticker hasn't updated yet
- Added debug logging to track when updates are triggered for duration calculation
2025-08-18 19:13:54 -05:00
ChuckBuilds
e4b3adb867 Fix test script to handle missing game data keys
- Added safe key access using .get() method with defaults
- Added display of available keys in game data for debugging
- Added sport field display to help identify data structure
- This prevents KeyError when game data structure changes
2025-08-18 19:09:50 -05:00
ChuckBuilds
9f00124fad Fix odds ticker dynamic duration calculation
- Fixed double-counting of display width in total_scroll_width calculation
- Added detailed debug logging for dynamic duration calculation
- Added debug logging for scrolling behavior and loop resets
- Created test script for debugging dynamic duration issues
- The issue was that total_scroll_width included display width, causing
  incorrect duration calculations that resulted in early cutoff
2025-08-18 19:05:36 -05:00
ChuckBuilds
68416d0293 live games in odds ticker 2025-08-18 15:50:23 -05:00
ChuckBuilds
e63198dc49 scroll priority to determine data refreshes 2025-08-18 15:21:39 -05:00
ChuckBuilds
a5ce721733 improve filtering on show_favorite_teams_only 2025-08-15 10:14:33 -05:00
ChuckBuilds
e3b65588a2 support older versions of python not having the Union import 2025-08-15 09:38:23 -05:00
ChuckBuilds
f13e9306c9 more fallback errors for milb fonts 2025-08-14 16:46:48 -05:00
ChuckBuilds
ef82610a06 milb font error handling 2025-08-14 13:39:48 -05:00
ChuckBuilds
18145edbf1 default games to show 1 2025-08-14 13:02:23 -05:00
ChuckBuilds
54635fee3c ensure game rotation count respects user defined variable 2025-08-14 13:01:23 -05:00
ChuckBuilds
6152969340 fix favorite team toggle logic being skipped 2025-08-14 12:26:57 -05:00
Chuck
8770e5a327 update readme to use install script 2025-08-13 21:59:16 -05:00
Chuck
822d9909ed apply fix to mlb 2025-08-13 21:49:19 -05:00
Chuck
d179700c6c Removed the problematic os.path.dirname(os.path.abspath(__file__)) pattern 2025-08-13 21:35:53 -05:00
Chuck
dfecc6f8a0 loading fonts va absolute paths 2025-08-13 21:23:37 -05:00
Chuck
0d8d4084a9 overzealous with the font change, rolling some back 2025-08-13 20:54:16 -05:00
Chuck
6bc1039ed6 change how font is loaded via systemctl - added direct paths 2025-08-13 20:36:23 -05:00
Chuck
8e1b04550b allow werkzeug to work in our environment 2025-08-13 17:32:08 -05:00
Chuck
33e1f05f77 update first time install script 2025-08-13 17:15:24 -05:00
Chuck
c4113367f7 default config set 2025-08-13 15:46:20 -05:00
Chuck
4b906b3a92 remove autostart of dsiplay from autostart of web ui 2025-08-13 14:59:49 -05:00
Chuck
06d8360922 web autostart troubleshooting 2025-08-13 14:45:56 -05:00
Chuck
9d4082665a graceful font fallback 2025-08-13 12:53:11 -05:00
Chuck
a3481f3674 permission handling in first time install script 2025-08-13 12:13:41 -05:00
Chuck
e36d92340e more robust first time install script, ensure it creates config_secrets 2025-08-13 11:36:59 -05:00
Chuck
6225189b3c more robust font loading for OTD manager 2025-08-13 10:23:43 -05:00
Chuck
6c658c23c4 disable google calendar by default 2025-08-13 09:52:53 -05:00
Chuck
30cf8ee2e8 make the first time install script more inclusive of user actions 2025-08-12 17:42:22 -05:00
Chuck
2526c6097e update docs 2025-08-12 10:23:22 -05:00
Chuck
1e0889fe84 cleanup 2025-08-11 18:24:23 -05:00
Chuck
ba0716d37e update readme 2025-08-11 18:20:23 -05:00
Chuck
b8d9eb65f6 clean up milb upcoming 2025-08-11 18:00:40 -05:00
Chuck
03f0a6e6e2 troubleshoot milb upcoming 2025-08-11 17:25:03 -05:00
Chuck
5971e4afa1 troubleshooting autostart for web ui v2 2025-08-11 16:28:04 -05:00
Chuck
dc840b63d8 trying to improve on demand display 2025-08-11 16:01:16 -05:00
Chuck
865b30c631 reduce log spam 2025-08-11 15:45:19 -05:00
Chuck
da17f214da improve stop on demand 2025-08-11 15:21:20 -05:00
Chuck
643397c939 added first_time_install script 2025-08-11 14:22:54 -05:00
Chuck
1704001ef6 ensure web ui actions work and web interface is starting without venv 2025-08-11 14:12:17 -05:00
Chuck
18d6758dbe web sudo script 2025-08-11 14:02:43 -05:00
Chuck
19f5b7e3bc remove venv from web v2 2025-08-11 11:35:43 -05:00
Chuck
28c81825cc remove venv from web v2 2025-08-11 11:27:03 -05:00
Chuck
151777fbd6 update requirements for web ui 2025-08-10 21:22:36 -05:00
Chuck
8a8e3c21cb update service to autostart web ui 2025-08-10 20:53:33 -05:00
Chuck
809cb07bb8 on demand displays 2025-08-10 20:46:41 -05:00
Chuck
edce5fae85 milb upcoming game debug logging 2025-08-10 18:26:25 -05:00
Chuck
10c1342bdb milb upcoming game debug logging 2025-08-10 17:38:56 -05:00
Chuck
ede82406fa set web ui v2 to be default 2025-08-10 17:18:59 -05:00
Chuck
6ff8d8b5af display preview error handling 2025-08-10 16:27:49 -05:00
Chuck
bd7d136504 bdf double baseline issue 2025-08-10 16:20:21 -05:00
Chuck
f8ebcffa08 add api counter 2025-08-10 16:17:51 -05:00
Chuck
eed64334e3 improvements 2025-08-10 16:02:56 -05:00
Chuck
2bee99f9cc added shutdown to actions tab, enabled some more displays, changed baseball to non-priority 2025-08-10 15:45:06 -05:00
Chuck
35dcf76689 web preview display improvements 2025-08-10 15:33:51 -05:00
Chuck
1f7285cfc4 web preview fixes 2025-08-10 13:33:51 -05:00
Chuck
4f1736fb0f web action simplification 2025-08-10 13:17:53 -05:00
Chuck
0229567156 web action permission changes 2025-08-10 12:59:07 -05:00
Chuck
87daddbeb2 web action permission changes 2025-08-10 12:52:27 -05:00
Chuck
c284b9c26c web v2 command updates 2025-08-10 12:37:41 -05:00
Chuck
95e3e4dda4 live preview updates to formatting 2025-08-10 12:31:12 -05:00
Chuck
d95e6539e3 live preview troubleshooting 2025-08-10 12:14:53 -05:00
Chuck
a49feb2971 change web ui v2 server side loading 2025-08-10 12:02:33 -05:00
Chuck
8b7ae3beed web ui v2 improvements 2025-08-10 11:43:28 -05:00
Chuck
0a0fbbbdbb remove extra spacing on score 2025-08-10 11:07:00 -05:00
Chuck
ca44097669 update ncaa FB and NFL recent games to look more like other displays 2025-08-10 11:05:03 -05:00
Chuck
c0c77f6762 show fav teams only nfl 2025-08-09 22:39:16 -05:00
Chuck
b7ba899df7 adjust ball & strike count in mlb display 2025-08-09 22:38:40 -05:00
Chuck
9b4bf36dbb test favorite teams false 2025-08-09 21:01:11 -05:00
Chuck
85d63243c7 AI bug squash sesh 2025-08-09 21:00:25 -05:00
Chuck
79cbc46f9b set soccer logging to info 2025-08-09 20:45:56 -05:00
Chuck
bd9fe652d9 only call update module for active displays 2025-08-09 20:44:31 -05:00
Chuck
dac7b34228 fix show_favorite_teams_only false logic 2025-08-09 20:36:37 -05:00
Chuck
8703c485bc live priority rotation fix 2025-08-09 20:31:47 -05:00
Chuck
29f36827ca adjust score spacing soccer 2025-08-09 20:21:35 -05:00
Chuck
6fdb2b55b5 improved sport switching on simultaneous displays 2025-08-09 20:17:54 -05:00
Chuck
6a2e5edf2e more robust half time detection 2025-08-09 20:06:25 -05:00
Chuck
938c31c815 adjust MLS half detection 2025-08-09 20:03:44 -05:00
Chuck
d0ead60421 adjust NFL quarter logic 2025-08-09 19:57:17 -05:00
Chuck
e0883eeae2 adjust NFL recent score spacing 2025-08-09 17:17:17 -05:00
Chuck
b0941641c7 added dynamic display durations to scrolling managers 2025-08-09 17:15:14 -05:00
Chuck
8654dd44e6 all sports managers process recent and upcoming games as a function of game count instead of time (hours). Ensure all sports managers respect favorite team filtering if enabled 2025-08-09 16:47:38 -05:00
Chuck
afb7e23fcc fix soccer timezone 2025-08-09 16:03:02 -05:00
Chuck
1ffe3e7c16 add favorite team filtering to soccer manager and ensure timezones are respected 2025-08-09 15:54:15 -05:00
Chuck
7c0934cd9b non-priority live game setting change 2025-08-09 15:38:57 -05:00
Chuck
e5eef1320d milb live game check extended to 5 minutes 2025-08-09 14:20:08 -05:00
Chuck
5ec9b3ea6f case insensitive soccer logos 2025-08-09 14:17:05 -05:00
Chuck
708e993f41 soccer game extraction improvement 2025-08-09 14:09:05 -05:00
Chuck
fd68777484 enable NFL recent 2025-08-09 14:00:44 -05:00
Chuck
d616dddac0 enable soccer 2025-08-09 14:00:01 -05:00
Chuck
7b31c4cca5 milb deduplication 2025-08-09 13:55:34 -05:00
Chuck
be94e9fb6b decision flag debug logging for when games are rejected MILB 2025-08-09 13:48:52 -05:00
Chuck
1b9981d74e try to handle incorrect api data from milb 2025-08-09 13:42:04 -05:00
Chuck
f1ad263849 got duplicate live feeds for milb 2025-08-09 13:38:23 -05:00
Chuck
d802adb048 updates to milb live descriptors 2025-08-09 13:32:22 -05:00
Chuck
71bb616b76 changes to fildering and processing of MILB live games 2025-08-09 13:26:18 -05:00
Chuck
3ba0ec2041 milb live logic change 2025-08-09 13:17:10 -05:00
Chuck
40576ac18d shorten live check for milbLive Manager 2025-08-09 13:09:48 -05:00
Chuck
e6fa83904b pull live games even if missing inning info 2025-08-09 13:05:49 -05:00
Chuck
a52696aae2 milb update interval 2025-08-09 12:46:12 -05:00
Chuck
e9ca9a0454 milb upcoming type error 2025-08-09 12:22:34 -05:00
Chuck
7d38bbb0fa display update improvements and less logging 2025-08-09 12:03:56 -05:00
Chuck
512ffb7639 live games respect update durations from config 2025-08-09 12:00:12 -05:00
Chuck
cc652472a0 improved game filtering milb 2025-08-09 11:47:20 -05:00
Chuck
4cc3b39ce6 cache manager revamp 2025-08-09 11:42:51 -05:00
Chuck
fabb9bd611 cache key logic updates 2025-08-09 11:15:01 -05:00
Chuck
436bdbd8f2 milb debugging around strikes an dballs. 2025-08-09 11:10:19 -05:00
Chuck
d6ca83f090 disable soccer to focus on milb live 2025-08-09 11:05:27 -05:00
Chuck
96de2e7d0f milb debugging 2025-08-09 11:04:39 -05:00
Chuck
ec922fac2c manual cache management 2025-08-09 10:46:14 -05:00
Chuck
b4d5aef876 milb logging and manual cache clearing 2025-08-09 10:44:58 -05:00
Chuck
a672abba6a soccer logger update 2025-08-09 10:35:56 -05:00
Chuck
b193e03be9 milb_manager live display logic update and enable mls 2025-08-09 10:30:01 -05:00
Chuck
4088807c72 milb_manager cache test 2025-08-09 10:22:56 -05:00
Chuck
f02ed06e09 update milb gamedate filed 2025-08-02 20:16:10 -05:00
Chuck
ac69569d77 logging for why milb api isn't working and cache updates to odds cache storage 2025-08-02 20:02:52 -05:00
Chuck
13a2ef6e5e fix number of arguments called for config 2025-08-02 19:45:33 -05:00
Chuck
c490c5dca8 ensure displays share config file 2025-08-02 19:33:24 -05:00
Chuck
24204c581e milb config error 2025-08-02 17:49:19 -05:00
Chuck
881a46867d milb combined live game status mapping that was causing confusion 2025-08-02 17:41:37 -05:00
Chuck
3c665c21d1 milb turn off test mode.... 2025-08-02 17:31:35 -05:00
Chuck
f95138d1a4 milb diagnosis script with error fixes 2025-08-01 17:56:53 -05:00
Chuck
04009f78f7 milb diagnosis 2025-08-01 17:52:06 -05:00
Chuck
45f449d371 slow down scrolling 2025-07-31 22:52:37 -05:00
Chuck
d8e2de927a weather api error handling 2025-07-31 22:51:42 -05:00
Chuck
f67348b9b8 Scroll delay changes 2025-07-31 22:42:57 -05:00
Chuck
c92eaa93bd Merge cursor/modernize-and-enhance-led-matrix-web-interface-24d0 into development 2025-07-31 22:27:30 -05:00
Chuck
8411e4ff76 news manager font change 2025-07-31 22:12:47 -05:00
Chuck
b451d5def8 Respect live game display duration when no priority is given 2025-07-31 21:52:21 -05:00
Chuck
a6f8237069 adjust milb use of cache 2025-07-30 17:18:25 -05:00
Chuck
ceb6d5fdac set milb to priority 2025-07-30 16:49:37 -05:00
Chuck
41ed6b8a43 call managers differently 2025-07-30 16:37:05 -05:00
Chuck
06a51b5799 non-priority live game logic update 2025-07-30 16:11:48 -05:00
Chuck
5001e59ee3 non-priority live game error 2025-07-30 15:53:51 -05:00
Chuck
85747edff1 non-priority rotation fix 2025-07-30 15:15:06 -05:00
Chuck
fb4b950148 Merge branch 'cursor/modernize-and-enhance-led-matrix-web-interface-24d0' of https://github.com/ChuckBuilds/LEDMatrix into cursor/modernize-and-enhance-led-matrix-web-interface-24d0 2025-07-30 14:23:15 -05:00
Chuck
a2988557de better log messaging about what display going to and from 2025-07-30 14:22:17 -05:00
Chuck
f554e35686 Merge branch 'agent' into cursor/modernize-and-enhance-led-matrix-web-interface-24d0
Signed-off-by: Chuck <33324927+ChuckBuilds@users.noreply.github.com>
2025-07-30 13:14:36 -05:00
Chuck
dbcfbcd0f2 change espn logo 2025-07-30 12:33:32 -05:00
Chuck
27b52466ad fix scroll logic in news manager 2025-07-30 11:57:41 -05:00
Cursor Agent
20082cbadf Enhance LED Matrix web interface with comprehensive config and monitoring
Co-authored-by: charlesmynard <charlesmynard@gmail.com>
2025-07-28 03:08:55 +00:00
Chuck
4a7138205c fix error in web v2 2025-07-27 21:12:55 -05:00
Chuck
6ae4451c51 fix error in web v2 2025-07-27 21:10:27 -05:00
Chuck
7f17d8cd8f fix error in web v2 2025-07-27 21:07:17 -05:00
Chuck
0f6e3c9497 fix error in web v2 2025-07-27 21:00:49 -05:00
Chuck
88078111b4 venv requirements 2025-07-27 20:55:43 -05:00
Chuck
0601a9fda7 new strategy to draw news manager 2025-07-27 13:19:10 -05:00
Chuck
05d9f7c057 cant find why its not scrolling faster 2025-07-27 13:10:07 -05:00
Chuck
34903dd979 Scroll delay check 2025-07-27 13:03:57 -05:00
Chuck
3ba317c4e4 Add scroll control to news manager 2025-07-27 13:01:02 -05:00
Chuck
6bbb4f5de8 trying to make news scroll smoother 2025-07-27 12:56:17 -05:00
Chuck
4ab4d14a4e adjusting news manager scroll speed 2025-07-27 12:42:12 -05:00
Cursor Agent
d9e5b9404d Add modern web interface v2 for LED Matrix display control
Co-authored-by: charlesmynard <charlesmynard@gmail.com>
2025-07-27 15:32:48 +00:00
Chuck
e5d4f3c9f0 playing with scroll speed for news manager 2025-07-27 10:25:47 -05:00
Chuck
46ba9b4c4a added font logging to news manager 2025-07-27 10:20:23 -05:00
Chuck
9b6231915a change font 2025-07-27 10:19:30 -05:00
Chuck
6d8e7abff7 reduce dynamic duration logging 2025-07-27 10:14:55 -05:00
Chuck
932b263c5a news ticker scroll speed change 2025-07-27 10:10:45 -05:00
Chuck
aef8b3b6cc remove dynamic duration calculation from startup loop 2025-07-27 10:08:03 -05:00
Chuck
be50fb86d7 adjust display controller loop of news 2025-07-27 10:06:15 -05:00
Chuck
73d2248ccb fix news loop 2025-07-27 10:02:32 -05:00
Chuck
48937855d4 fix display_image error 2025-07-27 10:00:50 -05:00
Chuck
802e596f06 fix display width error for news_manager 2025-07-27 09:58:37 -05:00
Chuck
b6751a94c2 Sports news ticker with dynamic headline scrolling (#9)
* Add news manager with RSS feed ticker and dynamic scrolling

Co-authored-by: charlesmynard <charlesmynard@gmail.com>

* Add F1 feeds, custom feed management script, and comprehensive feed guide

Co-authored-by: charlesmynard <charlesmynard@gmail.com>

* Remove emoji and improve error/success message formatting

Co-authored-by: charlesmynard <charlesmynard@gmail.com>

* Add dynamic duration feature for news display with configurable timing

Co-authored-by: charlesmynard <charlesmynard@gmail.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2025-07-27 09:53:19 -05:00
Chuck
8b0c71dbdf new display logic for non-priority games 2025-07-26 20:42:56 -05:00
Chuck
2f7fa481a3 non-priority sports logic improvement 2025-07-26 19:34:41 -05:00
ChuckBuilds
ffc006bd99 change default config to just clock 2025-07-26 18:25:45 -05:00
ChuckBuilds
ea74d388b0 Update wiki submodule with latest documentation 2025-07-26 18:23:58 -05:00
Chuck
d4bd8d66e8 new bible verses for 5ymb01 2025-07-26 18:22:46 -05:00
ChuckBuilds
3a81e16490 wiki updates 2025-07-26 18:20:39 -05:00
Chuck
4ea2b9cc36 json fix bible verse 2025-07-25 22:17:51 -05:00
Chuck
407ebc56d7 add 3rd category to config 2025-07-25 21:52:37 -05:00
Chuck
f9e3419f39 test 3rd word of the day 2025-07-25 21:09:31 -05:00
ChuckBuilds
b03371d69a toggle visual adjustments 2025-07-24 20:59:58 -05:00
ChuckBuilds
58251eefb7 placement as % of matrix height 2025-07-24 20:49:40 -05:00
ChuckBuilds
74036ed6d9 placement as % of matrix height 2025-07-24 20:47:20 -05:00
ChuckBuilds
bfa1234feb updated hard coded y values for music title, artist, album 2025-07-24 20:44:50 -05:00
ChuckBuilds
6535ce113a updated hard coded y values for music title, artist, album 2025-07-24 20:14:46 -05:00
ChuckBuilds
dd8d219e73 updated hard coded y values for music title, artist, album 2025-07-24 20:13:04 -05:00
ChuckBuilds
1576e730ea hard coded y values for music title, artist, album 2025-07-24 20:10:57 -05:00
ChuckBuilds
7fc158c914 change artist postioning 2025-07-24 20:00:35 -05:00
ChuckBuilds
f9588f47d0 hard code line height 2025-07-24 19:51:17 -05:00
ChuckBuilds
2eaa158e80 adjust bdf offset 2025-07-24 19:31:01 -05:00
ChuckBuilds
3f05d9fcbc webui button changes 2025-07-24 19:29:25 -05:00
Chuck
3d2b155b79 change default user to be programatic to download git updates 2025-07-24 16:15:41 -05:00
Chuck
3df3b93348 added log viewer to web ui 2025-07-24 16:13:35 -05:00
Chuck
790b483298 remove hard coded bdf y offset 2025-07-24 16:09:00 -05:00
Chuck
d80c1a93db hardcoded line placements 2025-07-24 16:05:48 -05:00
Chuck
e8d2408477 font detection for music font placement 2025-07-24 15:59:24 -05:00
Chuck
fcc8c10c2b disable displays for debugging 2025-07-24 15:38:59 -05:00
Chuck
3063840b6d programmatic changes to artist and album font placement 2025-07-24 15:38:29 -05:00
Chuck
a3c5f9a74f programmatic changes to artist and album font 2025-07-24 15:33:58 -05:00
Chuck
e85bebee12 adjust music artist and album font programatically. Web ui now includes all settings 2025-07-24 15:04:17 -05:00
Chuck
30d416b822 web ui json editor improvements 2025-07-24 14:48:59 -05:00
Chuck
e1a32b1466 web ui save button improvements 2025-07-24 14:40:12 -05:00
Chuck
d02d7445cd web ui JSON linter added 2025-07-24 14:21:49 -05:00
Chuck
0785bcba93 web ui more options added 2025-07-24 14:05:42 -05:00
Chuck
9d01996ae6 webui rework 2025-07-24 13:31:24 -05:00
Chuck
8c705753df changing album position 2025-07-24 13:12:40 -05:00
Chuck
c7fc86e54d changing case for album scrolling 2025-07-24 13:06:42 -05:00
Chuck
9eb65ec891 swap displays for testing 2025-07-24 12:48:23 -05:00
Chuck
92891af6b6 music scroll album name 2025-07-24 12:44:14 -05:00
Chuck
c0d299892e live game duration 2025-07-24 12:32:38 -05:00
Chuck
9a63550a9b adjusting music manager artist and album location 2025-07-24 10:23:31 -05:00
Chuck
25506410d0 adjusting music manager artist and album location 2025-07-24 10:20:56 -05:00
Chuck
102c0eb795 adjusting music manager artist and album location 2025-07-24 10:19:08 -05:00
Chuck
4605cb5c39 adjusting music manager artist and album location 2025-07-24 10:17:16 -05:00
Chuck
f8bf76c150 adjusting music manager artist and album location 2025-07-24 10:15:39 -05:00
Chuck
977bd96241 adjusting music manager artist and album location 2025-07-24 10:13:32 -05:00
Chuck
5224c09faf adjusting music manager artist and album location 2025-07-24 10:12:00 -05:00
Chuck
f342bd9d3a adjusting music manager artist and album location 2025-07-24 10:09:59 -05:00
Chuck
5516a5f764 disabling other displays to focus on debugging 2025-07-24 10:08:14 -05:00
Chuck
15fcd0a722 disabling other displays to focus on debugging 2025-07-24 10:07:28 -05:00
Chuck
a867f767d9 adjusting music manager artist and album location 2025-07-24 10:06:50 -05:00
Chuck
e84640501d adjusting music manager artist and album location 2025-07-24 10:04:34 -05:00
Chuck
e627594989 adjust music artist location lower slight 2025-07-24 09:45:27 -05:00
Chuck
7963ac77b9 disabled some displays to test faster 2025-07-24 09:42:15 -05:00
Chuck
fe6272bf3a shift album and artist names up in the music manager 2025-07-24 09:40:10 -05:00
Chuck
7fc902dea1 cache updates for live games in all sports 2025-07-24 08:21:14 -05:00
Chuck
e61ce4e4be fix NCAA FB cache error 2025-07-23 20:35:39 -05:00
Chuck
18b0a9703e remove all sports live displays from checking cache 2025-07-23 20:31:25 -05:00
Chuck
4994d8ac21 remove Live Sports display from new cache 2025-07-23 20:18:43 -05:00
Chuck
12dd1de858 fix utc timedate error in milb 2025-07-23 19:32:37 -05:00
Chuck
d928fcd5d6 switch milb upcoming flag from final to preview 2025-07-23 17:48:32 -05:00
Chuck
bb52bfdecb adjust stock logo position 2025-07-23 17:43:27 -05:00
Chuck
7f38aec32a adjust stock logo draw 2025-07-23 17:39:17 -05:00
Chuck
af6b78a094 adjust float error 2025-07-23 17:25:38 -05:00
Chuck
2d280a80fd removed -5 spacing from album y_pos for music manager 2025-07-23 17:21:30 -05:00
Chuck
0781b72c1d adjust stock ticker when charts are disabled to make it more compact 2025-07-23 17:18:21 -05:00
Chuck
9280538e08 adjust user configurable parts of stock ticker 2025-07-23 17:02:50 -05:00
Chuck
0b1ff3f9b6 adjust broadcast logo height ratio from .6 to .8 2025-07-23 16:47:35 -05:00
Chuck
3855b30d1b shift down calendar description 2025-07-23 16:46:30 -05:00
Chuck
9dedfe0264 shift bdf draw text down one mor epixel total 6 2025-07-23 16:18:07 -05:00
Chuck
0d6e147df3 shift bdf draw text down one mor epixel 2025-07-23 16:17:44 -05:00
Chuck
8bab8124cd shift bdf draw text down 2025-07-23 16:11:10 -05:00
Chuck
b051288804 broadcast logo rescaling 2025-07-23 15:00:06 -05:00
Chuck
b4d2c34217 fix bdf font positioning for displays negatively impacted by previous change 2025-07-23 14:57:07 -05:00
Chuck
2af78a37d5 fix bdf drawing in other displays relying on display manager 2025-07-23 14:36:35 -05:00
Chuck
b5b18babe8 revert daily weather temp font change due to negative effects on other displays 2025-07-23 14:27:50 -05:00
Chuck
723b7ce190 fix bdf font for weather 2025-07-23 14:17:53 -05:00
Chuck
6c02b9dc4a justify day date font in odds ticker manager 2025-07-23 13:53:30 -05:00
Chuck
58bfdc04a0 found a nice font for weather daily tempts 2025-07-23 13:50:46 -05:00
Chuck
d371b5ad09 re-enable other displays 2025-07-23 13:42:20 -05:00
Chuck
258ae8e654 revert font 2025-07-23 13:39:55 -05:00
Chuck
dc7e5b5a4f change font of body 2025-07-23 13:39:08 -05:00
Chuck
329b2def38 shift down one px starting line of body text 2025-07-23 13:37:18 -05:00
Chuck
56dc224e16 add one px line gap 2025-07-23 13:35:34 -05:00
Chuck
de04e342e8 center text 2025-07-23 13:33:46 -05:00
Chuck
80e12a8599 separate x and y logic for bdf placement 2025-07-23 13:30:54 -05:00
Chuck
64bb6129a8 steal logic from font test manager 2025-07-23 13:28:14 -05:00
Chuck
53ffc12a99 baseline tuning 2025-07-23 13:26:42 -05:00
Chuck
9b173f3ff2 improved rotation logic and trying to fix desenders on glyphs 2025-07-23 13:23:13 -05:00
Chuck
e5046db928 font change 2025-07-23 13:18:52 -05:00
Chuck
2638d222e7 shift down 2025-07-23 13:18:03 -05:00
Chuck
a0d15fb595 dyanmic movement 2025-07-23 13:16:59 -05:00
Chuck
81d8289158 shift letters down 2025-07-23 13:14:59 -05:00
Chuck
6c5f2c5c64 baseline shift 2025-07-23 13:13:40 -05:00
Chuck
85613aac00 baseline math 2025-07-23 13:12:17 -05:00
Chuck
9a86a9fe85 use font scender, whatever that is 2025-07-23 13:09:43 -05:00
Chuck
69df66b471 attempt to simplify font drawing 2025-07-23 13:08:01 -05:00
Chuck
665e1b4f67 bitmap fonts are outrageous 2025-07-23 13:05:20 -05:00
Chuck
93c68cc903 bitmap flip 2025-07-23 13:03:21 -05:00
Chuck
19f5191a5d attacking bdf baseline issue 2025-07-23 13:01:33 -05:00
Chuck
d10aed8fe5 trying x version 2025-07-23 12:59:48 -05:00
Chuck
78f014cad3 new fonts: Matrix light & chunky 2025-07-23 12:58:49 -05:00
Chuck
53464e0971 font change to MatrixLight8X 2025-07-23 12:55:26 -05:00
Chuck
e7100c4cba font change to cozette 2025-07-23 12:53:26 -05:00
Chuck
33e61634be fotn changes 2025-07-23 12:51:24 -05:00
Chuck
5518810889 new font 2025-07-23 12:48:15 -05:00
Chuck
e54a25da78 new font 2025-07-23 12:46:55 -05:00
Chuck
aa0472e5c5 new font try 2 2025-07-23 12:07:02 -05:00
Chuck
f3f50b87af try font change setting 2025-07-23 12:04:19 -05:00
Chuck
e4294a5e38 update display duration for of the day 2025-07-23 11:50:22 -05:00
Chuck
b5e8383342 text formatting 2025-07-23 11:40:49 -05:00
Chuck
141063117e fix body text height 2025-07-23 11:36:25 -05:00
Chuck
d4e799b202 fix line wrap 2025-07-23 11:34:55 -05:00
Chuck
fcacb82c57 fix title height 2025-07-23 11:33:21 -05:00
Chuck
60a7159a4d back to bdf font for clear drawing 2025-07-23 11:32:11 -05:00
Chuck
7eee58d5c1 font size too small 2025-07-23 11:28:32 -05:00
Chuck
475a1b1d15 PIL box attributeerror correction 2025-07-23 11:25:14 -05:00
Chuck
c6b7d2a5cc switching to TTF font 2025-07-23 11:24:10 -05:00
Chuck
3a2956a2c6 OTD formatting errors with BDF font 2025-07-23 11:18:15 -05:00
Chuck
30435c5371 update text height detection 2025-07-23 11:16:51 -05:00
Chuck
1192005c19 baseline offset 2025-07-23 11:11:35 -05:00
Chuck
4e7c5b0d1b address bitmap baseline in text rednering 2025-07-23 11:09:55 -05:00
Chuck
db11b2be27 fix bdf baseline text placement 2025-07-23 11:06:32 -05:00
Chuck
5654345b2a fix bdf text wrapping 2025-07-23 11:04:49 -05:00
Chuck
8ba5b73dab error squashing with bdf drawing 2025-07-23 11:03:56 -05:00
Chuck
5e47496704 bdf font size debugging 2025-07-23 10:33:12 -05:00
Chuck
585dbe0d10 bdf font debugging 2025-07-23 10:31:56 -05:00
Chuck
0d47875dec fix new bdf font draw error 2025-07-23 10:24:43 -05:00
Chuck
a904cac016 Of the day format and font updates, new rotational strucutre 2025-07-23 10:23:14 -05:00
Chuck
553a857cb6 try new font, Cozette 2025-07-23 09:50:16 -05:00
Chuck
4e56f88463 try new font 2025-07-23 08:37:15 -05:00
Chuck
b311256cc1 OTD draw cache change 2025-07-22 22:21:30 -05:00
Chuck
5c6776d120 OTD layout changes 2025-07-22 22:18:57 -05:00
Chuck
4a9c011b93 OTD layout changes 2025-07-22 22:05:42 -05:00
Chuck
54352825fd OTD layout changes 2025-07-22 22:03:48 -05:00
Chuck
3b75962ec1 change OTD font 2025-07-22 21:57:00 -05:00
Chuck
3db6fa5bdb change font test size 2025-07-22 21:53:01 -05:00
Chuck
04753e56e4 change font test size 2025-07-22 21:47:31 -05:00
Chuck
b6244075a7 change font test size 2025-07-22 21:46:33 -05:00
Chuck
7c45179248 update parent directory of font test 2025-07-22 21:40:45 -05:00
Chuck
eb96285a5c left justify OTD display and update font display to test 5x7regular 2025-07-22 21:38:43 -05:00
Chuck
584976fc49 format OTD 2025-07-22 21:31:16 -05:00
Chuck
ad8602a3d5 replace clear function after intializing and before drawing 2025-07-22 21:27:29 -05:00
Chuck
f27e4ef892 remove redundant clear_display 2025-07-22 21:26:00 -05:00
Chuck
41d703d825 update draw logic 2025-07-22 21:24:41 -05:00
Chuck
8af500237d add a rectangle to test draw method 2025-07-22 21:23:28 -05:00
Chuck
6e2e5cbfe4 display order rework 2025-07-22 21:19:07 -05:00
Chuck
935f7acfa2 more debug logging 2025-07-22 21:04:37 -05:00
Chuck
c588de84f3 file path name fix to remove duplicate folder name 2025-07-22 21:02:47 -05:00
Chuck
54c281475c additional logging and rate limit logs to see what is happening 2025-07-22 21:01:38 -05:00
Chuck
3ac37e06bb add debug logging to of the day display 2025-07-22 20:59:29 -05:00
Chuck
86e53360ac disable other displays to test Of the day display 2025-07-22 20:46:05 -05:00
Chuck
16d6c7c9b1 adjust timing of the day display 2025-07-22 20:44:11 -05:00
Chuck
cb81bec042 add Of The Day display 2025-07-22 20:39:09 -05:00
Chuck
3ab28e8201 move test files to test folder to clean up repo 2025-07-22 20:01:39 -05:00
258 changed files with 130455 additions and 2872 deletions

38
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

1
LEDMatrix.wiki Submodule

Submodule LEDMatrix.wiki added at 8d2c143954

281
README.md
View File

@@ -1,5 +1,5 @@
# LEDMatrix # LEDMatrix
An LED matrix display system that provides real-time information display capabilities for various data sources. The system is highly configurable and supports multiple display modes that can be enabled or disabled based on user preferences.
### Setup video and feature walkthrough on Youtube : ### Setup video and feature walkthrough on Youtube :
[![IMAGE ALT TEXT HERE](https://img.youtube.com/vi/_HaqfJy1Y54/0.jpg)](https://www.youtube.com/watch?v=_HaqfJy1Y54) [![IMAGE ALT TEXT HERE](https://img.youtube.com/vi/_HaqfJy1Y54/0.jpg)](https://www.youtube.com/watch?v=_HaqfJy1Y54)
@@ -171,6 +171,17 @@ git clone https://github.com/ChuckBuilds/LEDMatrix.git
cd LEDMatrix cd LEDMatrix
``` ```
4. First-time installation (recommended)
```bash
chmod +x first_time_install.sh
sudo ./first_time_install.sh
```
This single script installs services, dependencies, configures permissions and sudoers, and validates the setup.
----- OLD STEPS (left for manual review) -----
4. Install dependencies: 4. Install dependencies:
```bash ```bash
sudo pip3 install --break-system-packages -r requirements.txt sudo pip3 install --break-system-packages -r requirements.txt
@@ -245,7 +256,6 @@ sudo nano /boot/firmware/config.txt
```bash ```bash
sudo reboot sudo reboot
``` ```
----------------------------------------------------------------------------------- -----------------------------------------------------------------------------------
## Configuration ## Configuration
@@ -395,6 +405,107 @@ This will:
3. Display sample games 3. Display sample games
4. Test the scrolling functionality 4. Test the scrolling functionality
## Stocks Configuration
The stocks display shows real-time stock and crypto prices in a scrolling ticker format. To configure it:
1. In `config/config.json`, add the following section:
```json
{
"stocks": {
"enabled": true,
"symbols": ["AAPL", "MSFT", "GOOGL", "TSLA"],
"update_interval": 600,
"scroll_speed": 1,
"scroll_delay": 0.01,
"toggle_chart": false
}
}
```
### Configuration Options
- **`enabled`**: Enable/disable the stocks display (default: false)
- **`symbols`**: Array of stock symbols to display (e.g., ["AAPL", "MSFT", "GOOGL"])
- **`update_interval`**: How often to fetch new stock data in seconds (default: 600)
- **`scroll_speed`**: Pixels to scroll per update (default: 1)
- **`scroll_delay`**: Delay between scroll updates in seconds (default: 0.01)
- **`toggle_chart`**: Enable/disable mini charts in the scrolling ticker (default: false)
### Display Format
The stocks display shows information in this format:
```
[Logo] SYMBOL
$PRICE
+CHANGE (+PERCENT%)
```
Where:
- `[Logo]` - Stock/crypto logo (if available)
- `SYMBOL` - Stock symbol (e.g., AAPL, MSFT)
- `$PRICE` - Current stock price
- `+CHANGE` - Price change (green for positive, red for negative)
- `+PERCENT%` - Percentage change
### Chart Toggle Feature
The `toggle_chart` setting controls whether mini price charts are displayed alongside each stock:
- **`"toggle_chart": true`**: Shows mini line charts on the right side of each stock display
- **`"toggle_chart": false`**: Shows only text information (symbol, price, change)
When charts are disabled, the text is centered more prominently on the display.
### Crypto Support
The system also supports cryptocurrency symbols. Add crypto symbols to the `symbols` array:
```json
{
"stocks": {
"enabled": true,
"symbols": ["AAPL", "MSFT", "BTC-USD", "ETH-USD"],
"update_interval": 600,
"scroll_speed": 1,
"scroll_delay": 0.01,
"toggle_chart": false
}
}
```
### Requirements
- Yahoo Finance API access for stock data
- Stock/crypto logo files in the appropriate directories:
- `assets/stocks/ticker_icons/` (for stocks)
- `assets/stocks/crypto_icons/` (for cryptocurrencies)
### Troubleshooting
**No Stock Data Displayed:**
1. **Symbol Format**: Ensure stock symbols are correct (e.g., "AAPL" not "apple")
2. **API Access**: Verify Yahoo Finance API is accessible
3. **Market Hours**: Some data may be limited during off-hours
4. **Symbol Validity**: Check that symbols exist and are actively traded
**Performance Issues:**
1. **Reduce scroll_speed**: Try setting it to 1 instead of higher values
2. **Increase scroll_delay**: Try 0.05 instead of 0.01 for smoother scrolling
3. **Reduce symbols**: Limit the number of symbols to improve performance
### Testing
You can test the stocks functionality using:
```bash
python test/test_stock_toggle_chart.py
```
This will:
1. Test the toggle_chart functionality
2. Verify configuration loading
3. Test cache clearing behavior
## Football Game-Based Configuration (NFL & NCAA FB) ## Football Game-Based Configuration (NFL & NCAA FB)
For NFL and NCAA Football, the system now uses a game-based fetch approach instead of time-based windows. This is more practical for football since games are weekly and you want to show specific numbers of games rather than arbitrary time periods. For NFL and NCAA Football, the system now uses a game-based fetch approach instead of time-based windows. This is more practical for football since games are weekly and you want to show specific numbers of games rather than arbitrary time periods.
@@ -706,7 +817,7 @@ This will start the display cycle but only stays active as long as your ssh sess
The LEDMatrix can be installed as a systemd service to run automatically at boot and be managed easily. The service runs as root to ensure proper hardware timing access for the LED matrix. The LEDMatrix can be installed as a systemd service to run automatically at boot and be managed easily. The service runs as root to ensure proper hardware timing access for the LED matrix.
### Installing the Service ### Installing the Service (this is included in the first_time_install.sh)
1. Make the install script executable: 1. Make the install script executable:
```bash ```bash
@@ -766,6 +877,102 @@ sudo ./start_display.sh
sudo ./stop_display.sh sudo ./stop_display.sh
``` ```
-----------------------------------------------------------------------------------
## Web Interface Installation (V2)
The LEDMatrix system includes Web Interface V2 that runs on port 5001 and provides real-time display preview, configuration management, and on-demand display controls.
### Installing the Web Interface Service
1. Make the install script executable:
```bash
chmod +x install_web_service.sh
```
2. Run the install script with sudo:
```bash
sudo ./install_web_service.sh
```
The script will:
- Copy the web service file to `/etc/systemd/system/`
- Enable the service to start on boot
- Start the service immediately
- Show the service status
### Web Interface Configuration
The web interface can be configured to start automatically with the main display service:
1. In `config/config.json`, ensure the web interface autostart is enabled:
```json
{
"web_display_autostart": true
}
```
2. The web interface will now start automatically when:
- The system boots
- The `web_display_autostart` setting is `true` in your config
### Accessing the Web Interface
Once installed, you can access the web interface at:
```
http://your-pi-ip:5001
```
### Managing the Web Interface Service
```bash
# Check service status
sudo systemctl status ledmatrix-web.service
# View logs
journalctl -u ledmatrix-web.service -f
# Stop the service
sudo systemctl stop ledmatrix-web.service
# Start the service
sudo systemctl start ledmatrix-web.service
# Disable autostart
sudo systemctl disable ledmatrix-web.service
# Enable autostart
sudo systemctl enable ledmatrix-web.service
```
### Web Interface Features
- **Real-time Display Preview**: See what's currently displayed on the LED matrix
- **Configuration Management**: Edit settings through a web interface
- **On-Demand Controls**: Start specific displays (weather, stocks, sports) on demand
- **Service Management**: Start/stop the main display service
- **System Controls**: Restart, update code, and manage the system
- **API Metrics**: Monitor API usage and system performance
- **Logs**: View system logs in real-time
### Troubleshooting Web Interface
**Web Interface Not Accessible After Restart:**
1. Check if the web service is running: `sudo systemctl status ledmatrix-web.service`
2. Verify the service is enabled: `sudo systemctl is-enabled ledmatrix-web.service`
3. Check logs for errors: `journalctl -u ledmatrix-web.service -f`
4. Ensure `web_display_autostart` is set to `true` in `config/config.json`
**Port 5001 Not Accessible:**
1. Check if the service is running on the correct port
2. Verify firewall settings allow access to port 5001
3. Check if another service is using port 5001
**Service Fails to Start:**
1. Check Python dependencies are installed
2. Verify the virtual environment is set up correctly
3. Check file permissions and ownership
----------------------------------------------------------------------------------- -----------------------------------------------------------------------------------
@@ -932,6 +1139,31 @@ The LEDMatrix system includes a comprehensive scoreboard display system with thr
- Automatic game switching - Automatic game switching
- Built-in caching to reduce API calls - Built-in caching to reduce API calls
- Test mode for development - Test mode for development
## API Usage Tracking
The LEDMatrix system includes a built-in API usage counter that tracks API calls made by various managers in a 24-hour rolling window. This feature helps monitor API usage and ensure compliance with rate limits.
### API Counter Features
- **Real-time Tracking**: Counts API calls for weather, stocks, sports, and news data
- **24-hour Window**: Rolling window that resets every 24 hours
- **Web Interface Integration**: View current usage in the Overview tab of the web interface
- **Forecast Display**: Shows predicted API usage based on current configuration
- **Automatic Reset**: Counters automatically reset when the 24-hour window expires
### Tracked API Calls
- **Weather**: OpenWeatherMap API calls (geocoding + weather data)
- **Stocks**: Yahoo Finance API calls for stock and crypto data
- **Sports**: ESPN API calls for various sports leagues (NHL, NBA, MLB, NFL, etc.)
- **News**: RSS feed and news API calls
### Accessing API Metrics
1. Open the web interface in your browser
2. Navigate to the **Overview** tab
3. Scroll down to the "API Calls (24h window)" section
4. Click "Refresh API Metrics" to update the display
The counter shows both actual usage and forecasted usage based on your current configuration settings.
## Caching System ## Caching System
The LEDMatrix system includes a robust caching mechanism to optimize API calls and reduce network traffic: The LEDMatrix system includes a robust caching mechanism to optimize API calls and reduce network traffic:
@@ -973,16 +1205,24 @@ The LEDMatrix system includes a robust caching mechanism to optimize API calls a
##What's Next? ##What's Next?
- Adding MQTT/HomeAssistant integration - Adding MQTT/HomeAssistant integration
- Gambling odds? - Gambling odds (done!)
- Building a user-friendly UI for easier configuration - Building a user-friendly UI for easier configuration (done!)
### If you've read this far — thanks!
## Granting Passwordless Sudo Access for Web Interface Actions ## Granting Passwordless Sudo Access for Web Interface Actions
The web interface needs to run certain commands with `sudo` (e.g., `reboot`, `systemctl start/stop/enable/disable ledmatrix.service`, `python display_controller.py`). To avoid needing to enter a password for these actions through the web UI, you can configure the `sudoers` file to allow the user running the Flask application to execute these specific commands without a password. The web interface needs to run certain commands with `sudo` (e.g., `reboot`, `systemctl start/stop/enable/disable ledmatrix.service`, `python display_controller.py`). To avoid needing to enter a password for these actions through the web UI, you can configure the `sudoers` file to allow the user running the Flask application to execute these specific commands without a password.
1. Shortcut to automate the below steps:
```chmod +x configure_web_sudo.sh```
then
```./configure_web_sudo.sh```
Manual Method:
**WARNING: Be very careful when editing the `sudoers` file. Incorrect syntax can lock you out of `sudo` access.** **WARNING: Be very careful when editing the `sudoers` file. Incorrect syntax can lock you out of `sudo` access.**
1. **Identify the user:** Determine which user is running the `web_interface.py` script. Often, this might be the default user like `pi` on a Raspberry Pi, or a dedicated user you've set up. 1. **Identify the user:** Determine which user is running the `web_interface.py` script. Often, this might be the default user like `pi` on a Raspberry Pi, or a dedicated user you've set up.
@@ -1030,3 +1270,32 @@ The web interface needs to run certain commands with `sudo` (e.g., `reboot`, `sy
**Security Considerations:** **Security Considerations:**
Granting passwordless `sudo` access, even for specific commands, has security implications. Ensure that the scripts and commands allowed are secure and cannot be easily exploited. The web interface itself should also be secured if it's exposed to untrusted networks. Granting passwordless `sudo` access, even for specific commands, has security implications. Ensure that the scripts and commands allowed are secure and cannot be easily exploited. The web interface itself should also be secured if it's exposed to untrusted networks.
For `display_controller.py` and `stop_display.sh`, ensure their file permissions restrict write access to only trusted users, preventing unauthorized modification of these scripts which run with elevated privileges. For `display_controller.py` and `stop_display.sh`, ensure their file permissions restrict write access to only trusted users, preventing unauthorized modification of these scripts which run with elevated privileges.
## Web Interface V2 (simplified quick start)
### 1) Run the helper (does the above and starts the server):
```
python3 start_web_v2.py
```
### 2) Start the web UI v2
```
python web_interface_v2.py
```
### 3) Autostart (recommended)
Set `"web_display_autostart": true` in `config/config.json`.
Ensure your systemd service calls `start_web_conditionally.py` (installed by `install_service.sh`).
### 4) Permissions (optional but recommended)
- Add the service user to `systemd-journal` for viewing logs without sudo.
- Configure passwordless sudo for actions (start/stop service, reboot, shutdown) if desired.
- Required for web Ui actions, look in the section above for the commands to run (chmod +x configure_web_sudo.sh & ./configure_web_sudo.sh)
### 5) Old web UI (v1)
The project now defaults to Web UI v2. The v1 interface can be ignored.
An LED matrix display system that provides real-time information display capabilities for various data sources. The system is highly configurable and supports multiple display modes that can be enabled or disabled based on user preferences.
### If you've read this far — thanks!

162
add_custom_feed_example.py Normal file
View File

@@ -0,0 +1,162 @@
#!/usr/bin/env python3
import json
import sys
import os
def add_custom_feed(feed_name, feed_url):
"""Add a custom RSS feed to the news manager configuration"""
config_path = "config/config.json"
try:
# Load current config
with open(config_path, 'r') as f:
config = json.load(f)
# Ensure news_manager section exists
if 'news_manager' not in config:
print("ERROR: News manager configuration not found!")
return False
# Add custom feed
if 'custom_feeds' not in config['news_manager']:
config['news_manager']['custom_feeds'] = {}
config['news_manager']['custom_feeds'][feed_name] = feed_url
# Add to enabled feeds if not already there
if feed_name not in config['news_manager']['enabled_feeds']:
config['news_manager']['enabled_feeds'].append(feed_name)
# Save updated config
with open(config_path, 'w') as f:
json.dump(config, f, indent=4)
print(f"SUCCESS: Successfully added custom feed: {feed_name}")
print(f" URL: {feed_url}")
print(f" Feed is now enabled and will appear in rotation")
return True
except Exception as e:
print(f"ERROR: Error adding custom feed: {e}")
return False
def list_all_feeds():
"""List all available feeds (default + custom)"""
config_path = "config/config.json"
try:
with open(config_path, 'r') as f:
config = json.load(f)
news_config = config.get('news_manager', {})
custom_feeds = news_config.get('custom_feeds', {})
enabled_feeds = news_config.get('enabled_feeds', [])
print("\nAvailable News Feeds:")
print("=" * 50)
# Default feeds (hardcoded in news_manager.py)
default_feeds = {
'MLB': 'http://espn.com/espn/rss/mlb/news',
'NFL': 'http://espn.go.com/espn/rss/nfl/news',
'NCAA FB': 'https://www.espn.com/espn/rss/ncf/news',
'NHL': 'https://www.espn.com/espn/rss/nhl/news',
'NBA': 'https://www.espn.com/espn/rss/nba/news',
'TOP SPORTS': 'https://www.espn.com/espn/rss/news',
'BIG10': 'https://www.espn.com/blog/feed?blog=bigten',
'NCAA': 'https://www.espn.com/espn/rss/ncaa/news',
'Other': 'https://www.coveringthecorner.com/rss/current.xml'
}
print("\nDefault Sports Feeds:")
for name, url in default_feeds.items():
status = "ENABLED" if name in enabled_feeds else "DISABLED"
print(f" {name}: {status}")
print(f" {url}")
if custom_feeds:
print("\nCustom Feeds:")
for name, url in custom_feeds.items():
status = "ENABLED" if name in enabled_feeds else "DISABLED"
print(f" {name}: {status}")
print(f" {url}")
else:
print("\nCustom Feeds: None added yet")
print(f"\nCurrently Enabled Feeds: {len(enabled_feeds)}")
print(f" {', '.join(enabled_feeds)}")
except Exception as e:
print(f"ERROR: Error listing feeds: {e}")
def remove_custom_feed(feed_name):
"""Remove a custom RSS feed"""
config_path = "config/config.json"
try:
with open(config_path, 'r') as f:
config = json.load(f)
news_config = config.get('news_manager', {})
custom_feeds = news_config.get('custom_feeds', {})
if feed_name not in custom_feeds:
print(f"ERROR: Custom feed '{feed_name}' not found!")
return False
# Remove from custom feeds
del config['news_manager']['custom_feeds'][feed_name]
# Remove from enabled feeds if present
if feed_name in config['news_manager']['enabled_feeds']:
config['news_manager']['enabled_feeds'].remove(feed_name)
# Save updated config
with open(config_path, 'w') as f:
json.dump(config, f, indent=4)
print(f"SUCCESS: Successfully removed custom feed: {feed_name}")
return True
except Exception as e:
print(f"ERROR: Error removing custom feed: {e}")
return False
def main():
if len(sys.argv) < 2:
print("Usage:")
print(" python3 add_custom_feed_example.py list")
print(" python3 add_custom_feed_example.py add <feed_name> <feed_url>")
print(" python3 add_custom_feed_example.py remove <feed_name>")
print("\nExamples:")
print(" # Add F1 news feed")
print(" python3 add_custom_feed_example.py add 'F1' 'https://www.espn.com/espn/rss/rpm/news'")
print(" # Add BBC F1 feed")
print(" python3 add_custom_feed_example.py add 'BBC F1' 'http://feeds.bbci.co.uk/sport/formula1/rss.xml'")
print(" # Add personal blog feed")
print(" python3 add_custom_feed_example.py add 'My Blog' 'https://myblog.com/rss.xml'")
return
command = sys.argv[1].lower()
if command == 'list':
list_all_feeds()
elif command == 'add':
if len(sys.argv) != 4:
print("ERROR: Usage: python3 add_custom_feed_example.py add <feed_name> <feed_url>")
return
feed_name = sys.argv[2]
feed_url = sys.argv[3]
add_custom_feed(feed_name, feed_url)
elif command == 'remove':
if len(sys.argv) != 3:
print("ERROR: Usage: python3 add_custom_feed_example.py remove <feed_name>")
return
feed_name = sys.argv[2]
remove_custom_feed(feed_name)
else:
print(f"ERROR: Unknown command: {command}")
if __name__ == "__main__":
main()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

21422
assets/fonts/5x8.bdf Normal file

File diff suppressed because it is too large Load Diff

20768
assets/fonts/6x9.bdf Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

10184
assets/fonts/MatrixLight8X.bdf Normal file

File diff suppressed because it is too large Load Diff

9993
assets/fonts/ic8x8u.bdf Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,404 +1,53 @@
NCAAF NCAAF
AAMU => Alabama A&M Bulldogs AMH => Amherst Mammoths
ACU => Abilene Christian Wildcats
ADA => Adams State Grizzlies
ADR => Adrian Bulldogs
AFA => Air Force Falcons
AIC => American International Yellow Jackets
AKR => Akron Zips
ALA => Alabama Crimson Tide
ALB => Albright Lions
ALBS => Albany State (GA) Golden Rams
ALCN => Alcorn State Braves
ALD => Alderson Broaddus Battlers
ALF => Alfred Saxons
ALL => Allegheny Gators
ALST => Alabama State Hornets
AMH => Amherst College Mammoths
AND => Anderson (IN) Ravens
ANG => Angelo State Rams
ANN => Anna Maria College Amcats ANN => Anna Maria College Amcats
APP => Appalachian State Mountaineers
APSU => Austin Peay Governors
ARIZ => Arizona Wildcats ARIZ => Arizona Wildcats
ARK => Arkansas-Monticello Boll Weevils ARK => Arkansas Razorbacks
ARMY => Army Black Knights
ARST => Arkansas State Red Wolves
ASH => Ashland Eagles
ASP => Assumption Greyhounds
ASU => Arizona State Sun Devils ASU => Arizona State Sun Devils
AUB => Auburn Tigers AUB => Auburn Tigers
AUG => St. Augustine's Falcons BOIS => Boise State Broncos
AUR => Aurora Spartans BRST => Bridgewater State Bears
AUS => Austin College 'Roos BUENA => Buena Vista Beavers
AVE => Averett Cougars CAL => California Golden Bears
AVI => Avila College Eagles CAR => Carroll University (WI) Pioneers
AZU => Azusa Pacific Cougars CLA => Claremont-Mudd-Scripps College Stags
BAK => Baker University Wildcats COLBY => Colby College White Mules
BAL => Baldwin Wallace Yellow Jackets
BALL => Ball State Cardinals
BAT => Bates College Bobcats
BAY => Baylor Bears
BC => Boston College Eagles
BEC => Becker College Hawks
BEL => Beloit College Buccaneers
BEN => Benedictine University (IL) Eagles
BENT => Bentley Falcons
BET => Bethel (TN) Wildcats
BGSU => Bowling Green Falcons
BHS => Black Hills State Yellow Jackets
BIR => Birmingham-Southern Panthers
BKN => Bacone College Warriors
BLA => Blackburn Beavers
BLOM => Bloomsburg Huskies
BLU => Bluffton Beavers
BOW => Bowdoin Polar Bears
BRI => British Columbia Thunderbirds
BRWN => Brown Bears
BST => Bemidji State Beavers
BSU => Bowie State Bulldogs
BUCK => Bucknell Bison
BUE => Buena Vista Beavers
BUF => Buffalo State Bengals
BUFF => Buffalo Bulls
BUT => Butler Bulldogs
BYU => BYU Cougars
CAL => California Lutheran Kingsmen
CAM => Campbell Fighting Camels
CAP => Capital University Crusaders
CAR => Carthage College Red Men
CARK => Central Arkansas Bears
CAS => Castleton Spartans
CAT => Catholic University Cardinals
CCSU => Central Connecticut Blue Devils
CCU => Coastal Carolina Chanticleers
CEN => Centre College Colonels
CHA => Chapman University Panthers
CHI => Chicago Maroons
CHSO => Charleston Southern Buccaneers
CIN => Cincinnati Bearcats
CLA => Clarion Golden Eagles
CLEM => Clemson Tigers
CLMB => Columbia Lions
CLT => Charlotte 49ers
CMU => Central Michigan Chippewas
COE => Coe College Kohawks
COL => Colorado School of Mines Orediggers
COLC => Colorado College Tigers
COLG => Colgate Raiders
COLO => Colorado Buffaloes COLO => Colorado Buffaloes
CON => Concordia-Minnesota Cobbers CONN => UConn Huskies
COR => Cornell College (IA) Rams
CP => Cal Poly Mustangs CP => Cal Poly Mustangs
CRO => Crown Storm
CSU => Colorado State Rams CSU => Colorado State Rams
CUL => Culver-Stockton Wildcats
CUM => Cumberland College Indians
CUR => Curry College Colonels CUR => Curry College Colonels
DAK => Dakota Wesleyan Tigers DEL => Delaware Blue Hens
DART => Dartmouth Big Green
DAV => Davidson Wildcats
DAY => Dayton Flyers
DEF => Defiance Yellow Jackets
DEL => Delta State Statesmen
DEN => Denison Big Red
DEP => DePauw Tigers
DIC => Dickinson State Blue Hawks
DRKE => Drake Bulldogs
DSU => Delaware State Hornets
DUB => Dubuque Spartans DUB => Dubuque Spartans
DUKE => Duke Blue Devils ELM => Elmhurst Bluejays
DUQ => Duquesne Dukes FAMU => Florida A&M Rattlers
EAS => Eastern New Mexico Greyhounds
ECU => East Carolina Pirates
EDI => Edinboro Fighting Scots
EIU => Eastern Illinois Panthers
EKU => Eastern Kentucky Colonels
ELI => Elizabeth City State Vikings
ELM => Elmhurst Blue Jays
ELON => Elon Phoenix
EMO => Emory & Henry Wasps
EMP => Emporia State Hornets
EMU => Eastern Michigan Eagles
END => Endicott College Gulls
EOR => Eastern Oregon Mountaineers
ETSU => East Tennessee State Buccaneers
EUR => Eureka College Red Devils
EWU => Eastern Washington Eagles
FAU => Florida Atlantic Owls
FAY => Fayetteville State Broncos
FDU => FDU-Florham Devils
FER => Ferrum Panthers
FIN => Findlay Oilers
FIT => Fitchburg State Falcons
FIU => Florida International Panthers
FLA => Florida Gators FLA => Florida Gators
FOR => Fort Valley State Wildcats
FRA => Franklin Grizzlies
FRES => Fresno State Bulldogs
FRO => Frostburg State Bobcats
FRST => Ferris State Bulldogs
FSU => Florida State Seminoles FSU => Florida State Seminoles
FTLW => Fort Lewis Skyhawks
FUR => Furman Paladins
GAL => Gallaudet Bison
GAN => Gannon Golden Knights
GASO => Georgia Southern Eagles
GAST => Georgia State Panthers
GEN => Geneva College Golden Tornadoes
GEO => George Fox University Bruins
GET => Gettysburg Bullets
GLE => Glenville State Pioneers
GMU => George Mason Patriots
GRA => Grand Valley State Lakers
GRE => Greenville Panthers
GRI => Grinnell Pioneers GRI => Grinnell Pioneers
GRO => Grove City College Wolverines
GT => Georgia Tech Yellow Jackets GT => Georgia Tech Yellow Jackets
GUI => Guilford Quakers GTWN => Georgetown Hoyas
GWEB => Gardner-Webb Bulldogs
HAM => Hampden-Sydney Tigers
HAMP => Hampton Pirates
HAN => Hanover Panthers
HAR => Hartwick Hawks
HARV => Harvard Crimson
HAS => Haskell Indian Nations Jayhawks
HAW => Hawai'i Rainbow Warriors HAW => Hawai'i Rainbow Warriors
HBU => Houston Baptist Huskies
HC => Holy Cross Crusaders
HEI => Heidelberg Student Princes
HEN => Hendrix College Warriors
HIL => Hillsdale Chargers
HIR => Hiram College Terriers
HOB => Hobart Statesmen
HOU => Houston Cougars
HOW => Howard Bison HOW => Howard Bison
HUS => Husson Eagles
IDHO => Idaho Vandals IDHO => Idaho Vandals
IDST => Idaho State Bengals
ILL => Illinois Fighting Illini
ILST => Illinois State Redbirds
ILW => Illinois Wesleyan Titans
IND => Indianapolis
INST => Indiana State Sycamores
IOW => Iowa Wesleyan Tigers
IOWA => Iowa Hawkeyes
ISU => Iowa State Cyclones ISU => Iowa State Cyclones
ITH => Ithaca Bombers JXST => Jacksonville State Gamecocks
IU => Indiana Hoosiers
JKST => Jackson State Tigers
JMU => James Madison Dukes
JOH => Johnson C Smith Golden Bulls
JUN => Juniata Eagles
JVST => Jacksonville State Gamecocks
KAL => Kalamazoo Hornets
KAN => Kansas Wesleyan University Coyotes
KEN => Kenyon Lords
KENN => Kennesaw State Owls
KENT => Kent State Golden Flashes
KIN => King's College (PA) Monarchs
KNO => Knox College Prairie Fire
KSU => Kansas State Wildcats
KU => Kansas Jayhawks
KUT => Kutztown Golden Bears
KYST => Kentucky State Thorobreds
KYW => Kentucky Wesleyan Panthers
LA => La Verne Leopards
LAC => Lane Dragons
LAF => Lafayette Leopards
LAG => LaGrange College Panthers
LAK => Lake Forest Foresters
LAM => Lambuth Eagles
LAN => Langston Lions
LAW => Lawrence Vikings
LEB => Lebanon Valley Flying Dutchmen
LEH => Lehigh Mountain Hawks
LEN => Lenoir-Rhyne Bears
LEW => Lewis & Clark Pioneers
LIB => Liberty Flames
LIM => Limestone Saints
LIN => Linfield Wildcats
LOC => Lock Haven Bald Eagles
LOR => Loras College Duhawks
LOU => Louisville Cardinals
LSU => LSU Tigers
LT => Louisiana Tech Bulldogs
LUT => Luther Norse LUT => Luther Norse
LYC => Lycoming Warriors MESA => Colorado Mesa Mavericks
M-OH => Miami (OH) RedHawks MIL => Millikin Big Blue
MAC => Macalester Scots MOR => Morehouse College Maroon Tigers
MAI => Maine Maritime Mariners NOR => North Park Vikings
MAN => Mansfield Mountaineers
MAR => Maryville College Fighting Scots
MAS => Mass Maritime Buccaneers
MASS => UMass Minutemen
MAY => Mayville State Comets
MCM => McMurry War Hawks
MCN => McNeese Cowboys
MD => Maryland Terrapins
MEM => Memphis Tigers
MEN => Menlo College Oaks
MER => Merchant Marine Mariners
MERC => Mercyhurst Lakers
MES => Colorado Mesa Mavericks
MET => Methodist Monarchs
MH => Mars Hill Mountain Lions
MIAMI => Miami Hurricanes
MICH => Michigan Wolverines
MID => Midwestern State Mustangs
MIL => Millsaps Majors
MIN => Minot State Beavers
MINN => Minnesota Golden Gophers
MIS => Missouri Western Griffons
MISS => Ole Miss Rebels
MIZ => Missouri Tigers
MNST => Minnesota State Mavericks
MONM => Monmouth Hawks
MONT => Montana Grizzlies
MOR => Morningside Chiefs
MORE => Morehead State Eagles
MORG => Morgan State Bears
MOU => Mount Union Raiders
MRSH => Marshall Thundering Herd
MRST => Marist Red Foxes
MSST => Mississippi State Bulldogs
MSU => Michigan State Spartans
MTST => Montana State Bobcats
MTSU => Middle Tennessee Blue Raiders
MTU => Michigan Tech Huskies
MUH => Muhlenberg Mules
MUR => Murray State Racers
MUS => Muskingum Fighting Muskies
MVSU => Mississippi Valley State Delta Devils
NAU => Northern Arizona Lumberjacks
NAVY => Navy Midshipmen
NBY => Newberry Wolves
NCAT => North Carolina A&T Aggies
NCCU => North Carolina Central Eagles
NCST => NC State Wolfpack
ND => Notre Dame Fighting Irish
NDOH => Notre Dame College Falcons
NDSU => North Dakota State Bison
NEB => Nebraska-Kearney Lopers
NEV => Nevada Wolf Pack
NH => New Haven Chargers
NICH => Nicholls Colonels
NIU => Northern Illinois Huskies
NMH => New Mexico Highlands Cowboys
NMI => Northern Michigan Wildcats
NMSU => New Mexico State Aggies
NOR => Univ. of Northwestern-St. Paul Eagles
NORF => Norfolk State Spartans
NW => Northwestern Wildcats
OBE => Oberlin Yeomen
ODU => Old Dominion Monarchs
OHI => Ohio Northern Polar Bears
OHIO => Ohio Bobcats
OKL => Oklahoma Baptist Bison
OKST => Oklahoma State Cowboys
OLI => Olivet College Comets
OMA => Omaha Mavericks
ORST => Oregon State Beavers
OSU => Ohio State Buckeyes
OTT => Otterbein Cardinals
OU => Oklahoma Sooners
PAC => Pacific (OR) Boxers
PENN => Pennsylvania Quakers
PIKE => Pikeville Bears
PITT => Pittsburgh Panthers
PRE => Presentation College Saints
PRI => Principia College Panthers
PRIN => Princeton Tigers
PST => Pittsburg State Gorillas
PSU => Penn State Nittany Lions
RED => Redlands Bulldogs RED => Redlands Bulldogs
RICE => Rice Owls
RICH => Richmond Spiders
RIT => Rochester Yellow Jackets
ROB => Robert Morris (IL) Eagles
ROS => Rose-Hulman Engineers
RUTG => Rutgers Scarlet Knights
SAC => Sacramento State Hornets SAC => Sacramento State Hornets
SAG => Saginaw Valley Cardinals
SDAK => South Dakota Coyotes
SDSU => San Diego State Aztecs SDSU => San Diego State Aztecs
SET => Seton Hill Griffins
SIU => Southern Illinois Salukis
SJSU => San José State Spartans SJSU => San José State Spartans
SLI => Slippery Rock The Rock
SOU => Southwestern College Moundbuilders
SPR => Springfield College Pride
ST => St. Scholastica Saints
STAN => Stanford Cardinal STAN => Stanford Cardinal
STE => Stevenson University Mustangs
STET => Stetson Hatters STET => Stetson Hatters
STO => Stonehill College Skyhawks
SUS => Susquehanna University River Hawks
SUU => Southern Utah Thunderbirds
SYR => Syracuse Orange
TA&M => Texas A&M Aggies
TAY => Taylor Trojans
TEM => Temple Owls
TEX => Texas Longhorns
TIF => Tiffin University Dragons
TLSA => Tulsa Golden Hurricane
TRI => Trinity University (TX) Tigers
TUF => Tufts University Jumbos
TXST => Texas State Bobcats
UAB => UAB Blazers UAB => UAB Blazers
UAPB => Arkansas-Pine Bluff Golden Lions
UCD => UC Davis Aggies
UCF => UCF Knights
UCLA => UCLA Bruins UCLA => UCLA Bruins
UCONN => UConn Huskies
UGA => Georgia Bulldogs UGA => Georgia Bulldogs
UK => Kentucky Wildcats
UL => Louisiana Ragin' Cajuns
ULM => UL Monroe Warhawks
UMD => Minnesota-Duluth Bulldogs
UMDA => UMASS Dartmouth Corsairs
UML => UMass Lowell River Hawks
UNA => North Alabama Lions
UNC => North Carolina Tar Heels
UNCO => Northern Colorado Bears
UND => North Dakota Fighting Hawks
UNH => New Hampshire Wildcats
UNI => University of Mary Marauders
UNLV => UNLV Rebels
UNM => New Mexico Lobos
UNNY => Union Dutchmen
UNT => North Texas Mean Green
UPP => Upper Iowa Peacocks
URI => Rhode Island Rams
USA => South Alabama Jaguars USA => South Alabama Jaguars
USC => USC Trojans USC => USC Trojans
USD => San Diego Toreros
USF => South Florida Bulls USF => South Florida Bulls
USU => Utah State Aggies
UTAH => Utah Utes
UTC => Chattanooga Mocs
UTI => Utica College Pioneers
UVA => Virginia Cavaliers
VAL => Valley City State Vikings
VAN => Vanderbilt Commodores
VILL => Villanova Wildcats
VIR => Virginia State Trojans
VT => Virginia Tech Hokies
WAB => Wabash College Little Giants
WAKE => Wake Forest Demon Deacons
WAS => Washington-Missouri Bears
WASH => Washington Huskies
WAY => Wayne State (MI) Warriors
WES => Westminster College (MO) Blue Jays
WHE => Wheaton College Illinois Thunder
WIL => Wilkes University Colonels
WIN => Wingate Bulldogs
WIS => Wisconsin-Platteville Pioneers
WISC => Wisconsin Badgers
WKU => Western Kentucky Hilltoppers
WOR => Worcester State College Lancers
WSU => Washington State Cougars
WVU => West Virginia Mountaineers
YALE => Yale Bulldogs YALE => Yale Bulldogs
NBA NBA
@@ -1106,6 +755,149 @@ MLB Conferences/Divisions
OAK => Oakland Athletics OAK => Oakland Athletics
SEA => Seattle Mariners SEA => Seattle Mariners
TEX => Texas Rangers TEX => Texas Rangers
Soccer - Premier League (England)
ARS => Arsenal
AVL => Aston Villa
BHA => Brighton & Hove Albion
BOU => AFC Bournemouth
BRE => Brentford
BUR => Burnley
CHE => Chelsea
CRY => Crystal Palace
EVE => Everton
FUL => Fulham
LIV => Liverpool
LUT => Luton Town
MCI => Manchester City
MUN => Manchester United
NEW => Newcastle United
NFO => Nottingham Forest
SHU => Sheffield United
TOT => Tottenham Hotspur
WHU => West Ham United
WOL => Wolverhampton Wanderers
Soccer - La Liga (Spain)
ALA => Alavés
ATH => Athletic Bilbao
ATM => Atlético Madrid
BAR => Barcelona
BET => Real Betis
CAG => Cagliari
CEL => Celta Vigo
ESP => Espanyol
GET => Getafe
GIR => Girona
LAZ => Lazio
LEG => Leganés
RAY => Rayo Vallecano
RMA => Real Madrid
SEV => Sevilla
VAL => Valencia
VLD => Valladolid
Soccer - Bundesliga (Germany)
BOC => VfL Bochum
BOL => VfL Bochum
DOR => Borussia Dortmund
FCA => FC Augsburg
FCB => Bayern Munich
FCU => FC Union Berlin
HAC => Hannover 96
HDH => Hertha BSC
KOL => 1. FC Köln
LEV => Bayer Leverkusen
M05 => Mainz 05
RBL => RB Leipzig
SCF => SC Freiburg
SGE => Eintracht Frankfurt
STU => VfB Stuttgart
SVW => Werder Bremen
TSG => TSG Hoffenheim
WOB => VfL Wolfsburg
Soccer - Serie A (Italy)
ATA => Atalanta
CAG => Cagliari
EMP => Empoli
FIO => Fiorentina
INT => Inter Milan
JUV => Juventus
LAZ => Lazio
MIL => AC Milan
MON => Monza
NAP => Napoli
ROM => Roma
TOR => Torino
UDI => Udinese
VER => Hellas Verona
Soccer - Ligue 1 (France)
LIL => Lille
LPM => Lille
LYON => Lyon
MAR => Marseille
MON => Monaco
NAN => Nantes
NICE => Nice
OL => Olympique Lyonnais
OM => Olympique de Marseille
PAR => Paris Saint-Germain
PSG => Paris Saint-Germain
REN => Rennes
STR => Strasbourg
Soccer - Champions League
AJA => Ajax
ASM => AS Monaco
ASS => AS Saint-Étienne
BOC => VfL Bochum
CEL => Celtic
COM => Club Brugge
FCA => FC Augsburg
FCB => Bayern Munich
FCU => FC Union Berlin
FIO => Fiorentina
GEN => Genoa
HAC => Hannover 96
IPS => Ipswich Town
KSV => Kaiserslautern
LEC => Lecce
LIL => Lille
LIV => Liverpool
M05 => Mainz 05
MCI => Manchester City
MUN => Manchester United
NAN => Nantes
OSA => Osasuna
RBL => RB Leipzig
RCL => RC Lens
RMA => Real Madrid
SCF => SC Freiburg
SGE => Eintracht Frankfurt
SR => Sporting CP
STP => St. Pauli
SVW => Werder Bremen
TFC => Toulouse FC
TOT => Tottenham Hotspur
TSG => TSG Hoffenheim
UDI => Udinese
VEN => Venezia
VFB => VfB Stuttgart
VIL => Villarreal
Soccer - Other Teams
austin => Austin FC
cf_montral => CF Montréal
charlotte => Charlotte FC
dortmund => Borussia Dortmund
gladbach => Borussia Mönchengladbach
lafc => Los Angeles FC
leverkusen => Bayer Leverkusen
nycfc => New York City FC
paris_sg => Paris Saint-Germain
st_louis => St. Louis City SC
MLS Conferences/Divisions MLS Conferences/Divisions
Conferences currently unsupported Conferences currently unsupported

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

1
check_team_images.py Normal file
View File

@@ -0,0 +1 @@

23
cleanup_venv.sh Normal file
View File

@@ -0,0 +1,23 @@
#!/bin/bash
# Cleanup script to remove virtual environment if it exists
# This script removes the venv_web_v2 directory if it exists
set -e
# Get the directory where this script is located
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
echo "Cleaning up virtual environment..."
# Check if virtual environment exists and remove it
if [ -d "venv_web_v2" ]; then
echo "Removing existing virtual environment..."
rm -rf venv_web_v2
echo "Virtual environment removed successfully"
else
echo "No virtual environment found to remove"
fi
echo "Cleanup complete!"

129
clear_cache.py Normal file
View File

@@ -0,0 +1,129 @@
#!/usr/bin/env python3
"""
Cache clearing utility for LEDMatrix
This script allows manual clearing of specific cache keys or all cache data.
"""
import os
import sys
import json
import argparse
from pathlib import Path
# Add the src directory to the path so we can import our modules
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
from cache_manager import CacheManager
def list_cache_keys(cache_manager):
"""List all available cache keys."""
cache_dir = cache_manager.cache_dir
if not cache_dir or not os.path.exists(cache_dir):
print(f"Cache directory does not exist: {cache_dir}")
return []
cache_files = []
for file in os.listdir(cache_dir):
if file.endswith('.json'):
cache_files.append(file[:-5]) # Remove .json extension
return cache_files
def clear_specific_cache(cache_manager, key):
"""Clear a specific cache key."""
try:
cache_manager.clear_cache(key)
print(f"✓ Cleared cache key: {key}")
return True
except Exception as e:
print(f"✗ Error clearing cache key '{key}': {e}")
return False
def clear_all_cache(cache_manager):
"""Clear all cache data."""
try:
cache_manager.clear_cache()
print("✓ Cleared all cache data")
return True
except Exception as e:
print(f"✗ Error clearing all cache: {e}")
return False
def show_cache_info(cache_manager, key=None):
"""Show information about cache entries."""
if key:
try:
data = cache_manager.get(key)
if data is not None:
print(f"Cache key '{key}' exists with data type: {type(data)}")
if isinstance(data, dict):
print(f" Keys: {list(data.keys())}")
if 'games' in data:
print(f" Number of games: {len(data['games']) if isinstance(data['games'], dict) else 'N/A'}")
elif isinstance(data, list):
print(f" Number of items: {len(data)}")
else:
print(f" Data: {str(data)[:100]}...")
else:
print(f"Cache key '{key}' does not exist or is expired")
except Exception as e:
print(f"Error checking cache key '{key}': {e}")
else:
# Show all cache keys
keys = list_cache_keys(cache_manager)
if keys:
print("Available cache keys:")
for key in sorted(keys):
print(f" - {key}")
else:
print("No cache keys found")
def main():
parser = argparse.ArgumentParser(description='Clear LEDMatrix cache data')
parser.add_argument('--list', '-l', action='store_true',
help='List all available cache keys')
parser.add_argument('--clear-all', '-a', action='store_true',
help='Clear all cache data')
parser.add_argument('--clear', '-c', type=str, metavar='KEY',
help='Clear a specific cache key')
parser.add_argument('--info', '-i', type=str, metavar='KEY',
help='Show information about a specific cache key')
args = parser.parse_args()
# Initialize cache manager
cache_manager = CacheManager()
if args.list:
show_cache_info(cache_manager)
elif args.clear_all:
print("Clearing all cache data...")
clear_all_cache(cache_manager)
elif args.clear:
print(f"Clearing cache key: {args.clear}")
clear_specific_cache(cache_manager, args.clear)
elif args.info:
show_cache_info(cache_manager, args.info)
else:
# Default: show available options
print("LEDMatrix Cache Utility")
print("=" * 30)
print()
print("Available commands:")
print(" --list, -l List all cache keys")
print(" --clear-all, -a Clear all cache data")
print(" --clear KEY, -c Clear specific cache key")
print(" --info KEY, -i Show info about cache key")
print()
print("Examples:")
print(" python clear_cache.py --list")
print(" python clear_cache.py --clear milb_live_api_data")
print(" python clear_cache.py --clear-all")
print(" python clear_cache.py --info milb_upcoming_api_data")
print()
# Show current cache status
show_cache_info(cache_manager)
if __name__ == "__main__":
main()

View File

@@ -5,10 +5,10 @@
"start_time": "07:00", "start_time": "07:00",
"end_time": "23:00" "end_time": "23:00"
}, },
"timezone": "America/Chicago", "timezone": "America/New_York",
"location": { "location": {
"city": "Dallas", "city": "Tampa",
"state": "Texas", "state": "Florida",
"country": "US" "country": "US"
}, },
"display": { "display": {
@@ -39,6 +39,7 @@
"daily_forecast": 30, "daily_forecast": 30,
"stock_news": 20, "stock_news": 20,
"odds_ticker": 60, "odds_ticker": 60,
"leaderboard": 60,
"nhl_live": 30, "nhl_live": 30,
"nhl_recent": 30, "nhl_recent": 30,
"nhl_upcoming": 30, "nhl_upcoming": 30,
@@ -69,7 +70,9 @@
"ncaam_basketball_live": 30, "ncaam_basketball_live": 30,
"ncaam_basketball_recent": 30, "ncaam_basketball_recent": 30,
"ncaam_basketball_upcoming": 30, "ncaam_basketball_upcoming": 30,
"music": 30 "music": 30,
"of_the_day": 40,
"news_manager": 60
}, },
"use_short_date_format": true "use_short_date_format": true
}, },
@@ -79,49 +82,117 @@
"update_interval": 1 "update_interval": 1
}, },
"weather": { "weather": {
"enabled": true, "enabled": true,
"update_interval": 1800, "update_interval": 1800,
"units": "imperial", "units": "imperial",
"display_format": "{temp}°F\n{condition}" "display_format": "{temp}\u00b0F\n{condition}"
}, },
"stocks": { "stocks": {
"enabled": true, "enabled": false,
"update_interval": 600, "update_interval": 600,
"scroll_speed": 1,
"scroll_delay": 0.01,
"toggle_chart": true,
"dynamic_duration": true,
"min_duration": 30,
"max_duration": 300,
"duration_buffer": 0.1,
"symbols": [ "symbols": [
"ASTS", "SCHD", "INTC", "NVDA", "T", "VOO", "SMCI" "ASTS",
"SCHD",
"INTC",
"NVDA",
"T",
"VOO",
"SMCI"
], ],
"display_format": "{symbol}: ${price} ({change}%)" "display_format": "{symbol}: ${price} ({change}%)"
}, },
"crypto": { "crypto": {
"enabled": true, "enabled": false,
"update_interval": 600, "update_interval": 600,
"symbols": [ "symbols": [
"BTC-USD", "ETH-USD" "BTC-USD",
"ETH-USD"
], ],
"display_format": "{symbol}: ${price} ({change}%)" "display_format": "{symbol}: ${price} ({change}%)"
}, },
"stock_news": { "stock_news": {
"enabled": true, "enabled": false,
"update_interval": 3600, "update_interval": 3600,
"scroll_speed": 1, "scroll_speed": 1,
"scroll_delay": 0.01, "scroll_delay": 0.01,
"max_headlines_per_symbol": 1, "max_headlines_per_symbol": 1,
"headlines_per_rotation": 2 "headlines_per_rotation": 2,
"dynamic_duration": true,
"min_duration": 30,
"max_duration": 300,
"duration_buffer": 0.1
}, },
"odds_ticker": { "odds_ticker": {
"enabled": true, "enabled": false,
"show_favorite_teams_only": true, "show_favorite_teams_only": true,
"games_per_favorite_team": 1, "games_per_favorite_team": 1,
"max_games_per_league": 5, "max_games_per_league": 5,
"show_odds_only": false, "show_odds_only": false,
"fetch_odds": true,
"sort_order": "soonest", "sort_order": "soonest",
"enabled_leagues": ["nfl","mlb", "ncaa_fb", "milb"], "enabled_leagues": [
"nfl",
"mlb",
"ncaa_fb",
"milb"
],
"update_interval": 3600, "update_interval": 3600,
"scroll_speed": 1, "scroll_speed": 1,
"scroll_delay": 0.01, "scroll_delay": 0.01,
"loop": true, "loop": true,
"future_fetch_days": 50, "future_fetch_days": 50,
"show_channel_logos": true "show_channel_logos": true,
"dynamic_duration": true,
"min_duration": 30,
"max_duration": 300,
"duration_buffer": 0.05
},
"leaderboard": {
"enabled": false,
"enabled_sports": {
"nfl": {
"enabled": true,
"top_teams": 10
},
"nba": {
"enabled": false,
"top_teams": 10
},
"mlb": {
"enabled": false,
"top_teams": 10
},
"ncaa_fb": {
"enabled": true,
"top_teams": 25,
"show_ranking": true
},
"nhl": {
"enabled": false,
"top_teams": 10
},
"ncaam_basketball": {
"enabled": false,
"top_teams": 25
}
},
"update_interval": 3600,
"scroll_speed": 1,
"scroll_delay": 0.01,
"display_duration": 60,
"loop": false,
"request_timeout": 30,
"dynamic_duration": true,
"min_duration": 45,
"max_duration": 600,
"duration_buffer": 0.1
}, },
"calendar": { "calendar": {
"enabled": false, "enabled": false,
@@ -129,18 +200,26 @@
"token_file": "token.pickle", "token_file": "token.pickle",
"update_interval": 3600, "update_interval": 3600,
"max_events": 3, "max_events": 3,
"calendars": ["birthdays"] "calendars": [
"birthdays"
]
}, },
"nhl_scoreboard": { "nhl_scoreboard": {
"enabled": false, "enabled": false,
"live_priority": true,
"live_game_duration": 20,
"show_odds": true, "show_odds": true,
"test_mode": false, "test_mode": false,
"update_interval_seconds": 3600, "update_interval_seconds": 3600,
"live_update_interval": 30, "live_update_interval": 30,
"recent_update_interval": 3600, "recent_update_interval": 3600,
"upcoming_update_interval": 3600, "upcoming_update_interval": 3600,
"recent_games_to_show": 1,
"upcoming_games_to_show": 1,
"show_favorite_teams_only": true, "show_favorite_teams_only": true,
"favorite_teams": ["TB"], "favorite_teams": [
"TB"
],
"logo_dir": "assets/sports/nhl_logos", "logo_dir": "assets/sports/nhl_logos",
"show_records": true, "show_records": true,
"display_modes": { "display_modes": {
@@ -151,6 +230,8 @@
}, },
"nba_scoreboard": { "nba_scoreboard": {
"enabled": false, "enabled": false,
"live_priority": true,
"live_game_duration": 20,
"show_odds": true, "show_odds": true,
"test_mode": false, "test_mode": false,
"update_interval_seconds": 3600, "update_interval_seconds": 3600,
@@ -159,9 +240,12 @@
"odds_update_interval": 3600, "odds_update_interval": 3600,
"recent_update_interval": 3600, "recent_update_interval": 3600,
"upcoming_update_interval": 3600, "upcoming_update_interval": 3600,
"recent_game_hours": 72, "recent_games_to_show": 1,
"upcoming_games_to_show": 1,
"show_favorite_teams_only": true, "show_favorite_teams_only": true,
"favorite_teams": ["DAL"], "favorite_teams": [
"DAL"
],
"logo_dir": "assets/sports/nba_logos", "logo_dir": "assets/sports/nba_logos",
"show_records": true, "show_records": true,
"display_modes": { "display_modes": {
@@ -171,27 +255,34 @@
} }
}, },
"nfl_scoreboard": { "nfl_scoreboard": {
"enabled": true, "enabled": false,
"live_priority": true,
"live_game_duration": 30,
"show_odds": true, "show_odds": true,
"test_mode": false, "test_mode": false,
"update_interval_seconds": 3600, "update_interval_seconds": 3600,
"live_update_interval": 30, "live_update_interval": 30,
"live_odds_update_interval": 3600, "live_odds_update_interval": 3600,
"odds_update_interval": 3600, "odds_update_interval": 3600,
"recent_games_to_show": 0, "recent_games_to_show": 1,
"upcoming_games_to_show": 2, "upcoming_games_to_show": 1,
"show_favorite_teams_only": true, "show_favorite_teams_only": true,
"favorite_teams": ["TB", "DAL"], "favorite_teams": [
"TB",
"DAL"
],
"logo_dir": "assets/sports/nfl_logos", "logo_dir": "assets/sports/nfl_logos",
"show_records": true, "show_records": true,
"display_modes": { "display_modes": {
"nfl_live": true, "nfl_live": true,
"nfl_recent": false, "nfl_recent": true,
"nfl_upcoming": true "nfl_upcoming": true
} }
}, },
"ncaa_fb_scoreboard": { "ncaa_fb_scoreboard": {
"enabled": true, "enabled": false,
"live_priority": true,
"live_game_duration": 20,
"show_odds": true, "show_odds": true,
"test_mode": false, "test_mode": false,
"update_interval_seconds": 3600, "update_interval_seconds": 3600,
@@ -199,29 +290,39 @@
"live_odds_update_interval": 3600, "live_odds_update_interval": 3600,
"odds_update_interval": 3600, "odds_update_interval": 3600,
"season_cache_duration_seconds": 86400, "season_cache_duration_seconds": 86400,
"recent_games_to_show": 0, "recent_games_to_show": 1,
"upcoming_games_to_show": 2, "upcoming_games_to_show": 1,
"show_favorite_teams_only": true, "show_favorite_teams_only": true,
"favorite_teams": ["UGA", "AUB"], "favorite_teams": [
"UGA",
"AUB"
],
"logo_dir": "assets/sports/ncaa_fbs_logos", "logo_dir": "assets/sports/ncaa_fbs_logos",
"show_records": true, "show_records": true,
"show_ranking": true,
"display_modes": { "display_modes": {
"ncaa_fb_live": true, "ncaa_fb_live": true,
"ncaa_fb_recent": false, "ncaa_fb_recent": true ,
"ncaa_fb_upcoming": true "ncaa_fb_upcoming": true
} }
}, },
"ncaa_baseball_scoreboard": { "ncaa_baseball_scoreboard": {
"enabled": false, "enabled": false,
"live_priority": true,
"live_game_duration": 30,
"show_odds": true, "show_odds": true,
"test_mode": false, "test_mode": false,
"update_interval_seconds": 3600, "update_interval_seconds": 3600,
"live_update_interval": 30, "live_update_interval": 30,
"recent_update_interval": 3600, "recent_update_interval": 3600,
"upcoming_update_interval": 3600, "upcoming_update_interval": 3600,
"recent_game_hours": 72, "recent_games_to_show": 1,
"upcoming_games_to_show": 1,
"show_favorite_teams_only": true, "show_favorite_teams_only": true,
"favorite_teams": ["UGA", "AUB"], "favorite_teams": [
"UGA",
"AUB"
],
"logo_dir": "assets/sports/ncaa_fbs_logos", "logo_dir": "assets/sports/ncaa_fbs_logos",
"show_records": true, "show_records": true,
"display_modes": { "display_modes": {
@@ -232,13 +333,19 @@
}, },
"ncaam_basketball_scoreboard": { "ncaam_basketball_scoreboard": {
"enabled": false, "enabled": false,
"live_priority": true,
"live_game_duration": 20,
"show_odds": true, "show_odds": true,
"test_mode": false, "test_mode": false,
"update_interval_seconds": 3600, "update_interval_seconds": 3600,
"live_update_interval": 30, "live_update_interval": 30,
"recent_game_hours": 72, "recent_games_to_show": 1,
"upcoming_games_to_show": 1,
"show_favorite_teams_only": true, "show_favorite_teams_only": true,
"favorite_teams": ["UGA", "AUB"], "favorite_teams": [
"UGA",
"AUB"
],
"logo_dir": "assets/sports/ncaa_fbs_logos", "logo_dir": "assets/sports/ncaa_fbs_logos",
"show_records": true, "show_records": true,
"display_modes": { "display_modes": {
@@ -248,11 +355,13 @@
} }
}, },
"youtube": { "youtube": {
"enabled": true, "enabled": false,
"update_interval": 3600 "update_interval": 3600
}, },
"mlb": { "mlb": {
"enabled": true, "enabled": false,
"live_priority": false,
"live_game_duration": 30,
"show_odds": true, "show_odds": true,
"test_mode": false, "test_mode": false,
"update_interval_seconds": 3600, "update_interval_seconds": 3600,
@@ -264,7 +373,10 @@
"recent_games_to_show": 1, "recent_games_to_show": 1,
"upcoming_games_to_show": 1, "upcoming_games_to_show": 1,
"show_favorite_teams_only": true, "show_favorite_teams_only": true,
"favorite_teams": ["TB", "TEX"], "favorite_teams": [
"TB",
"TEX"
],
"logo_dir": "assets/sports/mlb_logos", "logo_dir": "assets/sports/mlb_logos",
"show_records": true, "show_records": true,
"display_modes": { "display_modes": {
@@ -274,7 +386,9 @@
} }
}, },
"milb": { "milb": {
"enabled": true, "enabled": false,
"live_priority": false,
"live_game_duration": 30,
"test_mode": false, "test_mode": false,
"update_interval_seconds": 3600, "update_interval_seconds": 3600,
"live_update_interval": 30, "live_update_interval": 30,
@@ -282,7 +396,9 @@
"upcoming_update_interval": 3600, "upcoming_update_interval": 3600,
"recent_games_to_show": 1, "recent_games_to_show": 1,
"upcoming_games_to_show": 1, "upcoming_games_to_show": 1,
"favorite_teams": ["TAM"], "favorite_teams": [
"TAM"
],
"logo_dir": "assets/sports/milb_logos", "logo_dir": "assets/sports/milb_logos",
"show_records": true, "show_records": true,
"upcoming_fetch_days": 7, "upcoming_fetch_days": 7,
@@ -299,22 +415,37 @@
"font_size": 8, "font_size": 8,
"scroll": true, "scroll": true,
"scroll_speed": 40, "scroll_speed": 40,
"text_color": [255, 0, 0], "text_color": [
"background_color": [0, 0, 0], 255,
0,
0
],
"background_color": [
0,
0,
0
],
"scroll_gap_width": 32 "scroll_gap_width": 32
}, },
"soccer_scoreboard": { "soccer_scoreboard": {
"enabled": false, "enabled": false,
"live_priority": true,
"live_game_duration": 30,
"show_odds": true, "show_odds": true,
"test_mode": false, "test_mode": false,
"update_interval_seconds": 3600, "update_interval_seconds": 3600,
"live_update_interval": 30, "live_update_interval": 30,
"recent_update_interval": 3600, "recent_update_interval": 3600,
"upcoming_update_interval": 3600, "upcoming_update_interval": 3600,
"recent_game_hours": 168, "recent_games_to_show": 1,
"upcoming_games_to_show": 1,
"show_favorite_teams_only": true, "show_favorite_teams_only": true,
"favorite_teams": ["LIV"], "favorite_teams": [
"leagues": ["eng.1", "esp.1", "ger.1", "ita.1", "fra.1", "uefa.champions", "usa.1"], "DAL"
],
"leagues": [
"usa.1"
],
"logo_dir": "assets/sports/soccer_logos", "logo_dir": "assets/sports/soccer_logos",
"show_records": true, "show_records": true,
"display_modes": { "display_modes": {
@@ -324,9 +455,66 @@
} }
}, },
"music": { "music": {
"enabled": true, "enabled": false,
"preferred_source": "ytm", "preferred_source": "ytm",
"YTM_COMPANION_URL": "http://192.168.86.12:9863", "YTM_COMPANION_URL": "http://192.168.86.12:9863",
"POLLING_INTERVAL_SECONDS": 1 "POLLING_INTERVAL_SECONDS": 1
},
"of_the_day": {
"enabled": false,
"display_rotate_interval": 20,
"update_interval": 3600,
"subtitle_rotate_interval": 10,
"category_order": [
"word_of_the_day",
"slovenian_word_of_the_day"
],
"categories": {
"word_of_the_day": {
"enabled": true,
"data_file": "of_the_day/word_of_the_day.json",
"display_name": "Word of the Day"
},
"slovenian_word_of_the_day": {
"enabled": true,
"data_file": "of_the_day/slovenian_word_of_the_day.json",
"display_name": "Slovenian Word of the Day"
}
}
},
"news_manager": {
"enabled": false,
"update_interval": 300,
"scroll_speed": 1,
"scroll_delay": 0.01,
"headlines_per_feed": 2,
"enabled_feeds": [
"NFL",
"NCAA FB",
"F1",
"BBC F1"
],
"custom_feeds": {
"F1": "https://www.espn.com/espn/rss/rpm/news",
"BBC F1": "http://feeds.bbci.co.uk/sport/formula1/rss.xml"
},
"rotation_enabled": true,
"rotation_threshold": 3,
"dynamic_duration": true,
"min_duration": 30,
"max_duration": 300,
"duration_buffer": 0.1,
"font_size": 8,
"font_path": "assets/fonts/PressStart2P-Regular.ttf",
"text_color": [
255,
255,
255
],
"separator_color": [
255,
0,
0
]
} }
} }

124
configure_web_sudo.sh Normal file
View File

@@ -0,0 +1,124 @@
#!/bin/bash
# LED Matrix Web Interface Sudo Configuration Script
# This script configures passwordless sudo access for the web interface user
set -e
echo "Configuring passwordless sudo access for LED Matrix Web Interface..."
# Get the current user (should be the user running the web interface)
WEB_USER=$(whoami)
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "Detected web interface user: $WEB_USER"
echo "Project directory: $PROJECT_DIR"
# Check if running as root
if [ "$EUID" -eq 0 ]; then
echo "Error: This script should not be run as root."
echo "Run it as the user that will be running the web interface."
exit 1
fi
# Get the full paths to commands
PYTHON_PATH=$(which python3)
SYSTEMCTL_PATH=$(which systemctl)
REBOOT_PATH=$(which reboot)
POWEROFF_PATH=$(which poweroff)
BASH_PATH=$(which bash)
echo "Command paths:"
echo " Python: $PYTHON_PATH"
echo " Systemctl: $SYSTEMCTL_PATH"
echo " Reboot: $REBOOT_PATH"
echo " Poweroff: $POWEROFF_PATH"
echo " Bash: $BASH_PATH"
# Create a temporary sudoers file
TEMP_SUDOERS="/tmp/ledmatrix_web_sudoers_$$"
cat > "$TEMP_SUDOERS" << EOF
# LED Matrix Web Interface passwordless sudo configuration
# This allows the web interface user to run specific commands without a password
# Allow $WEB_USER to run specific commands without a password for the LED Matrix web interface
$WEB_USER ALL=(ALL) NOPASSWD: $REBOOT_PATH
$WEB_USER ALL=(ALL) NOPASSWD: $POWEROFF_PATH
$WEB_USER ALL=(ALL) NOPASSWD: $SYSTEMCTL_PATH start ledmatrix.service
$WEB_USER ALL=(ALL) NOPASSWD: $SYSTEMCTL_PATH stop ledmatrix.service
$WEB_USER ALL=(ALL) NOPASSWD: $SYSTEMCTL_PATH restart ledmatrix.service
$WEB_USER ALL=(ALL) NOPASSWD: $SYSTEMCTL_PATH enable ledmatrix.service
$WEB_USER ALL=(ALL) NOPASSWD: $SYSTEMCTL_PATH disable ledmatrix.service
$WEB_USER ALL=(ALL) NOPASSWD: $SYSTEMCTL_PATH status ledmatrix.service
$WEB_USER ALL=(ALL) NOPASSWD: $PYTHON_PATH $PROJECT_DIR/display_controller.py
$WEB_USER ALL=(ALL) NOPASSWD: $BASH_PATH $PROJECT_DIR/start_display.sh
$WEB_USER ALL=(ALL) NOPASSWD: $BASH_PATH $PROJECT_DIR/stop_display.sh
EOF
echo ""
echo "Generated sudoers configuration:"
echo "--------------------------------"
cat "$TEMP_SUDOERS"
echo "--------------------------------"
echo ""
echo "This configuration will allow the web interface to:"
echo "- Start/stop/restart the ledmatrix service"
echo "- Enable/disable the ledmatrix service"
echo "- Check service status"
echo "- Run display_controller.py directly"
echo "- Execute start_display.sh and stop_display.sh"
echo "- Reboot and shutdown the system"
echo ""
# Ask for confirmation
read -p "Do you want to apply this configuration? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Configuration cancelled."
rm -f "$TEMP_SUDOERS"
exit 0
fi
# Apply the configuration using visudo
echo "Applying sudoers configuration..."
if sudo cp "$TEMP_SUDOERS" /etc/sudoers.d/ledmatrix_web; then
echo "Configuration applied successfully!"
echo ""
echo "Testing sudo access..."
# Test a few commands
if sudo -n systemctl status ledmatrix.service > /dev/null 2>&1; then
echo "✓ systemctl status ledmatrix.service - OK"
else
echo "✗ systemctl status ledmatrix.service - Failed"
fi
if sudo -n test -f "$PROJECT_DIR/start_display.sh"; then
echo "✓ File access test - OK"
else
echo "✗ File access test - Failed"
fi
echo ""
echo "Configuration complete! The web interface should now be able to:"
echo "- Execute system commands without password prompts"
echo "- Start and stop the LED matrix display"
echo "- Restart the system if needed"
echo ""
echo "You may need to restart the web interface service for changes to take effect:"
echo " sudo systemctl restart ledmatrix-web.service"
else
echo "Error: Failed to apply sudoers configuration."
echo "You may need to run this script with sudo privileges."
rm -f "$TEMP_SUDOERS"
exit 1
fi
# Clean up
rm -f "$TEMP_SUDOERS"
echo ""
echo "Configuration script completed successfully!"

1
create_league_logos.py Normal file
View File

@@ -0,0 +1 @@

1
create_ncaa_logos.py Normal file
View File

@@ -0,0 +1 @@

107
debug_of_the_day.py Normal file
View File

@@ -0,0 +1,107 @@
#!/usr/bin/env python3
"""
Debug script for OfTheDayManager issues
Run this on the Raspberry Pi to diagnose the problem
Usage:
1. Copy this file to your Raspberry Pi
2. Run: python3 debug_of_the_day.py
3. Check the output for any errors or issues
This script will help identify why the OfTheDayManager is not loading data files.
"""
import json
import os
import sys
from datetime import date
def debug_of_the_day():
print("=== OfTheDayManager Debug Script ===")
print(f"Current working directory: {os.getcwd()}")
print(f"Python path: {sys.path}")
# Check if we're in the right directory
if not os.path.exists('config/config.json'):
print("ERROR: config/config.json not found. Make sure you're running from the LEDMatrix root directory.")
return
# Load the actual config
try:
with open('config/config.json', 'r') as f:
config = json.load(f)
print("✓ Successfully loaded config.json")
except Exception as e:
print(f"ERROR loading config.json: {e}")
return
# Check of_the_day configuration
of_the_day_config = config.get('of_the_day', {})
print(f"OfTheDay enabled: {of_the_day_config.get('enabled', False)}")
if not of_the_day_config.get('enabled', False):
print("OfTheDay is disabled in config!")
return
categories = of_the_day_config.get('categories', {})
print(f"Categories configured: {list(categories.keys())}")
# Test each category
today = date.today()
day_of_year = today.timetuple().tm_yday
print(f"Today is day {day_of_year} of the year")
for category_name, category_config in categories.items():
print(f"\n--- Testing category: {category_name} ---")
print(f"Category enabled: {category_config.get('enabled', True)}")
if not category_config.get('enabled', True):
print("Category is disabled, skipping...")
continue
data_file = category_config.get('data_file')
print(f"Data file: {data_file}")
# Test path resolution
if not os.path.isabs(data_file):
if data_file.startswith('of_the_day/'):
file_path = os.path.join(os.getcwd(), data_file)
else:
file_path = os.path.join(os.getcwd(), 'of_the_day', data_file)
else:
file_path = data_file
file_path = os.path.abspath(file_path)
print(f"Resolved path: {file_path}")
print(f"File exists: {os.path.exists(file_path)}")
if not os.path.exists(file_path):
print(f"ERROR: Data file not found at {file_path}")
continue
# Test JSON loading
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
print(f"✓ Successfully loaded JSON with {len(data)} items")
# Check for today's entry
day_key = str(day_of_year)
if day_key in data:
item = data[day_key]
print(f"✓ Found entry for day {day_of_year}: {item.get('title', 'No title')}")
else:
print(f"✗ No entry found for day {day_of_year}")
# Show some nearby entries
nearby_days = [k for k in data.keys() if k.isdigit() and abs(int(k) - day_of_year) <= 5]
print(f"Nearby days with entries: {sorted(nearby_days)}")
except Exception as e:
print(f"ERROR loading JSON: {e}")
import traceback
traceback.print_exc()
print("\n=== Debug complete ===")
if __name__ == "__main__":
debug_of_the_day()

120
enable_news_manager.py Normal file
View File

@@ -0,0 +1,120 @@
#!/usr/bin/env python3
import json
import sys
import os
def enable_news_manager():
"""Enable the news manager in the configuration"""
config_path = "config/config.json"
try:
# Load current config
with open(config_path, 'r') as f:
config = json.load(f)
# Enable news manager
if 'news_manager' not in config:
print("News manager configuration not found!")
return False
config['news_manager']['enabled'] = True
# Save updated config
with open(config_path, 'w') as f:
json.dump(config, f, indent=4)
print("SUCCESS: News manager enabled successfully!")
print(f"Enabled feeds: {config['news_manager']['enabled_feeds']}")
print(f"Headlines per feed: {config['news_manager']['headlines_per_feed']}")
print(f"Update interval: {config['news_manager']['update_interval']} seconds")
return True
except Exception as e:
print(f"ERROR: Error enabling news manager: {e}")
return False
def disable_news_manager():
"""Disable the news manager in the configuration"""
config_path = "config/config.json"
try:
# Load current config
with open(config_path, 'r') as f:
config = json.load(f)
# Disable news manager
if 'news_manager' in config:
config['news_manager']['enabled'] = False
# Save updated config
with open(config_path, 'w') as f:
json.dump(config, f, indent=4)
print("SUCCESS: News manager disabled successfully!")
else:
print("News manager configuration not found!")
return True
except Exception as e:
print(f"ERROR: Error disabling news manager: {e}")
return False
def show_status():
"""Show current news manager status"""
config_path = "config/config.json"
try:
with open(config_path, 'r') as f:
config = json.load(f)
if 'news_manager' not in config:
print("News manager configuration not found!")
return
news_config = config['news_manager']
print("News Manager Status:")
print("=" * 30)
print(f"Enabled: {news_config.get('enabled', False)}")
print(f"Update Interval: {news_config.get('update_interval', 300)} seconds")
print(f"Scroll Speed: {news_config.get('scroll_speed', 2)} pixels/frame")
print(f"Scroll Delay: {news_config.get('scroll_delay', 0.02)} seconds/frame")
print(f"Headlines per Feed: {news_config.get('headlines_per_feed', 2)}")
print(f"Enabled Feeds: {news_config.get('enabled_feeds', [])}")
print(f"Rotation Enabled: {news_config.get('rotation_enabled', True)}")
print(f"Rotation Threshold: {news_config.get('rotation_threshold', 3)}")
print(f"Font Size: {news_config.get('font_size', 12)}")
custom_feeds = news_config.get('custom_feeds', {})
if custom_feeds:
print("Custom Feeds:")
for name, url in custom_feeds.items():
print(f" {name}: {url}")
else:
print("No custom feeds configured")
except Exception as e:
print(f"ERROR: Error reading configuration: {e}")
def main():
if len(sys.argv) < 2:
print("Usage: python3 enable_news_manager.py [enable|disable|status]")
sys.exit(1)
command = sys.argv[1].lower()
if command == "enable":
enable_news_manager()
elif command == "disable":
disable_news_manager()
elif command == "status":
show_status()
else:
print("Invalid command. Use: enable, disable, or status")
sys.exit(1)
if __name__ == "__main__":
main()

671
first_time_install.sh Normal file
View File

@@ -0,0 +1,671 @@
#!/bin/bash
# LED Matrix First-Time Installation Script
# This script handles the complete setup for a new LED Matrix installation
set -Eeuo pipefail
# Global state for nicer error messages
CURRENT_STEP="initialization"
# Error handler for friendlier failures
on_error() {
local exit_code=$?
local line_no=${1:-unknown}
echo "✗ An error occurred during: $CURRENT_STEP (line $line_no, exit $exit_code)" >&2
if [ -n "${LOG_FILE:-}" ]; then
echo "See the log for details: $LOG_FILE" >&2
echo "-- Last 50 lines from log --" >&2
tail -n 50 "$LOG_FILE" >&2 || true
fi
echo "\nCommon fixes:" >&2
echo "- Ensure the Pi is online (try: ping -c1 8.8.8.8)." >&2
echo "- If you saw an APT lock error: wait a minute, close other installers, then run: sudo dpkg --configure -a" >&2
echo "- Re-run this script. It is safe to run multiple times." >&2
exit "$exit_code"
}
trap 'on_error $LINENO' ERR
echo "=========================================="
echo "LED Matrix First-Time Installation Script"
echo "=========================================="
echo ""
# Show device model if available (helps users confirm they're on a Raspberry Pi)
if [ -r /proc/device-tree/model ]; then
DEVICE_MODEL=$(tr -d '\0' </proc/device-tree/model)
echo "Detected device: $DEVICE_MODEL"
else
echo "⚠ Could not detect Raspberry Pi model (continuing anyway)"
fi
# Get the actual user who invoked sudo (set after we ensure sudo below)
if [ -n "${SUDO_USER:-}" ]; then
ACTUAL_USER="$SUDO_USER"
else
ACTUAL_USER=$(whoami)
fi
# Get the home directory of the actual user
USER_HOME=$(eval echo ~$ACTUAL_USER)
# Determine the Project Root Directory (where this script is located)
PROJECT_ROOT_DIR=$(cd "$(dirname "$0")" && pwd)
echo "Detected user: $ACTUAL_USER"
echo "User home directory: $USER_HOME"
echo "Project directory: $PROJECT_ROOT_DIR"
echo ""
# Check if running as root; if not, try to elevate automatically for novices
if [ "$EUID" -ne 0 ]; then
echo "This script needs administrator privileges. Attempting to re-run with sudo..."
exec sudo -E env LEDMATRIX_ELEVATED=1 bash "$0" "$@"
fi
echo "✓ Running as root (required for installation)"
# Initialize logging
LOG_DIR="$PROJECT_ROOT_DIR/logs"
mkdir -p "$LOG_DIR"
LOG_FILE="$LOG_DIR/first_time_install_$(date +%Y%m%d_%H%M%S).log"
exec > >(tee -a "$LOG_FILE") 2>&1
echo "Logging to: $LOG_FILE"
# Args and options (novice-friendly defaults)
ASSUME_YES=${LEDMATRIX_ASSUME_YES:-0}
SKIP_SOUND=${LEDMATRIX_SKIP_SOUND:-0}
SKIP_PERF=${LEDMATRIX_SKIP_PERF:-0}
SKIP_REBOOT_PROMPT=${LEDMATRIX_SKIP_REBOOT_PROMPT:-0}
usage() {
cat <<USAGE
Usage: sudo ./first_time_install.sh [options]
Options:
-y, --yes Proceed without interactive confirmations
--force-rebuild Force rebuild of rpi-rgb-led-matrix even if present
--skip-sound Skip sound module configuration
--skip-perf Skip performance tweaks (isolcpus/audio)
--no-reboot-prompt Do not prompt for reboot at the end
-h, --help Show this help message and exit
Environment variables (same effect as flags):
LEDMATRIX_ASSUME_YES=1, RPI_RGB_FORCE_REBUILD=1, LEDMATRIX_SKIP_SOUND=1,
LEDMATRIX_SKIP_PERF=1, LEDMATRIX_SKIP_REBOOT_PROMPT=1
USAGE
}
while [ $# -gt 0 ]; do
case "$1" in
-y|--yes) ASSUME_YES=1 ;;
--force-rebuild) RPI_RGB_FORCE_REBUILD=1 ;;
--skip-sound) SKIP_SOUND=1 ;;
--skip-perf) SKIP_PERF=1 ;;
--no-reboot-prompt) SKIP_REBOOT_PROMPT=1 ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown option: $1"; usage; exit 1 ;;
esac
shift
done
# Helpers
retry() {
local attempt=1
local max_attempts=3
local delay_seconds=5
while true; do
"$@" && return 0
local status=$?
if [ $attempt -ge $max_attempts ]; then
echo "✗ Command failed after $attempt attempts: $*"
return $status
fi
echo "⚠ Command failed (attempt $attempt/$max_attempts). Retrying in ${delay_seconds}s: $*"
attempt=$((attempt+1))
sleep "$delay_seconds"
done
}
apt_update() { retry apt update; }
apt_install() { retry apt install -y "$@"; }
apt_remove() { apt-get remove -y "$@" || true; }
check_network() {
if command -v ping >/dev/null 2>&1; then
if ping -c 1 -W 3 8.8.8.8 >/dev/null 2>&1; then
return 0
fi
fi
if command -v curl >/dev/null 2>&1; then
if curl -Is --max-time 5 http://deb.debian.org >/dev/null 2>&1; then
return 0
fi
fi
echo "✗ No internet connectivity detected."
echo "Please connect your Raspberry Pi to the internet and re-run this script."
exit 1
}
echo ""
echo "This script will perform the following steps:"
echo "1. Install system dependencies"
echo "2. Fix cache permissions"
echo "3. Install main LED Matrix service"
echo "4. Install Python project dependencies (requirements.txt)"
echo "5. Build and install rpi-rgb-led-matrix and test import"
echo "6. Install web interface dependencies"
echo "7. Install web interface service"
echo "8. Configure web interface permissions"
echo "9. Configure passwordless sudo access"
echo "10. Set up proper file ownership"
echo "11. Configure sound module to avoid conflicts"
echo "12. Apply performance optimizations"
echo "13. Test the installation"
echo ""
# Ask for confirmation
if [ "$ASSUME_YES" = "1" ]; then
echo "Non-interactive mode: proceeding with installation."
else
read -p "Do you want to proceed with the installation? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Installation cancelled."
exit 0
fi
fi
echo ""
CLEAR='
'
CURRENT_STEP="Install system dependencies"
echo "Step 1: Installing system dependencies..."
echo "----------------------------------------"
# Ensure network is available before APT operations
check_network
# Update package list
apt_update
# Install required system packages
echo "Installing Python packages and dependencies..."
apt_install python3-pip python3-venv python3-dev python3-pil python3-pil.imagetk build-essential python3-setuptools python3-wheel cython3
# Install additional system dependencies that might be needed
echo "Installing additional system dependencies..."
apt_install git curl wget unzip
echo "✓ System dependencies installed"
echo ""
CURRENT_STEP="Fix cache permissions"
echo "Step 2: Fixing cache permissions..."
echo "----------------------------------"
# Run the cache permissions fix
if [ -f "$PROJECT_ROOT_DIR/fix_cache_permissions.sh" ]; then
echo "Running cache permissions fix..."
bash "$PROJECT_ROOT_DIR/fix_cache_permissions.sh"
echo "✓ Cache permissions fixed"
else
echo "⚠ Cache permissions script not found, creating cache directories manually..."
mkdir -p /var/cache/ledmatrix
chown "$ACTUAL_USER:$ACTUAL_USER" /var/cache/ledmatrix
chmod 777 /var/cache/ledmatrix
echo "✓ Cache directories created manually"
fi
echo ""
CURRENT_STEP="Install main LED Matrix service"
echo "Step 3: Installing main LED Matrix service..."
echo "---------------------------------------------"
# Run the main service installation (idempotent)
if [ -f "$PROJECT_ROOT_DIR/install_service.sh" ]; then
echo "Running main service installation..."
bash "$PROJECT_ROOT_DIR/install_service.sh"
echo "✓ Main LED Matrix service installed"
else
echo "✗ Main service installation script not found at $PROJECT_ROOT_DIR/install_service.sh"
echo "Please ensure you are running this script from the project root: $PROJECT_ROOT_DIR"
exit 1
fi
echo ""
CURRENT_STEP="Ensure secrets configuration exists"
echo "Step 3.1: Ensuring secrets configuration exists..."
echo "-----------------------------------------------"
# Ensure config directory exists
mkdir -p "$PROJECT_ROOT_DIR/config"
chmod 755 "$PROJECT_ROOT_DIR/config" || true
# Create config_secrets.json from template if missing
if [ ! -f "$PROJECT_ROOT_DIR/config/config_secrets.json" ]; then
if [ -f "$PROJECT_ROOT_DIR/config/config_secrets.template.json" ]; then
echo "Creating config/config_secrets.json from template..."
cp "$PROJECT_ROOT_DIR/config/config_secrets.template.json" "$PROJECT_ROOT_DIR/config/config_secrets.json"
chown "$ACTUAL_USER:$ACTUAL_USER" "$PROJECT_ROOT_DIR/config/config_secrets.json" || true
chmod 640 "$PROJECT_ROOT_DIR/config/config_secrets.json"
echo "✓ Secrets file created from template"
else
echo "⚠ Template config/config_secrets.template.json not found; creating a minimal secrets file"
cat > "$PROJECT_ROOT_DIR/config/config_secrets.json" <<'EOF'
{
"weather": {
"api_key": "YOUR_OPENWEATHERMAP_API_KEY"
}
}
EOF
chown "$ACTUAL_USER:$ACTUAL_USER" "$PROJECT_ROOT_DIR/config/config_secrets.json" || true
chmod 640 "$PROJECT_ROOT_DIR/config/config_secrets.json"
echo "✓ Minimal secrets file created"
fi
else
echo "Secrets file already exists; leaving as-is"
fi
echo ""
CURRENT_STEP="Install project Python dependencies"
echo "Step 4: Installing Python project dependencies..."
echo "-----------------------------------------------"
# Install main project Python dependencies
cd "$PROJECT_ROOT_DIR"
if [ -f "$PROJECT_ROOT_DIR/requirements.txt" ]; then
python3 -m pip install --break-system-packages -r "$PROJECT_ROOT_DIR/requirements.txt"
else
echo "⚠ requirements.txt not found; skipping main dependency install"
fi
echo "✓ Project Python dependencies installed"
echo ""
CURRENT_STEP="Build and install rpi-rgb-led-matrix"
echo "Step 5: Building and installing rpi-rgb-led-matrix..."
echo "-----------------------------------------------------"
# If already installed and not forcing rebuild, skip expensive build
if python3 -c 'from rgbmatrix import RGBMatrix, RGBMatrixOptions' >/dev/null 2>&1 && [ "${RPI_RGB_FORCE_REBUILD:-0}" != "1" ]; then
echo "rgbmatrix Python package already available; skipping build (set RPI_RGB_FORCE_REBUILD=1 to force rebuild)."
else
# Build and install rpi-rgb-led-matrix Python bindings
if [ -d "$PROJECT_ROOT_DIR/rpi-rgb-led-matrix-master" ]; then
pushd "$PROJECT_ROOT_DIR/rpi-rgb-led-matrix-master" >/dev/null
echo "Building rpi-rgb-led-matrix Python bindings..."
make build-python PYTHON=$(which python3)
cd bindings/python
echo "Installing rpi-rgb-led-matrix Python package via pip..."
python3 -m pip install --break-system-packages .
popd >/dev/null
else
echo "✗ rpi-rgb-led-matrix-master directory not found at $PROJECT_ROOT_DIR"
echo "You can clone it with: git submodule update --init --recursive (if applicable)"
exit 1
fi
echo "Running rgbmatrix import test..."
if python3 - <<'PY'
from importlib.metadata import version, PackageNotFoundError
try:
from rgbmatrix import RGBMatrix, RGBMatrixOptions
try:
print("Success! rgbmatrix version:", version('rgbmatrix'))
except PackageNotFoundError:
print("Success! rgbmatrix installed (version unknown)")
except Exception as e:
raise SystemExit(f"rgbmatrix import failed: {e}")
PY
then
echo "✓ rpi-rgb-led-matrix installed and verified"
else
echo "✗ rpi-rgb-led-matrix import test failed"
exit 1
fi
fi
echo ""
CURRENT_STEP="Install web interface dependencies"
echo "Step 6: Installing web interface dependencies..."
echo "------------------------------------------------"
# Install web interface dependencies
echo "Installing Python dependencies for web interface..."
cd "$PROJECT_ROOT_DIR"
# Try to install dependencies using the smart installer if available
if [ -f "$PROJECT_ROOT_DIR/install_dependencies_apt.py" ]; then
echo "Using smart dependency installer..."
python3 "$PROJECT_ROOT_DIR/install_dependencies_apt.py"
else
echo "Using pip to install dependencies..."
if [ -f "$PROJECT_ROOT_DIR/requirements_web_v2.txt" ]; then
python3 -m pip install --break-system-packages -r requirements_web_v2.txt
else
echo "⚠ requirements_web_v2.txt not found; skipping web dependency install"
fi
fi
echo "✓ Web interface dependencies installed"
echo ""
CURRENT_STEP="Install web interface service"
echo "Step 7: Installing web interface service..."
echo "-------------------------------------------"
if [ -f "$PROJECT_ROOT_DIR/install_web_service.sh" ]; then
if [ ! -f "/etc/systemd/system/ledmatrix-web.service" ]; then
bash "$PROJECT_ROOT_DIR/install_web_service.sh"
# Ensure systemd sees any new/changed unit files
systemctl daemon-reload || true
echo "✓ Web interface service installed"
else
echo "ledmatrix-web.service already present; preserving existing configuration and skipping static installer"
fi
else
echo "⚠ install_web_service.sh not found; skipping web service installation"
fi
echo ""
CURRENT_STEP="Harden systemd unit file permissions"
echo "Step 7.1: Setting systemd unit file permissions..."
echo "-----------------------------------------------"
for unit in "/etc/systemd/system/ledmatrix.service" "/etc/systemd/system/ledmatrix-web.service"; do
if [ -f "$unit" ]; then
chown root:root "$unit" || true
chmod 644 "$unit" || true
fi
done
systemctl daemon-reload || true
echo "✓ Systemd unit file permissions set"
echo ""
CURRENT_STEP="Configure web interface permissions"
echo "Step 8: Configuring web interface permissions..."
echo "------------------------------------------------"
# Add user to required groups (idempotent)
echo "Adding user to systemd-journal group..."
if id -nG "$ACTUAL_USER" | grep -qw systemd-journal; then
echo "User $ACTUAL_USER already in systemd-journal"
else
usermod -a -G systemd-journal "$ACTUAL_USER"
fi
echo "Adding user to adm group..."
if id -nG "$ACTUAL_USER" | grep -qw adm; then
echo "User $ACTUAL_USER already in adm"
else
usermod -a -G adm "$ACTUAL_USER"
fi
echo "✓ User added to required groups"
echo ""
CURRENT_STEP="Configure passwordless sudo access"
echo "Step 9: Configuring passwordless sudo access..."
echo "------------------------------------------------"
# Create sudoers configuration for the web interface
echo "Creating sudoers configuration..."
SUDOERS_FILE="/etc/sudoers.d/ledmatrix_web"
# Get command paths
PYTHON_PATH=$(which python3)
SYSTEMCTL_PATH=$(which systemctl)
REBOOT_PATH=$(which reboot)
POWEROFF_PATH=$(which poweroff)
BASH_PATH=$(which bash)
# Create sudoers content
cat > /tmp/ledmatrix_web_sudoers << EOF
# LED Matrix Web Interface passwordless sudo configuration
# This allows the web interface user to run specific commands without a password
# Allow $ACTUAL_USER to run specific commands without a password for the LED Matrix web interface
$ACTUAL_USER ALL=(ALL) NOPASSWD: $REBOOT_PATH
$ACTUAL_USER ALL=(ALL) NOPASSWD: $POWEROFF_PATH
$ACTUAL_USER ALL=(ALL) NOPASSWD: $SYSTEMCTL_PATH start ledmatrix.service
$ACTUAL_USER ALL=(ALL) NOPASSWD: $SYSTEMCTL_PATH stop ledmatrix.service
$ACTUAL_USER ALL=(ALL) NOPASSWD: $SYSTEMCTL_PATH restart ledmatrix.service
$ACTUAL_USER ALL=(ALL) NOPASSWD: $SYSTEMCTL_PATH enable ledmatrix.service
$ACTUAL_USER ALL=(ALL) NOPASSWD: $SYSTEMCTL_PATH disable ledmatrix.service
$ACTUAL_USER ALL=(ALL) NOPASSWD: $SYSTEMCTL_PATH status ledmatrix.service
$ACTUAL_USER ALL=(ALL) NOPASSWD: $PYTHON_PATH $PROJECT_ROOT_DIR/display_controller.py
$ACTUAL_USER ALL=(ALL) NOPASSWD: $BASH_PATH $PROJECT_ROOT_DIR/start_display.sh
$ACTUAL_USER ALL=(ALL) NOPASSWD: $BASH_PATH $PROJECT_ROOT_DIR/stop_display.sh
EOF
if [ -f "$SUDOERS_FILE" ] && cmp -s /tmp/ledmatrix_web_sudoers "$SUDOERS_FILE"; then
echo "Sudoers configuration already up to date"
rm /tmp/ledmatrix_web_sudoers
else
echo "Installing/updating sudoers configuration..."
cp /tmp/ledmatrix_web_sudoers "$SUDOERS_FILE"
chmod 440 "$SUDOERS_FILE"
rm /tmp/ledmatrix_web_sudoers
fi
echo "✓ Passwordless sudo access configured"
echo ""
CURRENT_STEP="Set proper file ownership"
echo "Step 10: Setting proper file ownership..."
echo "----------------------------------------"
# Set ownership of project files to the user
echo "Setting project file ownership..."
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$PROJECT_ROOT_DIR"
# Set proper permissions for config files
if [ -f "$PROJECT_ROOT_DIR/config/config.json" ]; then
chmod 644 "$PROJECT_ROOT_DIR/config/config.json"
echo "✓ Config file permissions set"
fi
# Set proper permissions for secrets file (restrictive: owner rw, group r)
if [ -f "$PROJECT_ROOT_DIR/config/config_secrets.json" ]; then
chown "$ACTUAL_USER:$ACTUAL_USER" "$PROJECT_ROOT_DIR/config/config_secrets.json" || true
chmod 640 "$PROJECT_ROOT_DIR/config/config_secrets.json"
echo "✓ Secrets file permissions set"
fi
echo "✓ File ownership configured"
echo ""
CURRENT_STEP="Normalize project file permissions"
echo "Step 10.1: Normalizing project file and directory permissions..."
echo "--------------------------------------------------------------"
# Normalize directory permissions (exclude VCS metadata)
find "$PROJECT_ROOT_DIR" -path "*/.git*" -prune -o -type d -exec chmod 755 {} +
# Set default file permissions
find "$PROJECT_ROOT_DIR" -path "*/.git*" -prune -o -type f -exec chmod 644 {} +
# Ensure shell scripts are executable
find "$PROJECT_ROOT_DIR" -path "*/.git*" -prune -o -type f -name "*.sh" -exec chmod 755 {} +
# Explicitly ensure common helper scripts are executable (in case paths change)
chmod 755 "$PROJECT_ROOT_DIR/start_display.sh" "$PROJECT_ROOT_DIR/stop_display.sh" 2>/dev/null || true
chmod 755 "$PROJECT_ROOT_DIR/fix_cache_permissions.sh" "$PROJECT_ROOT_DIR/fix_web_permissions.sh" 2>/dev/null || true
chmod 755 "$PROJECT_ROOT_DIR/install_service.sh" "$PROJECT_ROOT_DIR/install_web_service.sh" 2>/dev/null || true
echo "✓ Project file permissions normalized"
echo ""
CURRENT_STEP="Sound module configuration"
echo "Step 11: Sound module configuration..."
echo "-------------------------------------"
# Remove services that may interfere with LED matrix timing
echo "Removing potential conflicting services (bluetooth and others)..."
if [ "$SKIP_SOUND" = "1" ]; then
echo "Skipping sound module configuration as requested (--skip-sound)."
elif apt_remove bluez bluez-firmware pi-bluetooth triggerhappy pigpio; then
echo "✓ Unnecessary services removed (or not present)"
else
echo "⚠ Some packages could not be removed; continuing"
fi
# Blacklist onboard sound module (idempotent)
BLACKLIST_FILE="/etc/modprobe.d/blacklist-rgb-matrix.conf"
if [ -f "$BLACKLIST_FILE" ] && grep -q '^blacklist snd_bcm2835\b' "$BLACKLIST_FILE"; then
echo "snd_bcm2835 already blacklisted in $BLACKLIST_FILE"
else
echo "Ensuring snd_bcm2835 is blacklisted in $BLACKLIST_FILE..."
mkdir -p "/etc/modprobe.d"
if [ -f "$BLACKLIST_FILE" ]; then
cp "$BLACKLIST_FILE" "$BLACKLIST_FILE.bak" 2>/dev/null || true
fi
# Append once (don't clobber existing unrelated content)
if [ -f "$BLACKLIST_FILE" ]; then
echo "blacklist snd_bcm2835" >> "$BLACKLIST_FILE"
else
printf "blacklist snd_bcm2835\n" > "$BLACKLIST_FILE"
fi
fi
# Update initramfs if available
if command -v update-initramfs >/dev/null 2>&1; then
echo "Updating initramfs..."
update-initramfs -u
else
echo "update-initramfs not found; skipping"
fi
echo "✓ Sound module configuration applied"
echo ""
CURRENT_STEP="Apply performance optimizations"
echo "Step 12: Applying performance optimizations..."
echo "---------------------------------------------"
# Prefer /boot/firmware on newer Raspberry Pi OS, fall back to /boot on older
CMDLINE_FILE="/boot/firmware/cmdline.txt"
CONFIG_FILE="/boot/firmware/config.txt"
if [ ! -f "$CMDLINE_FILE" ]; then CMDLINE_FILE="/boot/cmdline.txt"; fi
if [ ! -f "$CONFIG_FILE" ]; then CONFIG_FILE="/boot/config.txt"; fi
# Append isolcpus=3 to cmdline if not present (idempotent)
if [ "$SKIP_PERF" = "1" ]; then
echo "Skipping performance optimizations as requested (--skip-perf)."
elif [ -f "$CMDLINE_FILE" ]; then
if grep -q '\bisolcpus=3\b' "$CMDLINE_FILE"; then
echo "isolcpus=3 already present in $CMDLINE_FILE"
else
echo "Adding isolcpus=3 to $CMDLINE_FILE..."
cp "$CMDLINE_FILE" "$CMDLINE_FILE.bak" 2>/dev/null || true
# Ensure single-line cmdline gets the flag once, with a leading space
sed -i '1 s/$/ isolcpus=3/' "$CMDLINE_FILE"
fi
else
echo "$CMDLINE_FILE not found; skipping isolcpus optimization"
fi
# Ensure dtparam=audio=off in config.txt (idempotent)
if [ "$SKIP_PERF" = "1" ]; then
: # skipped
elif [ -f "$CONFIG_FILE" ]; then
if grep -q '^dtparam=audio=off\b' "$CONFIG_FILE"; then
echo "Onboard audio already disabled in $CONFIG_FILE"
elif grep -q '^dtparam=audio=on\b' "$CONFIG_FILE"; then
echo "Disabling onboard audio in $CONFIG_FILE..."
cp "$CONFIG_FILE" "$CONFIG_FILE.bak" 2>/dev/null || true
sed -i 's/^dtparam=audio=on\b/dtparam=audio=off/' "$CONFIG_FILE"
else
echo "Adding dtparam=audio=off to $CONFIG_FILE..."
cp "$CONFIG_FILE" "$CONFIG_FILE.bak" 2>/dev/null || true
printf "\n# Disable onboard audio for LED matrix performance\n" >> "$CONFIG_FILE"
echo "dtparam=audio=off" >> "$CONFIG_FILE"
fi
else
echo "$CONFIG_FILE not found; skipping audio disable"
fi
echo "✓ Performance optimizations applied"
echo ""
CURRENT_STEP="Test the installation"
echo "Step 13: Testing the installation..."
echo "----------------------------------"
# Test sudo access
echo "Testing sudo access..."
if sudo -u "$ACTUAL_USER" sudo -n systemctl status ledmatrix.service > /dev/null 2>&1; then
echo "✓ Sudo access test passed"
else
echo "⚠ Sudo access test failed - may need to log out and back in"
fi
# Test journal access
echo "Testing journal access..."
if sudo -u "$ACTUAL_USER" journalctl --no-pager --lines=1 > /dev/null 2>&1; then
echo "✓ Journal access test passed"
else
echo "⚠ Journal access test failed - may need to log out and back in"
fi
# Check service status
echo "Checking service status..."
if systemctl is-active --quiet ledmatrix.service; then
echo "✓ Main LED Matrix service is running"
else
echo "⚠ Main LED Matrix service is not running"
fi
if systemctl is-active --quiet ledmatrix-web.service; then
echo "✓ Web interface service is running"
else
echo "⚠ Web interface service is not running"
fi
echo ""
if [ "$SKIP_REBOOT_PROMPT" = "1" ]; then
echo "Skipping reboot prompt as requested (--no-reboot-prompt)."
elif [ "$ASSUME_YES" = "1" ]; then
echo "Non-interactive mode: rebooting now to apply changes..."
reboot
else
read -p "A reboot is recommended to apply kernel and audio changes. Reboot now? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Rebooting now..."
reboot
fi
fi
echo "=========================================="
echo "Installation Complete!"
echo "=========================================="
echo ""
echo "IMPORTANT: For group changes to take effect, you need to:"
echo "1. Log out and log back in to your SSH session, OR"
echo "2. Run: newgrp systemd-journal"
echo ""
echo "After logging back in, you can:"
echo ""
echo "Access the web interface at:"
echo " http://your-pi-ip:5001"
echo ""
echo "Check service status:"
echo " sudo systemctl status ledmatrix.service"
echo " sudo systemctl status ledmatrix-web.service"
echo ""
echo "View logs:"
echo " journalctl -u ledmatrix.service -f"
echo " journalctl -u ledmatrix-web.service -f"
echo ""
echo "Control the display:"
echo " sudo systemctl start ledmatrix.service"
echo " sudo systemctl stop ledmatrix.service"
echo ""
echo "Enable/disable web interface autostart:"
echo " Edit config/config.json and set 'web_display_autostart': true"
echo ""
echo "Configuration files:"
echo " Main config: config/config.json"
echo " Secrets: config/config_secrets.json (create from template if needed)"
echo ""
echo "Enjoy your LED Matrix display!"

View File

@@ -2,28 +2,37 @@
# LEDMatrix Cache Permissions Fix Script # LEDMatrix Cache Permissions Fix Script
# This script fixes permissions on all known cache directories so they're writable by the daemon or current user # This script fixes permissions on all known cache directories so they're writable by the daemon or current user
# Also sets up placeholder logo directories for sports managers
echo "Fixing LEDMatrix cache directory permissions..." echo "Fixing LEDMatrix cache directory permissions..."
CACHE_DIRS=(
"/var/cache/ledmatrix"
"/home/ledpi/.ledmatrix_cache"
)
# Get the real user (not root when running with sudo) # Get the real user (not root when running with sudo)
REAL_USER=${SUDO_USER:-$USER} REAL_USER=${SUDO_USER:-$USER}
# Resolve the home directory of the real user robustly
if command -v getent >/dev/null 2>&1; then
REAL_HOME=$(getent passwd "$REAL_USER" | cut -d: -f6)
else
REAL_HOME=$(eval echo ~"$REAL_USER")
fi
REAL_GROUP=$(id -gn "$REAL_USER") REAL_GROUP=$(id -gn "$REAL_USER")
# Known cache directories for LEDMatrix. Use the actual user's home instead of a hard-coded path.
CACHE_DIRS=(
"/var/cache/ledmatrix"
"$REAL_HOME/.ledmatrix_cache"
)
for CACHE_DIR in "${CACHE_DIRS[@]}"; do for CACHE_DIR in "${CACHE_DIRS[@]}"; do
echo "" echo ""
echo "Checking cache directory: $CACHE_DIR" echo "Checking cache directory: $CACHE_DIR"
if [ ! -d "$CACHE_DIR" ]; then if [ ! -d "$CACHE_DIR" ]; then
echo " - Directory does not exist. Skipping." echo " - Directory does not exist. Creating it..."
continue sudo mkdir -p "$CACHE_DIR"
fi fi
echo " - Current permissions:" echo " - Current permissions:"
ls -ld "$CACHE_DIR" ls -ld "$CACHE_DIR"
echo " - Fixing permissions..." echo " - Fixing permissions..."
# Make directory writable by services regardless of user context
sudo chmod 777 "$CACHE_DIR" sudo chmod 777 "$CACHE_DIR"
sudo chown "$REAL_USER":"$REAL_GROUP" "$CACHE_DIR" sudo chown "$REAL_USER":"$REAL_GROUP" "$CACHE_DIR"
echo " - Updated permissions:" echo " - Updated permissions:"
@@ -37,6 +46,42 @@ for CACHE_DIR in "${CACHE_DIRS[@]}"; do
echo " - Permissions fix complete for $CACHE_DIR." echo " - Permissions fix complete for $CACHE_DIR."
done done
# Set up placeholder logos directory for sports managers
echo ""
echo "Setting up placeholder logos directory for sports managers..."
PLACEHOLDER_DIR="/var/cache/ledmatrix/placeholder_logos"
if [ ! -d "$PLACEHOLDER_DIR" ]; then
echo "Creating placeholder logos directory: $PLACEHOLDER_DIR"
sudo mkdir -p "$PLACEHOLDER_DIR"
sudo chown "$REAL_USER":"$REAL_GROUP" "$PLACEHOLDER_DIR"
sudo chmod 777 "$PLACEHOLDER_DIR"
else
echo "Placeholder logos directory already exists: $PLACEHOLDER_DIR"
sudo chmod 777 "$PLACEHOLDER_DIR"
sudo chown "$REAL_USER":"$REAL_GROUP" "$PLACEHOLDER_DIR"
fi
echo " - Current permissions:"
ls -ld "$PLACEHOLDER_DIR"
echo " - Testing write access as $REAL_USER..."
if sudo -u "$REAL_USER" test -w "$PLACEHOLDER_DIR"; then
echo " ✓ Placeholder logos directory is writable by $REAL_USER"
else
echo " ✗ Placeholder logos directory is not writable by $REAL_USER"
fi
# Test with daemon user (which the system might run as)
if sudo -u daemon test -w "$PLACEHOLDER_DIR" 2>/dev/null; then
echo " ✓ Placeholder logos directory is writable by daemon user"
else
echo " ✗ Placeholder logos directory is not writable by daemon user"
fi
echo "" echo ""
echo "All cache directory permission fixes attempted." echo "All cache directory permission fixes attempted."
echo "If you still see errors, check which user is running the LEDMatrix service and ensure it matches the owner above." echo "If you still see errors, check which user is running the LEDMatrix service and ensure it matches the owner above."
echo ""
echo "The system will now create placeholder logos in:"
echo " $PLACEHOLDER_DIR"
echo "This should eliminate the permission denied warnings for sports logos."

105
fix_web_permissions.sh Normal file
View File

@@ -0,0 +1,105 @@
#!/bin/bash
# LED Matrix Web Interface Permissions Fix Script
# This script fixes permissions for the web interface to access logs and system commands
set -e
echo "Fixing LED Matrix Web Interface permissions..."
# Get the current user (should be the user running the web interface)
WEB_USER=$(whoami)
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "Detected web interface user: $WEB_USER"
echo "Project directory: $PROJECT_DIR"
# Check if running as root
if [ "$EUID" -eq 0 ]; then
echo "Error: This script should not be run as root."
echo "Run it as the user that will be running the web interface."
exit 1
fi
echo ""
echo "This script will:"
echo "1. Add the web user to the 'systemd-journal' group for log access"
echo "2. Add the web user to the 'adm' group for additional system access"
echo "3. Configure sudoers for passwordless access to system commands"
echo "4. Set proper file permissions"
echo ""
# Ask for confirmation
read -p "Do you want to proceed? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Permission fix cancelled."
exit 0
fi
echo ""
echo "Step 1: Adding user to systemd-journal group..."
if sudo usermod -a -G systemd-journal "$WEB_USER"; then
echo "✓ Added $WEB_USER to systemd-journal group"
else
echo "✗ Failed to add user to systemd-journal group"
fi
echo ""
echo "Step 2: Adding user to adm group..."
if sudo usermod -a -G adm "$WEB_USER"; then
echo "✓ Added $WEB_USER to adm group"
else
echo "✗ Failed to add user to adm group"
fi
echo ""
echo "Step 3: Setting proper file permissions..."
# Set ownership of project files to the web user
if sudo chown -R "$WEB_USER:$WEB_USER" "$PROJECT_DIR"; then
echo "✓ Set project ownership to $WEB_USER"
else
echo "✗ Failed to set project ownership"
fi
# Set proper permissions for config files
if sudo chmod 644 "$PROJECT_DIR/config/config.json" 2>/dev/null; then
echo "✓ Set config file permissions"
else
echo "⚠ Config file permissions not set (file may not exist)"
fi
echo ""
echo "Step 4: Testing journal access..."
# Test if the user can now access journal logs
if journalctl --user-unit=ledmatrix.service --no-pager --lines=1 > /dev/null 2>&1; then
echo "✓ Journal access test passed"
elif sudo -u "$WEB_USER" journalctl --no-pager --lines=1 > /dev/null 2>&1; then
echo "✓ Journal access test passed (with sudo)"
else
echo "⚠ Journal access test failed - you may need to log out and back in"
fi
echo ""
echo "Step 5: Testing sudo access..."
# Test sudo access for system commands
if sudo -n systemctl status ledmatrix.service > /dev/null 2>&1; then
echo "✓ Sudo access test passed"
else
echo "⚠ Sudo access test failed - you may need to run configure_web_sudo.sh"
fi
echo ""
echo "Permission fix completed!"
echo ""
echo "IMPORTANT: For group changes to take effect, you need to:"
echo "1. Log out and log back in, OR"
echo "2. Run: newgrp systemd-journal"
echo "3. Restart the web interface service:"
echo " sudo systemctl restart ledmatrix-web.service"
echo ""
echo "After logging back in, test journal access with:"
echo " journalctl --no-pager --lines=5"
echo ""
echo "If you still have sudo issues, run:"
echo " ./configure_web_sudo.sh"

150
install_dependencies_apt.py Normal file
View File

@@ -0,0 +1,150 @@
#!/usr/bin/env python3
"""
Alternative dependency installer that tries apt packages first,
then falls back to pip with --break-system-packages
"""
import subprocess
import sys
import os
from pathlib import Path
def install_via_apt(package_name):
"""Try to install a package via apt."""
try:
# Map pip package names to apt package names
apt_package_map = {
'flask': 'python3-flask',
'flask_socketio': 'python3-flask-socketio',
'PIL': 'python3-pil',
'socketio': 'python3-socketio',
'eventlet': 'python3-eventlet',
'freetype': 'python3-freetype',
'psutil': 'python3-psutil',
'werkzeug': 'python3-werkzeug',
'numpy': 'python3-numpy',
'requests': 'python3-requests',
'python-dateutil': 'python3-dateutil',
'pytz': 'python3-tz',
'geopy': 'python3-geopy',
'unidecode': 'python3-unidecode',
'websockets': 'python3-websockets',
'websocket-client': 'python3-websocket-client'
}
apt_package = apt_package_map.get(package_name, f'python3-{package_name}')
print(f"Trying to install {apt_package} via apt...")
subprocess.check_call([
'sudo', 'apt', 'update'
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
subprocess.check_call([
'sudo', 'apt', 'install', '-y', apt_package
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
print(f"Successfully installed {apt_package} via apt")
return True
except subprocess.CalledProcessError:
print(f"Failed to install {package_name} via apt, will try pip")
return False
def install_via_pip(package_name):
"""Install a package via pip with --break-system-packages."""
try:
print(f"Installing {package_name} via pip...")
subprocess.check_call([
sys.executable, '-m', 'pip', 'install', '--break-system-packages', package_name
])
print(f"Successfully installed {package_name} via pip")
return True
except subprocess.CalledProcessError as e:
print(f"Failed to install {package_name} via pip: {e}")
return False
def check_package_installed(package_name):
"""Check if a package is already installed."""
try:
__import__(package_name)
return True
except ImportError:
return False
def main():
"""Main installation function."""
print("Installing dependencies for LED Matrix Web Interface V2...")
# List of required packages
required_packages = [
'flask',
'flask_socketio',
'PIL',
'socketio',
'eventlet',
'freetype',
'psutil',
'werkzeug',
'numpy',
'requests',
'python-dateutil',
'pytz',
'geopy',
'unidecode',
'websockets',
'websocket-client'
]
failed_packages = []
for package in required_packages:
if check_package_installed(package):
print(f"{package} is already installed")
continue
# Try apt first, then pip
if not install_via_apt(package):
if not install_via_pip(package):
failed_packages.append(package)
# Install packages that don't have apt equivalents
special_packages = [
'timezonefinder==6.2.0',
'google-auth-oauthlib==1.0.0',
'google-auth-httplib2==0.1.0',
'google-api-python-client==2.86.0',
'spotipy',
'icalevents',
'python-engineio'
]
for package in special_packages:
if not install_via_pip(package):
failed_packages.append(package)
# Install rgbmatrix module from local source
print("Installing rgbmatrix module...")
try:
rgbmatrix_path = Path(__file__).parent / 'rpi-rgb-led-matrix-master' / 'bindings' / 'python'
if rgbmatrix_path.exists():
subprocess.check_call([
sys.executable, '-m', 'pip', 'install', '--break-system-packages', '-e', str(rgbmatrix_path)
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
print("rgbmatrix module installed successfully")
else:
print("Warning: rgbmatrix source not found")
except subprocess.CalledProcessError as e:
print(f"Failed to install rgbmatrix module: {e}")
failed_packages.append('rgbmatrix')
if failed_packages:
print(f"\nFailed to install the following packages: {failed_packages}")
print("You may need to install them manually or check your system configuration.")
return False
else:
print("\nAll dependencies installed successfully!")
return True
if __name__ == '__main__':
success = main()
sys.exit(0 if success else 1)

Some files were not shown because too many files have changed in this diff Show More