# 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. Special Thanks to: - Hzeller @ https://github.com/hzeller/rpi-rgb-led-matrix for his groundwork on controlling an LED Matrix from the Raspberry Pi - Basmilius @ https://github.com/basmilius/weather-icons/ for his free and extensive weather icons - nvstly @ https://github.com/nvstly/icons for their Stock and Crypto Icons - ESPN for their sports API - Yahoo Finance for their Stock API - OpenWeatherMap for their Free Weather API ## Core Features Modular, rotating Displays that can be individually enabled or disabled per the user's needs with some configuration around display durations, teams, stocks, weather, timezones, and more. Displays include: ### Time and Weather - Real-time clock display - Current Weather, Daily Weather, and Hourly Weather Forecasts with icons from - Google Calendar event display ### Sports Information The system supports live, recent, and upcoming game information for multiple sports leagues: - NHL (Hockey) - NBA (Basketball) - MLB (Baseball) - NFL (Football) - NCAA Football - NCAA Men's Basketball - NCAA Men's Baseball - Soccer - (Note, some of these sports seasons were not active during development and might need fine tuning when games are active) ### Financial Information - Near real-time stock & crypto price updates - Stock news headlines - Customizable stock & crypto watchlists ### Entertainment - Music playback information from multiple sources: - Spotify integration - YouTube Music integration - Album art display - Now playing information with scrolling text ### Custom Display Features - Custom Text display - Youtube Subscriber Count Display - Font testing and customization - Configurable display modes ## System Architecture The system is built with a modular architecture that allows for easy extension and maintenance: - `DisplayController`: Main orchestrator managing all display modes - Individual managers for each feature (sports, weather, music, etc.) - Separate authentication handlers for different services - Configurable display modes and rotation patterns from one file - config.json ## Configuration The system can be configured through a JSON configuration file that allows users to: - Enable/disable specific features - Set display durations - Configure API keys and endpoints - Customize display modes and rotation patterns - Set preferred music sources - Configure sports team preferences ## Hardware Requirements - Raspberry Pi 3b or 4 (NOT RPI5!) -- Amazon Affiliate Link: Raspberry Pi 4 4GB (https://amzn.to/4dJixuX) - Adafruit RGB Matrix Bonnet/HAT -- https://www.adafruit.com/product/3211 - 2x LED Matrix panels (64x32) (Designed for 128x32 but has a lot of dynamic scaling elements that could work on a variety of displays, pixel pitch is user preference) -- https://www.adafruit.com/product/2278 - DC Power Supply for Adafruit RGB HAT -- https://www.adafruit.com/product/658 ----------------------------------------------------------------------------------- ## Installation 1. Clone this repository: ```bash git clone https://github.com/ChuckBuilds/LEDMatrix.git cd LEDMatrix ``` 2. Install dependencies: ```bash pip3 install --break-system-packages -r requirements.txt ``` --break-system-packages allows us to install without a virtual environment ## Important: Sound Module Configuration 1. Remove unnecessary services that might interfere with the LED matrix: ```bash sudo apt-get remove bluez bluez-firmware pi-bluetooth triggerhappy pigpio ``` 2. Blacklist the sound module: ```bash cat <:9863` if running on a different computer). **`preferred_source` Options:** * `"spotify"`: Only uses Spotify. Ignores YTM. * `"ytm"`: Only uses the YTM Companion Server. Ignores Spotify. ## Spotify Authentication for Music Display If you are using the Spotify integration to display currently playing music, you will need to authenticate with Spotify. This project uses an authentication flow that requires a one-time setup. Due to how the display controller script may run with specific user permissions (even when using `sudo`), the following steps are crucial: 1. **Initial Setup & Secrets:** * Ensure you have your Spotify API Client ID, Client Secret, and Redirect URI. * The Redirect URI should be set to `http://127.0.0.1:8888/callback` in your Spotify Developer Dashboard. * Copy `config/config_secrets.template.json` to `config/config_secrets.json`. * Edit `config/config_secrets.json` and fill in your Spotify credentials under the `"music"` section: ```json { "music": { "SPOTIFY_CLIENT_ID": "YOUR_SPOTIFY_CLIENT_ID", "SPOTIFY_CLIENT_SECRET": "YOUR_SPOTIFY_CLIENT_SECRET", "SPOTIFY_REDIRECT_URI": "http://127.0.0.1:8888/callback" } } ``` 2. **Run the Authentication Script:** * Execute the authentication script using `sudo`. This is important because it needs to create an authentication cache file (`spotify_auth.json`) that will be owned by root. ```bash sudo python3 src/authenticate_spotify.py ``` * The script will output a URL. Copy this URL and paste it into a web browser on any device. * Log in to Spotify and authorize the application. * Your browser will be redirected to a URL starting with `http://127.0.0.1:8888/callback?code=...`. It will likely show an error page like "This site can't be reached" – this is expected. * Copy the **entire** redirected URL from your browser's address bar. * Paste this full URL back into the terminal when prompted by the script. * If successful, it will indicate that token info has been cached. 3. **Adjust Cache File Permissions:** * The main display script (`display_controller.py`), even when run with `sudo`, might operate with an effective User ID (e.g., UID 1 for 'daemon') that doesn't have permission to read the `spotify_auth.json` file created by `root` (which has -rw------- permissions by default). * To allow the display script to read this cache file, change its permissions: ```bash sudo chmod 644 config/spotify_auth.json ``` This makes the file readable by all users, including the effective user of the display script. 4. **Run the Main Application:** * You should now be able to run your main display controller script using `sudo`: ```bash sudo python3 display_controller.py ``` * The Spotify client should now authenticate successfully using the cached token. **Why these specific permissions steps?** The `authenticate_spotify.py` script, when run with `sudo`, creates `config/spotify_auth.json` owned by `root`. If the main `display_controller.py` (also run with `sudo`) effectively runs as a different user (e.g., UID 1/daemon, as observed during troubleshooting), that user won't be able to read the `root`-owned file unless its permissions are relaxed (e.g., to `644`). The `chmod 644` command allows the owner (`root`) to read/write, and everyone else (including the `daemon` user) to read. ### Music Display (YouTube Music) The system can display currently playing music information from YouTube Music Desktop (YTMD) via its Companion server API. **Setup:** 1. **Enable Companion Server in YTMD:** * In the YouTube Music Desktop application, go to `Settings` -> `Integrations`. * Enable the "Companion Server". * Note the IP address and Port it's listening on (default is usually `http://localhost:9863`), you'll need to know the local ip address if playing music on a device other than your rpi (probably are). 2. **Configure `config/config.json`:** * Update the `music` section in your `config/config.json`: ```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": 1 } ``` 3. **Initial Authentication & Token Storage:** * The first time you run ` python3 src/authenticate_ytm.py` after 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/ytm_auth.json`. * This ensures the `ledpi` user owns the config directory and file, and has the necessary write permissions. **Troubleshooting:** * "No authorized companions" in YTMD: Ensure you've approved the `LEDMatrixController` in YTMD settings after the first run. * Connection errors: Double-check the `YTM_COMPANION_URL` in `config.json` matches what YTMD's companion server is set to. * Ensure your firewall (Windows Firewall) allows YTM Desktop app to access local networks. ## Project Structure ``` LEDMatrix/ ├── assets/ # Static assets like fonts and icons ├── config/ # Configuration files │ ├── config.json # Main configuration │ └── config_secrets.template.json # Template for API keys and sensitive data ├── src/ # Source code │ ├── display_controller.py # Main application controller │ ├── config_manager.py # Configuration management │ ├── display_manager.py # LED matrix display handling │ ├── cache_manager.py # Caching system for API data │ ├── clock.py # Clock display module │ ├── weather_manager.py # Weather display module │ ├── weather_icons.py # Weather icon definitions │ ├── stock_manager.py # Stock ticker display module │ ├── stock_news_manager.py # Stock news display module │ ├── music_manager.py # Music display orchestration │ ├── spotify_client.py # Spotify API integration │ ├── ytm_client.py # YouTube Music integration │ ├── authenticate_spotify.py # Spotify authentication │ ├── authenticate_ytm.py # YouTube Music authentication │ ├── calendar_manager.py # Google Calendar integration │ ├── youtube_display.py # YouTube channel stats display │ ├── text_display.py # Custom text display module │ ├── font_test_manager.py # Font testing utility │ ├── nhl_managers.py # NHL game display │ ├── nba_managers.py # NBA game display │ ├── mlb_manager.py # MLB game display │ ├── nfl_managers.py # NFL game display │ ├── soccer_managers.py # Soccer game display │ ├── ncaa_fb_managers.py # NCAA Football display │ ├── ncaa_baseball_managers.py # NCAA Baseball display │ └── ncaam_basketball_managers.py # NCAA Basketball display ├── rpi-rgb-led-matrix-master/ # LED matrix library ├── run.py # Main entry point ├── display_controller.py # Legacy entry point ├── calendar_registration.py # Calendar API setup ├── run_font_test.py # Font testing entry point ├── ChuckBuilds.py # Custom display module ├── start_display.sh # Service start script ├── stop_display.sh # Service stop script ├── install_service.sh # Service installation script ├── ledmatrix.service # Systemd service definition ├── requirements.txt # Python dependencies └── config.example.json # Example configuration ``` The project is organized into several key components: - `src/`: Contains all the Python source code, organized by feature - `config/`: Configuration files for the application - `assets/`: Static assets like fonts and icons - `rpi-rgb-led-matrix-master/`: The LED matrix control library - Various utility scripts for running and managing the service Each display module in `src/` is responsible for a specific feature (weather, sports, music, etc.) and follows a consistent pattern of data fetching, processing, and display rendering. ## 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 - ESPN 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 or .btf(less support) and updated in display_manager.py ### 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: ```bash sudo usermod -a -G gpio # 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: ```bash python3 display_controller.py ```