LEDMatrix
A modular LED matrix display system for sports information using Raspberry Pi and RGB LED matrices.
Work in Progress, things may break. I'll try to keep the main branch as stable as I can but this is absolutely in a pre-release state. There are also a ton of commits as it's an easy way to get the changes to the rpi for testing.
Hardware Requirements
- Raspberry Pi 4 or older
- Adafruit RGB Matrix Bonnet/HAT
- 2x LED Matrix panels (64x32)
- DC Power Supply for Adafruit RGB HAT
Installation
- Clone this repository:
git clone https://github.com/ChuckBuilds/LEDMatrix.git
cd LEDMatrix
- Install dependencies:
pip3 install --break-system-packages -r requirements.txt
--break-system-packages allows us to install without a virtual environment
Configuration
- Copy the example configuration:
cp config/config.example.json config/config.json
- Edit
config/config.jsonwith your preferences
Important: Sound Module Configuration
- Remove unnecessary services that might interfere with the LED matrix:
sudo apt-get remove bluez bluez-firmware pi-bluetooth triggerhappy pigpio
- Blacklist the sound module:
cat <<EOF | sudo tee /etc/modprobe.d/blacklist-rgb-matrix.conf
blacklist snd_bcm2835
EOF
sudo update-initramfs -u
- Reboot:
sudo reboot
Performance Optimization
To reduce flickering and improve display quality:
- Edit
/boot/firmware/cmdline.txt:
sudo nano /boot/firmware/cmdline.txt
-
Add
isolcpus=3at the end of the line -
Add
dtparam=audio=offat the end of the line -
Ctrl + X to exit, Y to save
-
Save and reboot:
sudo reboot
Running without Sudo (Optional and not recommended)
To run the display script without sudo, the user executing the script needs access to GPIO pins. Add the user to the gpio group:
sudo usermod -a -G gpio <your_username>
# Example for user 'ledpi':
# sudo usermod -a -G gpio ledpi
Important: You must reboot the Raspberry Pi after adding the user to the group for the change to take effect.
You also need to disable hardware pulsing in the code (see src/display_manager.py, set options.disable_hardware_pulsing = True). This may result in a flickerying display
If configured correctly, you can then run:
python3 display_controller.py
Running the Display
From the project root directory:
sudo python3 display_controller.py
The display will alternate between showing:
- Current time
- Weather information (requires API key configuration)
Systemd Service Installation
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
- Make the install script executable:
chmod +x install_service.sh
- Run the install script with sudo:
sudo ./install_service.sh
The script will:
- Detect your user account and home directory
- Install the service file with the correct paths
- Enable the service to start on boot
- Start the service immediately
Managing the Service
The following commands are available to manage the service:
# Stop the display
sudo systemctl stop ledmatrix.service
# Start the display
sudo systemctl start ledmatrix.service
# Check service status
sudo systemctl status ledmatrix.service
# View logs
journalctl -u ledmatrix.service
# Disable autostart
sudo systemctl disable ledmatrix.service
# Enable autostart
sudo systemctl enable ledmatrix.service
Convenience Scripts
Two convenience scripts are provided for easy service management:
start_display.sh- Starts the LED matrix display servicestop_display.sh- Stops the LED matrix display service
Make them executable with:
chmod +x start_display.sh stop_display.sh
Then use them to control the service:
sudo ./start_display.sh
sudo ./stop_display.sh
API Keys
For sensitive settings like API keys:
-
Copy the template:
cp config/config_secrets.template.json config/config_secrets.json -
Edit
config/config_secrets.jsonwith your API keys viasudo nano config/config_secrets.json -
Ctrl + X to exit, Y to overwrite, Enter to save
NHL, NBA, MLB Scoreboard Display
The LEDMatrix system includes a comprehensive NHL, NBA scoreboard display system with three display modes:
Display Modes
- Live Games: Shows currently playing games with live scores and game status
- Recent Games: Displays completed games from the last 48 hours (configurable)
- Upcoming Games: Shows scheduled games for favorite teams
Features
- Real-time score updates from ESPN API
- Team logo display
- Game status indicators (period, time remaining)
- Power play and penalty information
- Configurable favorite teams
- Automatic game switching
- Built-in caching to reduce API calls
- Test mode for development
Configuration
In config.json, under the nhl_scoreboard section:
{
"nhl_scoreboard": {
"enabled": true,
"test_mode": false,
"update_interval_seconds": 300,
"live_update_interval": 60,
"recent_update_interval": 1800,
"upcoming_update_interval": 1800,
"recent_game_hours": 48,
"favorite_teams": ["TB", "DAL"],
"logo_dir": "assets/sports/nhl_logos",
"display_modes": {
"nhl_live": true,
"nhl_recent": true,
"nhl_upcoming": true
}
}
}
YouTube Display Configuration
The YouTube display module shows channel statistics for a specified YouTube channel. To configure it:
- In
config/config.json, add the following section:
{
"youtube": {
"enabled": true,
"update_interval": 300 // Update interval in seconds (default: 300)
}
}
- In
config/config_secrets.json, add your YouTube API credentials:
{
"youtube": {
"api_key": "YOUR_YOUTUBE_API_KEY",
"channel_id": "YOUR_CHANNEL_ID"
}
}
To get these credentials:
- Go to the Google Cloud Console
- Create a new project or select an existing one
- Enable the YouTube Data API v3
- Create credentials (API key)
- For the channel ID, you can find it in your YouTube channel URL or use the YouTube Data API to look it up
Calendar Display Configuration
The calendar display module shows upcoming events from your Google Calendar. To configure it:
- In
config/config.json, add the following section:
{
"calendar": {
"enabled": true,
"update_interval": 300, // Update interval in seconds (default: 300)
"max_events": 3, // Maximum number of events to display
"calendars": ["primary"] // List of calendar IDs to display
}
}
-
Set up Google Calendar API access:
- Go to the Google Cloud Console
- Create a new project or select an existing one
- Enable the Google Calendar API
- Create OAuth 2.0 credentials:
- Application type: Desktop app
- Download the credentials file as
credentials.json
- Place the
credentials.jsonfile in your project root directory
-
On first run, the application will:
- Open a browser window for Google authentication
- Request calendar read-only access
- Save the authentication token as
token.pickle
The calendar display will show:
- Event date and time
- Event title (wrapped to fit the display)
- Up to 3 upcoming events (configurable)
Development
The project structure is organized as follows:
LEDMatrix/
├── config/ # Configuration files
│ ├── config.json # Main configuration
│ └── config_secrets.json # API keys and sensitive data
├── src/ # Source code
│ ├── config_manager.py # Configuration loading
│ ├── display_manager.py # LED matrix display handling
│ ├── clock.py # Clock display module
│ ├── weather_manager.py # Weather display module
│ ├── stock_manager.py # Stock ticker display module
│ └── stock_news_manager.py # Stock news display module
└── display_controller.py # Main application controller
Project Structure
src/display_controller.py- Main application controllerconfig_manager.py- Configuration managementdisplay_manager.py- LED matrix display handlingclock.py- Clock display moduleweather_manager.py- Weather display modulestock_manager.py- Stock ticker display modulestock_news_manager.py- Stock news display module
config/config.json- Configuration settingsconfig_secrets.json- Private settings (not in git)
Caching System
The LEDMatrix system includes a robust caching mechanism to optimize API calls and reduce network traffic:
Cache Location
- Default cache directory:
/tmp/ledmatrix_cache - Cache files are stored with proper permissions (755 for directories, 644 for files)
- When running as root/sudo, cache ownership is automatically adjusted to the real user
Cached Data Types
- Weather data (current conditions and forecasts)
- Stock prices and market data
- Stock news headlines
- NHL game information
- NBA game information
Cache Behavior
- Data is cached based on update intervals defined in
config.json - Cache is automatically invalidated when:
- Update interval has elapsed
- Market is closed (for stock data)
- Data has changed significantly
- Failed API calls fall back to cached data when available
- Cache files use atomic operations to prevent corruption
Cache Management
- Cache files are automatically created and managed
- No manual intervention required
- Cache directory is created with proper permissions on first run
- Temporary files are used for safe updates
- JSON serialization handles all data types including timestamps
Fonts
You can add any font to the assets/fonts/ folder but they need to be .ttf and updated in display_manager.py
Music Display Configuration
The Music Display module shows information about the currently playing track from either Spotify or YouTube Music (via the YouTube Music Desktop App companion server).
Setup Requirements:
-
Spotify:
- Requires a Spotify Premium account (for API access).
- You need to register an application on the Spotify Developer Dashboard to get API credentials.
- Go to the dashboard, log in, and click "Create App".
- Give it a name (e.g., "LEDMatrix Display") and description.
- For the "Redirect URI", enter
http://localhost:8888/callback(or another unused port if 8888 is taken). You must add this exact URI in your app settings on the Spotify dashboard. - Note down the
Client IDandClient Secret.
-
YouTube Music (YTM):
- Requires the YouTube Music Desktop App (YTMD) to be installed and running on a computer on the same network as the Raspberry Pi.
- In YTMD settings, enable the "Companion Server" under Integration options. Note the URL it provides (usually
http://localhost:9863if running on the same machine, orhttp://<YTMD-Computer-IP>:9863if running on a different computer).
Configuration:
-
In
config/config_secrets.json, add your Spotify API credentials under themusickey:{ "music": { "SPOTIFY_CLIENT_ID": "YOUR_SPOTIFY_CLIENT_ID_HERE", "SPOTIFY_CLIENT_SECRET": "YOUR_SPOTIFY_CLIENT_SECRET_HERE", "SPOTIFY_REDIRECT_URI": "http://localhost:8888/callback" } // ... other secrets ... }(Ensure the
SPOTIFY_REDIRECT_URIhere matches exactly what you entered in the Spotify Developer Dashboard). -
In
config/config.json, add/modify themusicsection:{ "music": { "enabled": true, // Set to false to disable this display "preferred_source": "auto", // Options: "auto", "spotify", "ytm" "YTM_COMPANION_URL": "http://<YTMD-Computer-IP>:9863", // Replace with actual URL if YTMD is not on the Pi "POLLING_INTERVAL_SECONDS": 2 // How often to check for track updates } // ... other configurations ... }Also, ensure the display duration is set in the
display_durationssection:{ "display": { "display_durations": { "music": 20, // Duration in seconds // ... other durations ... } } // ... other configurations ... }
preferred_source Options:
"auto": (Default) Checks Spotify first. If Spotify is playing, shows its track. If not, checks YTM."spotify": Only uses Spotify. Ignores YTM."ytm": Only uses the YTM Companion Server. Ignores Spotify.
First Spotify Run (Headless Setup):
Since the display runs on a headless Raspberry Pi, the Spotify authorization process requires a few manual steps:
- Start the Application: Run the display controller script (
sudo python3 display_controller.py). - Copy Auth URL: When Spotify needs authorization for the first time (or after a token expires), the application will print a URL to the console. Copy this full URL.
- Authorize in Browser (on another device): Paste the copied URL into a web browser on your computer or phone. Log in to Spotify if prompted and click "Agree" to authorize the application.
- Get Redirected URL: Your browser will be redirected to a URL starting with your
SPOTIFY_REDIRECT_URI(e.g.,http://localhost:8888/callback) followed by?code=.... The page will likely show an error like "Site can't be reached" - this is expected and perfectly fine. - Copy Full Redirected URL: Immediately copy the complete URL from your browser's address bar. Make sure you copy the entire thing, including the
?code=...part. - Paste URL Back to Pi: Go back to the Raspberry Pi console where the display script is running. It should now be prompting you to "Enter the URL you were redirected to:". Paste the full URL you just copied from your browser into the console and press Enter.
The application will then use the provided code to get the necessary tokens and cache them (usually in a .cache file). Subsequent runs should not require this process unless the token expires.
Music Display (YouTube Music)
The system can display currently playing music information from YouTube Music Desktop (YTMD) via its Companion server API.
Setup:
-
Enable Companion Server in YTMD:
- In the YouTube Music Desktop application, go to
Settings->Integrations. - Enable the "Companion Server" (it might also be labeled as "JSON RPC" or similar).
- Note the IP address and Port it's listening on (default is usually
http://localhost:9863).
- In the YouTube Music Desktop application, go to
-
Configure
config/config.json:- Update the
musicsection in yourconfig/config.json:"music": { "enabled": true, "preferred_source": "ytm", "YTM_COMPANION_URL": "http://YOUR_YTMD_IP_ADDRESS:PORT", // e.g., "http://localhost:9863" or "http://192.168.1.100:9863" "POLLING_INTERVAL_SECONDS": 2 }
- Update the
-
Initial Authentication & Token Storage:
- The first time you run
display_controller.pyafter enabling YTM, it will attempt to register itself with the YTMD Companion Server. - You will see log messages in the terminal prompting you to approve the "LEDMatrixController" application within the YouTube Music Desktop app. You typically have 30 seconds to do this.
- Once approved, an authentication token is saved to your
config/config.json.
- The first time you run
-
File Permissions for Token Saving (Important if running as a specific user e.g.,
ledpi):- If the script (e.g.,
display_controller.pyor the systemd service) runs as a user likeledpi, that user needs permission to write the authentication token toconfig/config.json. - Execute the following commands, replacing
ledpiif you use a different user:sudo chown ledpi:ledpi /home/ledpi/LEDMatrix/config /home/ledpi/LEDMatrix/config/config.json sudo chmod 664 /home/ledpi/LEDMatrix/config/config.json sudo chmod 775 /home/ledpi/LEDMatrix/config - This ensures the
ledpiuser owns the config directory and file, and has the necessary write permissions.
- If the script (e.g.,
Troubleshooting:
- "No authorized companions" in YTMD: Ensure you've approved the
LEDMatrixControllerin YTMD settings after the first run. - Connection errors: Double-check the
YTM_COMPANION_URLinconfig.jsonmatches what YTMD's companion server is set to. - Permission denied saving token: Ensure you've run the
chownandchmodcommands above.