diff --git a/ubmodule status b/ubmodule status new file mode 100644 index 00000000..46efff8f --- /dev/null +++ b/ubmodule status @@ -0,0 +1,51 @@ +8c03e651 (HEAD -> development, origin/development) wiki page about team abbreviations +764d80e8 added more missing soccer logos +854c236a added portuguese soccer league to documentation for soccer manager and added auto-download missing logos for soccer teams +4b1b343a shift album font down 2 pixels +65f04bff adjust music manager album text location +80558561 shift of the day description and subtitle down in more situations +17a79976 shift of the day description down one more pixel for total of 4 +38062d0b shift album and artist font down +2ce25205 shift of the day description down one more pixel +c7ee9468 shift music album and artist font down the height of the text font +3afcbb75 add freetype error handling +bc182027 shift of the day underline up one pixel +a0973a2a shift whole display down 8 pixels +c18ab3f9 dialing of the day text spacing - revert back to too much spacing +97185950 dialing of the day text spacing +5f803f34 dialing of the day text spacing +03208307 of the day manager text refactor +9dd74425 of the day manager text positioning placement fix +67b6a6fd adjust spacing on of the day manager text +ca62fd71 Make sure sports displays are properly processing number of recent games to show +49346f9a change of the day file path detection +9200c9ca update logic on all sports displays that upcoming and recent games to show are based on each team, not just the first X # of games found +dbdb730b fix upcoming game logic for NFL display too +91211d5c fix upcoming game logic +d78c592d NCAA FB season now downloads in full but it slows down the display significantly, data fetch has been moved to the background and deferred during scrolling displays +4771ec8b add black buffer behind odds ticker to finish scroll +60f68ff2 add permission handling of the day to first time install script +c7634cbf NCAA FB odds fix +96cd3834 NCAA FB logging to figure out why recent and upcoming games aren't loading well +e39dd1e0 NCAA FB logging +7b133963 of the day try block fix +0579b3b8 more of the day debug logging and fix datetime duplicate in NCAA FB +e7e76eea more robust NCAA FB manager upcoming game check +3f431a54 path resolution for of the day manager +d0f87859 troubleshooting of the day manager +7618eafa troubleshooting of the day manager +f8f45390 hopefully fix of the day settings +0ab978d5 web ui config setting accuracy changes +c4a51d0f espn api update for NCAAFB +b20c3880 make sure web ui is pulling existing config options +652461a8 ensure leaderboard is in webui +691d3967 web ui bug fixes +9bc0cd56 moving away from dict errors +625a501d further dict wrapper update +28c2dcd2 fix dict class for web ui +c55511c0 webui changes to launch after config file changes +b96f1e39 make sure web ui save buttons work +fcbc6746 persistent config file via config.template.json and migrate_config.sh +4b36937a Update sports league logos +8ead8ad8 Fix NCAA Football recent games to show truly recent games (last 14 days) instead of entire season +fbff65fb fix NCAA FB Quarter logic. Fix -1th and 10 status text when negative yards are received diff --git a/wiki/CACHE_STRATEGY.md b/wiki/CACHE_STRATEGY.md deleted file mode 100644 index ff8b4a50..00000000 --- a/wiki/CACHE_STRATEGY.md +++ /dev/null @@ -1,173 +0,0 @@ -# LEDMatrix Cache Strategy Analysis - -## Current Implementation - -Your LEDMatrix system uses a sophisticated multi-tier caching strategy that balances data freshness with API efficiency. - -### Cache Duration Categories - -#### 1. **Ultra Time-Sensitive Data (15-60 seconds)** -- **Live Sports Scores**: Now respects sport-specific `live_update_interval` configuration - - Soccer live data: Uses `soccer_scoreboard.live_update_interval` (default: 60 seconds) - - NFL live data: Uses `nfl_scoreboard.live_update_interval` (default: 60 seconds) - - NHL live data: Uses `nhl_scoreboard.live_update_interval` (default: 60 seconds) - - NBA live data: Uses `nba_scoreboard.live_update_interval` (default: 60 seconds) - - MLB live data: Uses `mlb.live_update_interval` (default: 60 seconds) - - NCAA sports: Use respective `live_update_interval` configurations (default: 60 seconds) -- **Current Weather**: 5 minutes (300 seconds) - -#### 2. **Market Data (5-10 minutes)** -- **Stocks**: 10 minutes (600 seconds) - market hours aware -- **Crypto**: 5 minutes (300 seconds) - 24/7 trading -- **Stock News**: 1 hour (3600 seconds) - -#### 3. **Sports Data (5 minutes to 24 hours)** -- **Recent Games**: 5 minutes (300 seconds) -- **Upcoming Games**: 1 hour (3600 seconds) -- **Season Schedules**: 24 hours (86400 seconds) -- **Team Information**: 1 week (604800 seconds) - -#### 4. **Static Data (1 week to 30 days)** -- **Team Logos**: 30 days (2592000 seconds) -- **Configuration Data**: 1 week (604800 seconds) - -### Smart Cache Invalidation - -Beyond time limits, the system uses content-based invalidation: - -```python -def has_data_changed(self, data_type: str, new_data: Dict[str, Any]) -> bool: - """Check if data has changed from cached version.""" -``` - -- **Weather**: Compares temperature and conditions -- **Stocks**: Compares prices (only during market hours) -- **Sports**: Compares scores, game status, inning details -- **News**: Compares headlines and article IDs - -### Market-Aware Caching - -For stocks, the system extends cache duration during off-hours: - -```python -def _is_market_open(self) -> bool: - """Check if the US stock market is currently open.""" - # Only invalidates cache during market hours -``` - -## Enhanced Cache Strategy - -### Sport-Specific Live Update Intervals - -The cache manager now automatically respects the `live_update_interval` configuration for each sport: - -```python -def get_sport_live_interval(self, sport_key: str) -> int: - """Get the live_update_interval for a specific sport from config.""" - config = self.config_manager.get_config() - sport_config = config.get(f"{sport_key}_scoreboard", {}) - return sport_config.get("live_update_interval", 30) -``` - -### Automatic Sport Detection - -The cache manager automatically detects the sport from cache keys: - -```python -def get_sport_key_from_cache_key(self, key: str) -> Optional[str]: - """Extract sport key from cache key to determine appropriate live_update_interval.""" - # Maps cache key patterns to sport keys - sport_patterns = { - 'nfl': ['nfl', 'football'], - 'nba': ['nba', 'basketball'], - 'mlb': ['mlb', 'baseball'], - 'nhl': ['nhl', 'hockey'], - 'soccer': ['soccer', 'football'], - # ... etc - } -``` - -### Configuration Examples - -**Current Configuration (config/config.json):** -```json -{ - "nfl_scoreboard": { - "live_update_interval": 30, - "enabled": true - }, - "soccer_scoreboard": { - "live_update_interval": 30, - "enabled": false - }, - "mlb": { - "live_update_interval": 30, - "enabled": true - } -} -``` - -**Cache Behavior:** -- NFL live data: 30-second cache (from config) -- Soccer live data: 30-second cache (from config) -- MLB live data: 30-second cache (from config) - -### Fallback Strategy - -If configuration is unavailable, the system uses sport-specific defaults: - -```python -default_intervals = { - 'soccer': 60, # Soccer default - 'nfl': 60, # NFL default - 'nhl': 60, # NHL default - 'nba': 60, # NBA default - 'mlb': 60, # MLB default - 'milb': 60, # Minor league default - 'ncaa_fb': 60, # College football default - 'ncaa_baseball': 60, # College baseball default - 'ncaam_basketball': 60, # College basketball default -} -``` - -## Usage Examples - -### Automatic Sport Detection -```python -# Cache manager automatically detects NFL and uses nfl_scoreboard.live_update_interval -cached_data = cache_manager.get_with_auto_strategy("nfl_live_20241201") - -# Cache manager automatically detects soccer and uses soccer_scoreboard.live_update_interval -cached_data = cache_manager.get_with_auto_strategy("soccer_live_20241201") -``` - -### Manual Sport Specification -```python -# Explicitly specify sport for custom cache keys -cached_data = cache_manager.get_cached_data_with_strategy("custom_live_key", "sports_live") -``` - -## Benefits - -1. **Configuration-Driven**: Cache respects your sport-specific settings -2. **Automatic Detection**: No manual cache duration management needed -3. **Sport-Optimized**: Each sport uses its appropriate update interval -4. **Backward Compatible**: Existing code continues to work -5. **Flexible**: Easy to adjust intervals per sport in config - -## Migration - -The enhanced cache manager is backward compatible. Existing code will automatically benefit from sport-specific intervals without any changes needed. - -To customize intervals for specific sports, simply update the `live_update_interval` in your `config/config.json`: - -```json -{ - "nfl_scoreboard": { - "live_update_interval": 15 // More aggressive for NFL - }, - "mlb": { - "live_update_interval": 45 // Slower pace for MLB - } -} -``` \ No newline at end of file diff --git a/wiki/CUSTOM_FEEDS_GUIDE.md b/wiki/CUSTOM_FEEDS_GUIDE.md deleted file mode 100644 index aca7a007..00000000 --- a/wiki/CUSTOM_FEEDS_GUIDE.md +++ /dev/null @@ -1,245 +0,0 @@ -# Adding Custom RSS Feeds & Sports - Complete Guide - -This guide shows you **3 different ways** to add custom RSS feeds like F1, MotoGP, or any personal feeds to your news manager. - -## Quick Examples - -### F1 Racing Feeds -```bash -# BBC F1 (Recommended - works well) -python3 add_custom_feed_example.py add "BBC F1" "http://feeds.bbci.co.uk/sport/formula1/rss.xml" - -# Motorsport.com F1 -python3 add_custom_feed_example.py add "Motorsport F1" "https://www.motorsport.com/rss/f1/news/" - -# Formula1.com Official -python3 add_custom_feed_example.py add "F1 Official" "https://www.formula1.com/en/latest/all.xml" -``` - -### Other Sports -```bash -# MotoGP -python3 add_custom_feed_example.py add "MotoGP" "https://www.motogp.com/en/rss/news" - -# Tennis -python3 add_custom_feed_example.py add "Tennis" "https://www.atptour.com/en/rss/news" - -# Golf -python3 add_custom_feed_example.py add "Golf" "https://www.pgatour.com/news.rss" - -# Soccer/Football -python3 add_custom_feed_example.py add "ESPN Soccer" "https://www.espn.com/espn/rss/soccer/news" -``` - -### Personal/Blog Feeds -```bash -# Personal blog -python3 add_custom_feed_example.py add "My Blog" "https://myblog.com/rss.xml" - -# Tech news -python3 add_custom_feed_example.py add "TechCrunch" "https://techcrunch.com/feed/" - -# Local news -python3 add_custom_feed_example.py add "Local News" "https://localnews.com/rss" -``` - ---- - -## Method 1: Command Line (Easiest) - -### Add a Feed -```bash -python3 add_custom_feed_example.py add "FEED_NAME" "RSS_URL" -``` - -### List All Feeds -```bash -python3 add_custom_feed_example.py list -``` - -### Remove a Feed -```bash -python3 add_custom_feed_example.py remove "FEED_NAME" -``` - -### Example: Adding F1 -```bash -# Step 1: Check current feeds -python3 add_custom_feed_example.py list - -# Step 2: Add BBC F1 feed -python3 add_custom_feed_example.py add "BBC F1" "http://feeds.bbci.co.uk/sport/formula1/rss.xml" - -# Step 3: Verify it was added -python3 add_custom_feed_example.py list -``` - ---- - -## Method 2: Web Interface - -1. **Open Web Interface**: Go to `http://your-display-ip:5001` -2. **Navigate to News Tab**: Click the "News Manager" tab -3. **Add Custom Feed**: - - Enter feed name in "Feed Name" field (e.g., "BBC F1") - - Enter RSS URL in "RSS Feed URL" field - - Click "Add Feed" button -4. **Enable the Feed**: Check the checkbox next to your new feed -5. **Save Settings**: Click "Save News Settings" - ---- - -## Method 3: Direct Config Edit - -Edit `config/config.json` directly: - -```json -{ - "news_manager": { - "enabled": true, - "enabled_feeds": ["NFL", "NCAA FB", "BBC F1"], - "custom_feeds": { - "BBC F1": "http://feeds.bbci.co.uk/sport/formula1/rss.xml", - "Motorsport F1": "https://www.motorsport.com/rss/f1/news/", - "My Blog": "https://myblog.com/rss.xml" - }, - "headlines_per_feed": 2 - } -} -``` - ---- - -## Finding RSS Feeds - -### Popular Sports RSS Feeds - -| Sport | Source | RSS URL | -|-------|--------|---------| -| **F1** | BBC Sport | `http://feeds.bbci.co.uk/sport/formula1/rss.xml` | -| **F1** | Motorsport.com | `https://www.motorsport.com/rss/f1/news/` | -| **MotoGP** | Official | `https://www.motogp.com/en/rss/news` | -| **Tennis** | ATP Tour | `https://www.atptour.com/en/rss/news` | -| **Golf** | PGA Tour | `https://www.pgatour.com/news.rss` | -| **Soccer** | ESPN | `https://www.espn.com/espn/rss/soccer/news` | -| **Boxing** | ESPN | `https://www.espn.com/espn/rss/boxing/news` | -| **UFC/MMA** | ESPN | `https://www.espn.com/espn/rss/mma/news` | - -### How to Find RSS Feeds -1. **Look for RSS icons** on websites -2. **Check `/rss`, `/feed`, or `/rss.xml`** paths -3. **Use RSS discovery tools** like RSS Feed Finder -4. **Check site footers** for RSS links - -### Testing RSS Feeds -```bash -# Test if a feed works before adding it -python3 -c " -import feedparser -import requests -url = 'YOUR_RSS_URL_HERE' -try: - response = requests.get(url, timeout=10) - feed = feedparser.parse(response.content) - print(f'SUCCESS: Feed works! Title: {feed.feed.get(\"title\", \"N/A\")}') - print(f'{len(feed.entries)} articles found') - if feed.entries: - print(f'Latest: {feed.entries[0].title}') -except Exception as e: - print(f'ERROR: {e}') -" -``` - ---- - -## Advanced Configuration - -### Controlling Feed Behavior - -```json -{ - "news_manager": { - "headlines_per_feed": 3, // Headlines from each feed - "scroll_speed": 2, // Pixels per frame - "scroll_delay": 0.02, // Seconds between updates - "rotation_enabled": true, // Rotate content to avoid repetition - "rotation_threshold": 3, // Cycles before rotating - "update_interval": 300 // Seconds between feed updates - } -} -``` - -### Feed Priority -Feeds are displayed in the order they appear in `enabled_feeds`: -```json -"enabled_feeds": ["NFL", "BBC F1", "NCAA FB"] // NFL first, then F1, then NCAA -``` - -### Custom Display Names -You can use any display name for feeds: -```bash -python3 add_custom_feed_example.py add "Formula 1" "http://feeds.bbci.co.uk/sport/formula1/rss.xml" -python3 add_custom_feed_example.py add "Basketball News" "https://www.espn.com/espn/rss/nba/news" -``` - ---- - -## Troubleshooting - -### Feed Not Working? -1. **Test the RSS URL** using the testing command above -2. **Check for HTTPS vs HTTP** - some feeds require secure connections -3. **Verify the feed format** - must be valid RSS or Atom -4. **Check rate limiting** - some sites block frequent requests - -### Common Issues -- **403 Forbidden**: Site blocks automated requests (try different feed) -- **SSL Errors**: Use HTTP instead of HTTPS if available -- **No Content**: Feed might be empty or incorrectly formatted -- **Slow Loading**: Increase timeout in news manager settings - -### Feed Alternatives -If one feed doesn't work, try alternatives: -- **ESPN feeds** sometimes have access restrictions -- **BBC feeds** are generally reliable -- **Official sport websites** often have RSS feeds -- **News aggregators** like Google News have topic-specific feeds - ---- - -## Real-World Example: Complete F1 Setup - -```bash -# 1. List current setup -python3 add_custom_feed_example.py list - -# 2. Add multiple F1 sources for better coverage -python3 add_custom_feed_example.py add "BBC F1" "http://feeds.bbci.co.uk/sport/formula1/rss.xml" -python3 add_custom_feed_example.py add "Motorsport F1" "https://www.motorsport.com/rss/f1/news/" - -# 3. Add other racing series -python3 add_custom_feed_example.py add "MotoGP" "https://www.motogp.com/en/rss/news" - -# 4. Verify all feeds work -python3 simple_news_test.py - -# 5. Check final configuration -python3 add_custom_feed_example.py list -``` - -Result: Your display will now rotate between NFL, NCAA FB, BBC F1, Motorsport F1, and MotoGP headlines! - ---- - -## Pro Tips - -1. **Start Small**: Add one feed at a time and test it -2. **Mix Sources**: Use multiple sources for the same sport for better coverage -3. **Monitor Performance**: Too many feeds can slow down updates -4. **Use Descriptive Names**: "BBC F1" is better than just "F1" -5. **Test Regularly**: RSS feeds can change or break over time -6. **Backup Config**: Save your `config.json` before making changes - ---- - -**Need help?** The news manager is designed to be flexible and user-friendly. Start with the command line method - it's the easiest way to get started! \ No newline at end of file diff --git a/wiki/DYNAMIC_DURATION_GUIDE.md b/wiki/DYNAMIC_DURATION_GUIDE.md deleted file mode 100644 index 9e04a198..00000000 --- a/wiki/DYNAMIC_DURATION_GUIDE.md +++ /dev/null @@ -1,177 +0,0 @@ -# Dynamic Duration Feature - Complete Guide - -The news manager now includes intelligent **dynamic duration calculation** that automatically determines the exact time needed to display all your selected headlines without cutting off mid-scroll. - -## How It Works - -### Automatic Calculation -The system calculates the perfect display duration by: - -1. **Measuring Text Width**: Calculates the exact pixel width of all headlines combined -2. **Computing Scroll Distance**: Determines how far text needs to scroll (display width + text width) -3. **Calculating Time**: Uses scroll speed and delay to compute exact timing -4. **Adding Buffer**: Includes configurable buffer time for smooth transitions -5. **Applying Limits**: Ensures duration stays within your min/max preferences - -### Real-World Example -With current settings (4 feeds, 2 headlines each): -- **Total Headlines**: 8 headlines per cycle -- **Estimated Duration**: 57 seconds -- **Cycles per Hour**: ~63 cycles -- **Result**: Perfect timing, no cut-offs - -## Configuration Options - -### Core Settings -```json -{ - "news_manager": { - "dynamic_duration": true, // Enable/disable feature - "min_duration": 30, // Minimum display time (seconds) - "max_duration": 300, // Maximum display time (seconds) - "duration_buffer": 0.1, // Buffer time (10% extra) - "headlines_per_feed": 2, // Headlines from each feed - "scroll_speed": 2, // Pixels per frame - "scroll_delay": 0.02 // Seconds per frame - } -} -``` - -### Duration Scenarios - -| Scenario | Headlines | Est. Duration | Cycles/Hour | -|----------|-----------|---------------|-------------| -| **Light** | 4 headlines | 30s (min) | 120 | -| **Medium** | 6 headlines | 30s (min) | 120 | -| **Current** | 8 headlines | 57s | 63 | -| **Heavy** | 12 headlines | 85s | 42 | -| **Maximum** | 20+ headlines | 300s (max) | 12 | - -## Benefits - -### Perfect Timing -- **No Cut-offs**: Headlines never cut off mid-sentence -- **Complete Cycles**: Always shows full rotation of all selected content -- **Smooth Transitions**: Buffer time prevents jarring switches - -### Intelligent Scaling -- **Adapts to Content**: More feeds = longer duration automatically -- **User Control**: Set your preferred min/max limits -- **Flexible**: Works with any combination of feeds and headlines - -### Predictable Behavior -- **Consistent Experience**: Same content always takes same time -- **Reliable Cycling**: Know exactly when content will repeat -- **Configurable**: Adjust to your viewing preferences - -## Usage Examples - -### Command Line Testing -```bash -# Test dynamic duration calculations -python3 test_dynamic_duration.py - -# Check current status -python3 test_dynamic_duration.py status -``` - -### Configuration Changes -```bash -# Add more feeds (increases duration) -python3 add_custom_feed_example.py add "Tennis" "https://www.atptour.com/en/rss/news" - -# Check new duration -python3 test_dynamic_duration.py status -``` - -### Web Interface -1. Go to `http://display-ip:5001` -2. Click "News Manager" tab -3. Adjust "Duration Settings": - - **Min Duration**: Shortest acceptable cycle time - - **Max Duration**: Longest acceptable cycle time - - **Buffer**: Extra time for smooth transitions - -## Advanced Configuration - -### Fine-Tuning Duration -```json -{ - "min_duration": 45, // Increase for longer minimum cycles - "max_duration": 180, // Decrease for shorter maximum cycles - "duration_buffer": 0.15 // Increase buffer for more transition time -} -``` - -### Scroll Speed Impact -```json -{ - "scroll_speed": 3, // Faster scroll = shorter duration - "scroll_delay": 0.015 // Less delay = shorter duration -} -``` - -### Content Control -```json -{ - "headlines_per_feed": 3, // More headlines = longer duration - "enabled_feeds": [ // More feeds = longer duration - "NFL", "NBA", "MLB", "NHL", "BBC F1", "Tennis" - ] -} -``` - -## Troubleshooting - -### Duration Too Short -- **Increase** `min_duration` -- **Add** more feeds or headlines per feed -- **Decrease** `scroll_speed` - -### Duration Too Long -- **Decrease** `max_duration` -- **Remove** some feeds -- **Reduce** `headlines_per_feed` -- **Increase** `scroll_speed` - -### Jerky Transitions -- **Increase** `duration_buffer` -- **Adjust** `scroll_delay` - -## Disable Dynamic Duration - -To use fixed timing instead: -```json -{ - "dynamic_duration": false, - "fixed_duration": 60 // Fixed 60-second cycles -} -``` - -## Technical Details - -### Calculation Formula -``` -total_scroll_distance = display_width + text_width -frames_needed = total_scroll_distance / scroll_speed -base_time = frames_needed * scroll_delay -buffer_time = base_time * duration_buffer -final_duration = base_time + buffer_time (within min/max limits) -``` - -### Display Integration -The display controller automatically: -1. Calls `news_manager.get_dynamic_duration()` -2. Uses returned value for display timing -3. Switches to next mode after exact calculated time -4. Logs duration decisions for debugging - -## Best Practices - -1. **Start Conservative**: Use default settings initially -2. **Test Changes**: Use test script to preview duration changes -3. **Monitor Performance**: Watch for smooth transitions -4. **Adjust Gradually**: Make small changes to settings -5. **Consider Viewing**: Match duration to your typical viewing patterns - -The dynamic duration feature ensures your news ticker always displays complete, perfectly-timed content cycles regardless of how many feeds or headlines you configure! \ No newline at end of file diff --git a/wiki/DYNAMIC_DURATION_STOCKS_IMPLEMENTATION.md b/wiki/DYNAMIC_DURATION_STOCKS_IMPLEMENTATION.md deleted file mode 100644 index fc34cbba..00000000 --- a/wiki/DYNAMIC_DURATION_STOCKS_IMPLEMENTATION.md +++ /dev/null @@ -1,189 +0,0 @@ -# Dynamic Duration Implementation for Stocks and Stock News - -## Overview - -This document describes the implementation of dynamic duration functionality for the `stock_manager` and `stock_news_manager` classes, following the same pattern as the existing `news_manager`. - -## What Was Implemented - -### 1. Configuration Updates - -Added dynamic duration settings to both `stocks` and `stock_news` sections in `config/config.json`: - -```json -"stocks": { - "enabled": true, - "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": [...], - "display_format": "{symbol}: ${price} ({change}%)" -}, -"stock_news": { - "enabled": true, - "update_interval": 3600, - "scroll_speed": 1, - "scroll_delay": 0.01, - "max_headlines_per_symbol": 1, - "headlines_per_rotation": 2, - "dynamic_duration": true, - "min_duration": 30, - "max_duration": 300, - "duration_buffer": 0.1 -} -``` - -### 2. Stock Manager Updates (`src/stock_manager.py`) - -#### Added Dynamic Duration Properties -```python -# Dynamic duration settings -self.dynamic_duration_enabled = self.stocks_config.get('dynamic_duration', True) -self.min_duration = self.stocks_config.get('min_duration', 30) -self.max_duration = self.stocks_config.get('max_duration', 300) -self.duration_buffer = self.stocks_config.get('duration_buffer', 0.1) -self.dynamic_duration = 60 # Default duration in seconds -self.total_scroll_width = 0 # Track total width for dynamic duration calculation -``` - -#### Added `calculate_dynamic_duration()` Method -This method calculates the exact time needed to display all stocks based on: -- Total scroll width of the content -- Display width -- Scroll speed and delay settings -- Configurable buffer time -- Min/max duration limits - -#### Added `get_dynamic_duration()` Method -Returns the calculated dynamic duration for use by the display controller. - -#### Updated `display_stocks()` Method -The method now calculates and stores the total scroll width and calls `calculate_dynamic_duration()` when creating the scrolling image. - -### 3. Stock News Manager Updates (`src/stock_news_manager.py`) - -#### Added Dynamic Duration Properties -```python -# Dynamic duration settings -self.dynamic_duration_enabled = self.stock_news_config.get('dynamic_duration', True) -self.min_duration = self.stock_news_config.get('min_duration', 30) -self.max_duration = self.stock_news_config.get('max_duration', 300) -self.duration_buffer = self.stock_news_config.get('duration_buffer', 0.1) -self.dynamic_duration = 60 # Default duration in seconds -self.total_scroll_width = 0 # Track total width for dynamic duration calculation -``` - -#### Added `calculate_dynamic_duration()` Method -Similar to the stock manager, calculates duration based on content width and scroll settings. - -#### Added `get_dynamic_duration()` Method -Returns the calculated dynamic duration for use by the display controller. - -#### Updated `display_news()` Method -The method now calculates and stores the total scroll width and calls `calculate_dynamic_duration()` when creating the scrolling image. - -### 4. Display Controller Updates (`src/display_controller.py`) - -#### Updated `get_current_duration()` Method -Added dynamic duration handling for both `stocks` and `stock_news` modes: - -```python -# Handle dynamic duration for stocks -if mode_key == 'stocks' and self.stocks: - try: - dynamic_duration = self.stocks.get_dynamic_duration() - # Only log if duration has changed or we haven't logged this duration yet - if not hasattr(self, '_last_logged_duration') or self._last_logged_duration != dynamic_duration: - logger.info(f"Using dynamic duration for stocks: {dynamic_duration} seconds") - self._last_logged_duration = dynamic_duration - return dynamic_duration - except Exception as e: - logger.error(f"Error getting dynamic duration for stocks: {e}") - # Fall back to configured duration - return self.display_durations.get(mode_key, 60) - -# Handle dynamic duration for stock_news -if mode_key == 'stock_news' and self.news: - try: - dynamic_duration = self.news.get_dynamic_duration() - # Only log if duration has changed or we haven't logged this duration yet - if not hasattr(self, '_last_logged_duration') or self._last_logged_duration != dynamic_duration: - logger.info(f"Using dynamic duration for stock_news: {dynamic_duration} seconds") - self._last_logged_duration = dynamic_duration - return dynamic_duration - except Exception as e: - logger.error(f"Error getting dynamic duration for stock_news: {e}") - # Fall back to configured duration - return self.display_durations.get(mode_key, 60) -``` - -## How It Works - -### Dynamic Duration Calculation - -The dynamic duration is calculated using the following formula: - -1. **Total Scroll Distance**: `display_width + total_scroll_width` -2. **Frames Needed**: `total_scroll_distance / scroll_speed` -3. **Base Time**: `frames_needed * scroll_delay` -4. **Buffer Time**: `base_time * duration_buffer` -5. **Final Duration**: `int(base_time + buffer_time)` - -The final duration is then clamped between `min_duration` and `max_duration`. - -### Integration with Display Controller - -1. When the display controller needs to determine how long to show a particular mode, it calls `get_current_duration()` -2. For `stocks` and `stock_news` modes, it calls the respective manager's `get_dynamic_duration()` method -3. The manager returns the calculated duration based on the current content width -4. The display controller uses this duration to determine how long to display the content - -### Benefits - -1. **Consistent Display Time**: Content is displayed for an appropriate amount of time based on its length -2. **Configurable**: Users can adjust min/max durations and buffer percentages -3. **Fallback Support**: If dynamic duration fails, it falls back to configured fixed durations -4. **Performance**: Duration is calculated once when content is created, not on every frame - -## Configuration Options - -### Dynamic Duration Settings - -- **`dynamic_duration`**: Enable/disable dynamic duration calculation (default: `true`) -- **`min_duration`**: Minimum display duration in seconds (default: `30`) -- **`max_duration`**: Maximum display duration in seconds (default: `300`) -- **`duration_buffer`**: Buffer percentage to add for smooth cycling (default: `0.1` = 10%) - -### Example Configuration - -```json -{ - "dynamic_duration": true, - "min_duration": 20, - "max_duration": 180, - "duration_buffer": 0.15 -} -``` - -This would: -- Enable dynamic duration -- Set minimum display time to 20 seconds -- Set maximum display time to 3 minutes -- Add 15% buffer time for smooth cycling - -## Testing - -The implementation has been tested to ensure: -- Configuration is properly loaded -- Dynamic duration calculation works correctly -- Display controller integration is functional -- Fallback behavior works when dynamic duration is disabled - -## Compatibility - -This implementation follows the exact same pattern as the existing `news_manager` dynamic duration functionality, ensuring consistency across the codebase and making it easy to maintain and extend. diff --git a/wiki/GRACEFUL_UPDATES.md b/wiki/GRACEFUL_UPDATES.md deleted file mode 100644 index ec16d06f..00000000 --- a/wiki/GRACEFUL_UPDATES.md +++ /dev/null @@ -1,146 +0,0 @@ -# Graceful Update System - -The LED Matrix project now includes a graceful update system that prevents lag during scrolling displays by deferring updates until the display is not actively scrolling. - -## Overview - -When displays like the odds ticker, stock ticker, or news ticker are actively scrolling, performing API updates or data fetching can cause visual lag or stuttering. The graceful update system solves this by: - -1. **Tracking scrolling state** - The system monitors when displays are actively scrolling -2. **Deferring updates** - Updates that might cause lag are deferred during scrolling periods -3. **Processing when safe** - Deferred updates are processed when scrolling stops or during non-scrolling periods -4. **Priority-based execution** - Updates are executed in priority order when processed - -## How It Works - -### Scrolling State Tracking - -The `DisplayManager` class now includes scrolling state tracking: - -```python -# Signal when scrolling starts -display_manager.set_scrolling_state(True) - -# Signal when scrolling stops -display_manager.set_scrolling_state(False) - -# Check if currently scrolling -if display_manager.is_currently_scrolling(): - # Defer updates - pass -``` - -### Deferred Updates - -Updates can be deferred using the `defer_update` method: - -```python -# Defer an update with priority -display_manager.defer_update( - lambda: self._perform_update(), - priority=1 # Lower numbers = higher priority -) -``` - -### Automatic Processing - -Deferred updates are automatically processed when: -- A display signals it's not scrolling -- The main loop processes updates during non-scrolling periods -- The inactivity threshold is reached (default: 2 seconds) - -## Implementation Details - -### Display Manager Changes - -The `DisplayManager` class now includes: - -- `set_scrolling_state(is_scrolling)` - Signal scrolling state changes -- `is_currently_scrolling()` - Check if display is currently scrolling -- `defer_update(update_func, priority)` - Defer an update function -- `process_deferred_updates()` - Process all pending deferred updates -- `get_scrolling_stats()` - Get current scrolling statistics - -### Manager Updates - -The following managers have been updated to use the graceful update system: - -#### Odds Ticker Manager -- Defers API updates during scrolling -- Signals scrolling state during display -- Processes deferred updates when not scrolling - -#### Stock Manager -- Defers stock data updates during scrolling -- Always signals scrolling state (continuous scrolling) -- Priority 2 for stock updates - -#### Stock News Manager -- Defers news data updates during scrolling -- Signals scrolling state during display -- Priority 2 for news updates - -### Display Controller Changes - -The main display controller now: -- Checks scrolling state before updating modules -- Defers scrolling-sensitive updates during scrolling periods -- Processes deferred updates in the main loop -- Continues non-scrolling-sensitive updates normally - -## Configuration - -The system uses these default settings: - -- **Inactivity threshold**: 2.0 seconds -- **Update priorities**: - - Priority 1: Odds ticker updates - - Priority 2: Stock and news updates - - Priority 3+: Other updates - -## Benefits - -1. **Smoother Scrolling** - No more lag during ticker scrolling -2. **Better User Experience** - Displays remain responsive during updates -3. **Efficient Resource Usage** - Updates happen when the system is idle -4. **Priority-Based** - Important updates are processed first -5. **Automatic** - No manual intervention required - -## Testing - -You can test the graceful update system using the provided test script: - -```bash -python test_graceful_updates.py -``` - -This script demonstrates: -- Deferring updates during scrolling -- Processing updates when not scrolling -- Priority-based execution -- Inactivity threshold behavior - -## Debugging - -To debug the graceful update system, enable debug logging: - -```python -import logging -logging.getLogger('src.display_manager').setLevel(logging.DEBUG) -``` - -The system will log: -- When scrolling state changes -- When updates are deferred -- When deferred updates are processed -- Current scrolling statistics - -## Future Enhancements - -Potential improvements to the system: - -1. **Configurable thresholds** - Allow users to adjust inactivity thresholds -2. **More granular priorities** - Add more priority levels for different update types -3. **Update batching** - Group similar updates to reduce processing overhead -4. **Performance metrics** - Track and report update deferral statistics -5. **Web interface integration** - Show deferred update status in the web UI diff --git a/wiki/INSTALLATION_GUIDE.md b/wiki/INSTALLATION_GUIDE.md deleted file mode 100644 index ab06d5fc..00000000 --- a/wiki/INSTALLATION_GUIDE.md +++ /dev/null @@ -1,343 +0,0 @@ -# LED Matrix Installation Guide - -## Quick Start (Recommended for First-Time Installation) - -# System Setup & Installation - -1. Open PowerShell and ssh into your Raspberry Pi with ledpi@ledpi (or Username@Hostname) -```bash -ssh ledpi@ledpi -``` - -2. Update repositories, upgrade raspberry pi OS, install git -```bash -sudo apt update && sudo apt upgrade -y -sudo apt install -y git python3-pip cython3 build-essential python3-dev python3-pillow scons -``` - -3. Clone this repository: -```bash -git clone https://github.com/ChuckBuilds/LEDMatrix.git -cd LEDMatrix -``` - -4. First-time installation (recommended) - -```bash -chmod +x first_time_install.sh -sudo ./first_time_install.sh -``` - ------ Old Instructions left for posterity ------ - -4. Install dependencies: -```bash -sudo pip3 install --break-system-packages -r requirements.txt -``` ---break-system-packages allows us to install without a virtual environment - - -5. Install rpi-rgb-led-matrix dependencies: -```bash -cd rpi-rgb-led-matrix-master -``` -```bash -sudo make build-python PYTHON=$(which python3) -``` -```bash -cd bindings/python -sudo python3 setup.py install -``` -Test it with: -```bash -python3 -c 'from rgbmatrix import RGBMatrix, RGBMatrixOptions; print("Success!")' -``` - -## 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 <=5.9.0` - System monitoring -- Updated Flask and related packages for better compatibility - -### File Structure -``` -├── web_interface_v2.py # Enhanced backend with all features -├── templates/index_v2.html # Complete frontend with all tabs -├── requirements_web_v2.txt # Updated dependencies -├── start_web_v2.py # Startup script (unchanged) -└── WEB_INTERFACE_V2_ENHANCED_SUMMARY.md # This summary -``` - -### Key Features Preserved from Original -- All configuration options from the original web interface -- JSON linter with validation and formatting -- System actions (start/stop service, reboot, git pull) -- API key management -- News manager functionality -- Sports configuration -- Display duration settings -- All form validation and error handling - -### New Features Added -- CPU utilization monitoring -- Enhanced display preview (8x scaling, 20fps) -- Complete LED Matrix hardware configuration -- Improved responsive design -- Better error handling and user feedback -- Real-time system stats updates -- Enhanced JSON editor with validation -- Visual status indicators throughout - -## Usage - -1. **Start the Enhanced Interface**: - ```bash - python3 start_web_v2.py - ``` - -2. **Access the Interface**: - Open browser to `http://your-pi-ip:5001` - -3. **Configure LED Matrix**: - - Go to "Display" tab for hardware settings - - Use "Schedule" tab for timing - - Configure services in respective tabs - -4. **Monitor System**: - - "Overview" tab shows real-time stats - - CPU, memory, disk, and temperature monitoring - -5. **Edit Configurations**: - - Use individual tabs for specific settings - - "Raw JSON" tab for direct configuration editing - - Real-time validation and error feedback - -## Benefits - -1. **Complete Control**: Every LED Matrix configuration option is now accessible -2. **Better Monitoring**: Real-time system performance monitoring -3. **Improved Usability**: Modern, responsive interface with better UX -4. **Enhanced Preview**: Better display preview with higher resolution -5. **Comprehensive Management**: All features in one unified interface -6. **Backward Compatibility**: All original features preserved and enhanced - -The enhanced web interface provides a complete, professional-grade management system for LED Matrix displays while maintaining ease of use and reliability. \ No newline at end of file diff --git a/wiki/WIKI_ARCHITECTURE.md b/wiki/WIKI_ARCHITECTURE.md deleted file mode 100644 index 511c8806..00000000 --- a/wiki/WIKI_ARCHITECTURE.md +++ /dev/null @@ -1,587 +0,0 @@ -# System Architecture - -The LEDMatrix system is built with a modular, extensible architecture that separates concerns and allows for easy maintenance and extension. This guide explains how all components work together. - -## System Overview - -``` -┌─────────────────────────────────────────────────────────────┐ -│ LEDMatrix System │ -├─────────────────────────────────────────────────────────────┤ -│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ -│ │ Display │ │ Display │ │ Display │ │ -│ │ Controller │ │ Manager │ │ Managers │ │ -│ │ │ │ │ │ │ │ -│ │ • Main Loop │ │ • Hardware │ │ • Weather │ │ -│ │ • Rotation │ │ • Rendering │ │ • Stocks │ │ -│ │ • Scheduling│ │ • Fonts │ │ • Sports │ │ -│ │ • Live Mode │ │ • Graphics │ │ • Music │ │ -│ └─────────────┘ └─────────────┘ └─────────────┘ │ -├─────────────────────────────────────────────────────────────┤ -│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ -│ │ Config │ │ Cache │ │ Web │ │ -│ │ Manager │ │ Manager │ │ Interface │ │ -│ │ │ │ │ │ │ │ -│ │ • Settings │ │ • Data │ │ • Control │ │ -│ │ • Validation│ │ • Persistence│ │ • Status │ │ -│ │ • Loading │ │ • Fallbacks │ │ • Settings │ │ -│ └─────────────┘ └─────────────┘ └─────────────┘ │ -└─────────────────────────────────────────────────────────────┘ -``` - -## Core Components - -### 1. Display Controller (`src/display_controller.py`) - -**Purpose**: Main orchestrator that manages the entire display system. - -**Responsibilities**: -- Initialize all display managers -- Control display rotation and timing -- Handle live game priority -- Manage system scheduling -- Coordinate data updates -- Handle error recovery - -**Key Methods**: -```python -class DisplayController: - def __init__(self): - # Initialize all managers and configuration - - def run(self): - # Main display loop - - def _update_modules(self): - # Update all enabled modules - - def _check_live_games(self): - # Check for live games and prioritize - - def _rotate_team_games(self, sport): - # Rotate through team games -``` - -**Data Flow**: -1. Load configuration -2. Initialize display managers -3. Start main loop -4. Check for live games -5. Rotate through enabled displays -6. Handle scheduling and timing - -### 2. Display Manager (`src/display_manager.py`) - -**Purpose**: Low-level hardware interface and graphics rendering. - -**Responsibilities**: -- Initialize RGB LED matrix hardware -- Handle font loading and management -- Provide drawing primitives -- Manage display buffers -- Handle hardware configuration -- Provide text rendering utilities - -**Key Features**: -```python -class DisplayManager: - def __init__(self, config): - # Initialize hardware and fonts - - def draw_text(self, text, x, y, color, font): - # Draw text on display - - def update_display(self): - # Update physical display - - def clear(self): - # Clear display - - def draw_weather_icon(self, condition, x, y, size): - # Draw weather icons -``` - -**Hardware Interface**: -- RGB Matrix library integration -- GPIO pin management -- PWM timing control -- Double buffering for smooth updates -- Font rendering (TTF and BDF) - -### 3. Configuration Manager (`src/config_manager.py`) - -**Purpose**: Load, validate, and manage system configuration. - -**Responsibilities**: -- Load JSON configuration files -- Validate configuration syntax -- Provide default values -- Handle configuration updates -- Manage secrets and API keys - -**Configuration Sources**: -```python -class ConfigManager: - def load_config(self): - # Load main config.json - - def load_secrets(self): - # Load config_secrets.json - - def validate_config(self): - # Validate configuration - - def get_defaults(self): - # Provide default values -``` - -**Configuration Structure**: -- Main settings in `config/config.json` -- API keys in `config/config_secrets.json` -- Validation and error handling -- Default value fallbacks - -### 4. Cache Manager (`src/cache_manager.py`) - -**Purpose**: Intelligent data caching to reduce API calls and improve performance. - -**Responsibilities**: -- Store API responses -- Manage cache expiration -- Handle cache persistence -- Provide fallback data -- Optimize storage usage - -**Cache Strategy**: -```python -class CacheManager: - def get(self, key): - # Retrieve cached data - - def set(self, key, data, ttl): - # Store data with expiration - - def is_valid(self, key): - # Check if cache is still valid - - def clear_expired(self): - # Remove expired cache entries -``` - -**Cache Locations** (in order of preference): -1. `~/.ledmatrix_cache/` (user's home directory) -2. `/var/cache/ledmatrix/` (system cache directory) -3. `/tmp/ledmatrix_cache/` (temporary directory) - -## Display Manager Architecture - -### Manager Interface - -All display managers follow a consistent interface: - -```python -class BaseManager: - def __init__(self, config, display_manager): - self.config = config - self.display_manager = display_manager - self.cache_manager = CacheManager() - - def update_data(self): - """Fetch and process new data""" - pass - - def display(self, force_clear=False): - """Render content to display""" - pass - - def is_enabled(self): - """Check if manager is enabled""" - return self.config.get('enabled', False) - - def get_duration(self): - """Get display duration""" - return self.config.get('duration', 30) -``` - -### Data Flow Pattern - -Each manager follows this pattern: - -1. **Initialization**: Load configuration and setup -2. **Data Fetching**: Retrieve data from APIs or local sources -3. **Caching**: Store data using CacheManager -4. **Processing**: Transform raw data into display format -5. **Rendering**: Use DisplayManager to show content -6. **Cleanup**: Return control to main controller - -### Error Handling - -- **API Failures**: Fall back to cached data -- **Network Issues**: Use last known good data -- **Invalid Data**: Filter out bad entries -- **Hardware Errors**: Graceful degradation -- **Configuration Errors**: Use safe defaults - -## Sports Manager Architecture - -### Sports Manager Pattern - -Each sport follows a three-manager pattern: - -```python -# Live games (currently playing) -class NHLLiveManager(BaseSportsManager): - def fetch_games(self): - # Get currently playing games - - def display_games(self): - # Show live scores and status - -# Recent games (completed) -class NHLRecentManager(BaseSportsManager): - def fetch_games(self): - # Get recently completed games - - def display_games(self): - # Show final scores - -# Upcoming games (scheduled) -class NHLUpcomingManager(BaseSportsManager): - def fetch_games(self): - # Get scheduled games - - def display_games(self): - # Show game times and matchups -``` - -### Base Sports Manager - -Common functionality shared by all sports: - -```python -class BaseSportsManager: - def __init__(self, config, display_manager): - # Common initialization - - def fetch_espn_data(self, sport, endpoint): - # Fetch from ESPN API - - def process_game_data(self, games): - # Process raw game data - - def display_game(self, game): - # Display individual game - - def get_team_logo(self, team_abbr): - # Load team logo - - def format_score(self, score): - # Format score display -``` - -### ESPN API Integration - -All sports use ESPN's API for data: - -```python -def fetch_espn_data(self, sport, endpoint): - url = f"http://site.api.espn.com/apis/site/v2/sports/{sport}/{endpoint}" - response = requests.get(url) - return response.json() -``` - -**Supported Sports**: -- NHL (hockey) -- NBA (basketball) -- MLB (baseball) -- NFL (football) -- NCAA Football -- NCAA Basketball -- NCAA Baseball -- Soccer (multiple leagues) -- MiLB (minor league baseball) - -## Financial Data Architecture - -### Stock Manager - -```python -class StockManager: - def __init__(self, config, display_manager): - # Initialize stock and crypto settings - - def fetch_stock_data(self, symbol): - # Fetch from Yahoo Finance - - def fetch_crypto_data(self, symbol): - # Fetch crypto data - - def display_stocks(self): - # Show stock ticker - - def display_crypto(self): - # Show crypto prices -``` - -### Stock News Manager - -```python -class StockNewsManager: - def __init__(self, config, display_manager): - # Initialize news settings - - def fetch_news(self, symbols): - # Fetch financial news - - def display_news(self): - # Show news headlines -``` - -## Weather Architecture - -### Weather Manager - -```python -class WeatherManager: - def __init__(self, config, display_manager): - # Initialize weather settings - - def fetch_weather(self): - # Fetch from OpenWeatherMap - - def display_current_weather(self): - # Show current conditions - - def display_hourly_forecast(self): - # Show hourly forecast - - def display_daily_forecast(self): - # Show daily forecast -``` - -### Weather Icons - -```python -class WeatherIcons: - def __init__(self): - # Load weather icon definitions - - def get_icon(self, condition): - # Get icon for weather condition - - def draw_icon(self, condition, x, y, size): - # Draw weather icon -``` - -## Music Architecture - -### Music Manager - -```python -class MusicManager: - def __init__(self, display_manager, config): - # Initialize music settings - - def start_polling(self): - # Start background polling - - def update_music_display(self): - # Update music information - - def display_spotify(self): - # Display Spotify info - - def display_ytm(self): - # Display YouTube Music info -``` - -### Spotify Client - -```python -class SpotifyClient: - def __init__(self, config): - # Initialize Spotify API - - def authenticate(self): - # Handle OAuth authentication - - def get_current_track(self): - # Get currently playing track -``` - -### YouTube Music Client - -```python -class YTMClient: - def __init__(self, config): - # Initialize YTM companion server - - def get_current_track(self): - # Get current track from YTMD -``` - -## Web Interface Architecture - -### Web Interface - -```python -class WebInterface: - def __init__(self, config): - # Initialize Flask app - - def start_server(self): - # Start web server - - def get_status(self): - # Get system status - - def control_display(self, action): - # Control display actions -``` - -**Features**: -- System status monitoring -- Display control (start/stop) -- Configuration management -- Service management -- Real-time status updates - -## Service Architecture - -### Systemd Service - -```ini -[Unit] -Description=LEDMatrix Display Service -After=network.target - -[Service] -Type=simple -User=root -WorkingDirectory=/home/ledpi/LEDMatrix -ExecStart=/usr/bin/python3 display_controller.py -Restart=always -RestartSec=10 - -[Install] -WantedBy=multi-user.target -``` - -**Service Features**: -- Automatic startup -- Crash recovery -- Log management -- Resource monitoring - -## Data Flow Architecture - -### 1. Configuration Loading - -``` -config.json → ConfigManager → DisplayController → Display Managers -``` - -### 2. Data Fetching - -``` -API Sources → CacheManager → Display Managers → Display Manager -``` - -### 3. Display Rendering - -``` -Display Managers → Display Manager → RGB Matrix → LED Display -``` - -### 4. User Control - -``` -Web Interface → Display Controller → Display Managers -``` - -## Performance Architecture - -### Caching Strategy - -1. **API Response Caching**: Store API responses with TTL -2. **Processed Data Caching**: Cache processed display data -3. **Font Caching**: Cache loaded fonts -4. **Image Caching**: Cache team logos and icons - -### Resource Management - -1. **Memory Usage**: Monitor and optimize memory usage -2. **CPU Usage**: Minimize processing overhead -3. **Network Usage**: Optimize API calls -4. **Storage Usage**: Manage cache storage - -### Error Recovery - -1. **API Failures**: Use cached data -2. **Network Issues**: Retry with exponential backoff -3. **Hardware Errors**: Graceful degradation -4. **Configuration Errors**: Use safe defaults - -## Extension Architecture - -### Adding New Display Managers - -1. **Create Manager Class**: Extend base manager pattern -2. **Add Configuration**: Add to config.json -3. **Register in Controller**: Add to DisplayController -4. **Add Assets**: Include logos, icons, fonts -5. **Test Integration**: Verify with main system - -### Example New Manager - -```python -class CustomManager(BaseManager): - def __init__(self, config, display_manager): - super().__init__(config, display_manager) - - def update_data(self): - # Fetch custom data - - def display(self, force_clear=False): - # Display custom content -``` - -## Security Architecture - -### API Key Management - -1. **Separate Secrets**: Store in config_secrets.json -2. **Environment Variables**: Support for env vars -3. **Access Control**: Restrict file permissions -4. **Key Rotation**: Support for key updates - -### Network Security - -1. **HTTPS Only**: Use secure API endpoints -2. **Rate Limiting**: Respect API limits -3. **Error Handling**: Don't expose sensitive data -4. **Logging**: Secure log management - -## Monitoring Architecture - -### Logging System - -```python -import logging - -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(levelname)s:%(name)s:%(message)s' -) -``` - -### Health Monitoring - -1. **API Health**: Monitor API availability -2. **Display Health**: Monitor display functionality -3. **Cache Health**: Monitor cache performance -4. **System Health**: Monitor system resources - ---- - -*This architecture provides a solid foundation for the LEDMatrix system while maintaining flexibility for future enhancements and customizations.* \ No newline at end of file diff --git a/wiki/WIKI_CONFIGURATION.md b/wiki/WIKI_CONFIGURATION.md deleted file mode 100644 index c5febc66..00000000 --- a/wiki/WIKI_CONFIGURATION.md +++ /dev/null @@ -1,654 +0,0 @@ -# Configuration Guide - -The LEDMatrix system is configured through JSON files that control every aspect of the display. This guide covers all configuration options and their effects. - -## Configuration Files - -### Main Configuration (`config/config.json`) -Contains all non-sensitive settings for the system. - -### Secrets Configuration (`config/config_secrets.json`) -Contains API keys and sensitive credentials. - -## System Configuration - -### Display Hardware Settings - -```json -{ - "display": { - "hardware": { - "rows": 32, - "cols": 64, - "chain_length": 2, - "parallel": 1, - "brightness": 95, - "hardware_mapping": "adafruit-hat-pwm", - "scan_mode": 0, - "pwm_bits": 9, - "pwm_dither_bits": 1, - "pwm_lsb_nanoseconds": 130, - "disable_hardware_pulsing": false, - "inverse_colors": false, - "show_refresh_rate": false, - "limit_refresh_rate_hz": 120 - }, - "runtime": { - "gpio_slowdown": 3 - } - } -} -``` - -**Hardware Settings Explained**: -- **`rows`/`cols`**: Physical LED matrix dimensions (32x64 for 2 panels) -- **`chain_length`**: Number of LED panels connected (2 for 128x32 total) -- **`parallel`**: Number of parallel chains (usually 1) -- **`brightness`**: Display brightness (0-100) -- **`hardware_mapping`**: - - `"adafruit-hat-pwm"`: With jumper mod (recommended) - - `"adafruit-hat"`: Without jumper mod -- **`pwm_bits`**: Color depth (8-11, higher = better colors) -- **`gpio_slowdown`**: Timing adjustment (3 for Pi 3, 4 for Pi 4) - -### Display Durations - -```json -{ - "display": { - "display_durations": { - "clock": 15, - "weather": 30, - "stocks": 30, - "hourly_forecast": 30, - "daily_forecast": 30, - "stock_news": 20, - "odds_ticker": 60, - "nhl_live": 30, - "nhl_recent": 30, - "nhl_upcoming": 30, - "nba_live": 30, - "nba_recent": 30, - "nba_upcoming": 30, - "nfl_live": 30, - "nfl_recent": 30, - "nfl_upcoming": 30, - "ncaa_fb_live": 30, - "ncaa_fb_recent": 30, - "ncaa_fb_upcoming": 30, - "ncaa_baseball_live": 30, - "ncaa_baseball_recent": 30, - "ncaa_baseball_upcoming": 30, - "calendar": 30, - "youtube": 30, - "mlb_live": 30, - "mlb_recent": 30, - "mlb_upcoming": 30, - "milb_live": 30, - "milb_recent": 30, - "milb_upcoming": 30, - "text_display": 10, - "soccer_live": 30, - "soccer_recent": 30, - "soccer_upcoming": 30, - "ncaam_basketball_live": 30, - "ncaam_basketball_recent": 30, - "ncaam_basketball_upcoming": 30, - "music": 30, - "of_the_day": 40 - } - } -} -``` - -**Duration Settings**: -- Each value controls how long (in seconds) that display mode shows -- Higher values = more time for that content -- Total rotation time = sum of all enabled durations - -### System Settings - -```json -{ - "web_display_autostart": true, - "schedule": { - "enabled": true, - "start_time": "07:00", - "end_time": "23:00" - }, - "timezone": "America/Chicago", - "location": { - "city": "Dallas", - "state": "Texas", - "country": "US" - } -} -``` - -**System Settings Explained**: -- **`web_display_autostart`**: Start web interface automatically -- **`schedule`**: Control when display is active -- **`timezone`**: System timezone for accurate times -- **`location`**: Default location for weather and other location-based services - -## Display Manager Configurations - -### Clock Configuration - -```json -{ - "clock": { - "enabled": false, - "format": "%I:%M %p", - "update_interval": 1 - } -} -``` - -**Clock Settings**: -- **`enabled`**: Enable/disable clock display -- **`format`**: Time format string (Python strftime) -- **`update_interval`**: Update frequency in seconds - -**Common Time Formats**: -- `"%I:%M %p"` → `12:34 PM` -- `"%H:%M"` → `14:34` -- `"%I:%M:%S %p"` → `12:34:56 PM` - -### Weather Configuration - -```json -{ - "weather": { - "enabled": false, - "update_interval": 1800, - "units": "imperial", - "display_format": "{temp}°F\n{condition}" - } -} -``` - -**Weather Settings**: -- **`enabled`**: Enable/disable weather display -- **`update_interval`**: Update frequency in seconds (1800 = 30 minutes) -- **`units`**: `"imperial"` (Fahrenheit) or `"metric"` (Celsius) -- **`display_format`**: Custom format string for weather display - -**Weather Display Modes**: -- Current weather with icon -- Hourly forecast (next 24 hours) -- Daily forecast (next 7 days) - -### Stocks Configuration - -```json -{ - "stocks": { - "enabled": false, - "update_interval": 600, - "scroll_speed": 1, - "scroll_delay": 0.01, - "toggle_chart": false, - "symbols": ["ASTS", "SCHD", "INTC", "NVDA", "T", "VOO", "SMCI"] - }, - "crypto": { - "enabled": false, - "update_interval": 600, - "symbols": ["BTC-USD", "ETH-USD"] - } -} -``` - -**Stock Settings**: -- **`enabled`**: Enable/disable stock display -- **`update_interval`**: Update frequency in seconds (600 = 10 minutes) -- **`scroll_speed`**: Pixels per scroll update -- **`scroll_delay`**: Delay between scroll updates -- **`toggle_chart`**: Show/hide mini price charts -- **`symbols`**: Array of stock symbols to display - -**Crypto Settings**: -- **`enabled`**: Enable/disable crypto display -- **`symbols`**: Array of crypto symbols (use `-USD` suffix) - -### Stock News Configuration - -```json -{ - "stock_news": { - "enabled": false, - "update_interval": 3600, - "scroll_speed": 1, - "scroll_delay": 0.01, - "max_headlines_per_symbol": 1, - "headlines_per_rotation": 2 - } -} -``` - -**News Settings**: -- **`enabled`**: Enable/disable news display -- **`update_interval`**: Update frequency in seconds -- **`max_headlines_per_symbol`**: Max headlines per stock -- **`headlines_per_rotation`**: Headlines shown per rotation - -### Music Configuration - -```json -{ - "music": { - "enabled": true, - "preferred_source": "ytm", - "YTM_COMPANION_URL": "http://192.168.86.12:9863", - "POLLING_INTERVAL_SECONDS": 1 - } -} -``` - -**Music Settings**: -- **`enabled`**: Enable/disable music display -- **`preferred_source`**: `"spotify"` or `"ytm"` -- **`YTM_COMPANION_URL`**: YouTube Music companion server URL -- **`POLLING_INTERVAL_SECONDS`**: How often to check for updates - -### Calendar Configuration - -```json -{ - "calendar": { - "enabled": false, - "credentials_file": "credentials.json", - "token_file": "token.pickle", - "update_interval": 3600, - "max_events": 3, - "calendars": ["birthdays"] - } -} -``` - -**Calendar Settings**: -- **`enabled`**: Enable/disable calendar display -- **`credentials_file`**: Google API credentials file -- **`token_file`**: Authentication token file -- **`update_interval`**: Update frequency in seconds -- **`max_events`**: Maximum events to display -- **`calendars`**: Array of calendar IDs to monitor - -## Sports Configurations - -### Common Sports Settings - -All sports managers share these common settings: - -```json -{ - "nhl_scoreboard": { - "enabled": false, - "live_priority": true, - "live_game_duration": 20, - "show_odds": true, - "test_mode": false, - "update_interval_seconds": 3600, - "live_update_interval": 30, - "recent_update_interval": 3600, - "upcoming_update_interval": 3600, - "show_favorite_teams_only": true, - "favorite_teams": ["TB"], - "logo_dir": "assets/sports/nhl_logos", - "show_records": true, - "display_modes": { - "nhl_live": true, - "nhl_recent": true, - "nhl_upcoming": true - } - } -} -``` - -**Common Sports Settings**: -- **`enabled`**: Enable/disable this sport -- **`live_priority`**: Give live games priority over other content -- **`live_game_duration`**: How long to show live games -- **`show_odds`**: Display betting odds (where available) -- **`test_mode`**: Use test data instead of live API -- **`update_interval_seconds`**: How often to fetch new data -- **`live_update_interval`**: How often to update live games -- **`show_favorite_teams_only`**: Only show games for favorite teams -- **`favorite_teams`**: Array of team abbreviations -- **`logo_dir`**: Directory containing team logos -- **`show_records`**: Display team win/loss records -- **`display_modes`**: Enable/disable specific display modes - -### Football-Specific Settings - -NFL and NCAA Football use game-based fetching: - -```json -{ - "nfl_scoreboard": { - "enabled": false, - "recent_games_to_show": 0, - "upcoming_games_to_show": 2, - "favorite_teams": ["TB", "DAL"] - } -} -``` - -**Football Settings**: -- **`recent_games_to_show`**: Number of recent games to display -- **`upcoming_games_to_show`**: Number of upcoming games to display - -### Soccer Configuration - -```json -{ - "soccer_scoreboard": { - "enabled": false, - "recent_game_hours": 168, - "favorite_teams": ["LIV"], - "leagues": ["eng.1", "esp.1", "ger.1", "ita.1", "fra.1", "uefa.champions", "usa.1"] - } -} -``` - -**Soccer Settings**: -- **`recent_game_hours`**: Hours back to show recent games -- **`leagues`**: Array of league codes to monitor - -## Odds Ticker Configuration - -```json -{ - "odds_ticker": { - "enabled": false, - "show_favorite_teams_only": true, - "games_per_favorite_team": 1, - "max_games_per_league": 5, - "show_odds_only": false, - "sort_order": "soonest", - "enabled_leagues": ["nfl", "mlb", "ncaa_fb", "milb"], - "update_interval": 3600, - "scroll_speed": 1, - "scroll_delay": 0.01, - "loop": true, - "future_fetch_days": 50, - "show_channel_logos": true - } -} -``` - -**Odds Ticker Settings**: -- **`enabled`**: Enable/disable odds ticker -- **`show_favorite_teams_only`**: Only show odds for favorite teams -- **`games_per_favorite_team`**: Games per team to show -- **`max_games_per_league`**: Maximum games per league -- **`enabled_leagues`**: Leagues to include in ticker -- **`sort_order`**: `"soonest"` or `"latest"` -- **`future_fetch_days`**: Days ahead to fetch games -- **`show_channel_logos`**: Display broadcast network logos - -## Custom Display Configurations - -### Text Display - -```json -{ - "text_display": { - "enabled": false, - "text": "Subscribe to ChuckBuilds", - "font_path": "assets/fonts/press-start-2p.ttf", - "font_size": 8, - "scroll": true, - "scroll_speed": 40, - "text_color": [255, 0, 0], - "background_color": [0, 0, 0], - "scroll_gap_width": 32 - } -} -``` - -**Text Display Settings**: -- **`enabled`**: Enable/disable text display -- **`text`**: Text to display -- **`font_path`**: Path to TTF font file -- **`font_size`**: Font size in pixels -- **`scroll`**: Enable/disable scrolling -- **`scroll_speed`**: Scroll speed in pixels -- **`text_color`**: RGB color for text -- **`background_color`**: RGB color for background -- **`scroll_gap_width`**: Gap between text repetitions - -### YouTube Display - -```json -{ - "youtube": { - "enabled": false, - "update_interval": 3600 - } -} -``` - -**YouTube Settings**: -- **`enabled`**: Enable/disable YouTube stats -- **`update_interval`**: Update frequency in seconds - -### Of The Day Display - -```json -{ - "of_the_day": { - "enabled": true, - "display_rotate_interval": 20, - "update_interval": 3600, - "subtitle_rotate_interval": 10, - "category_order": ["word_of_the_day", "slovenian_word_of_the_day", "bible_verse_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" - }, - "bible_verse_of_the_day": { - "enabled": true, - "data_file": "of_the_day/bible_verse_of_the_day.json", - "display_name": "Bible Verse of the Day" - } - } - } -} -``` - -**Of The Day Settings**: -- **`enabled`**: Enable/disable of the day display -- **`display_rotate_interval`**: How long to show each category -- **`update_interval`**: Update frequency in seconds -- **`subtitle_rotate_interval`**: How long to show subtitles -- **`category_order`**: Order of categories to display -- **`categories`**: Configuration for each category - -## API Configuration (config_secrets.json) - -### Weather API - -```json -{ - "weather": { - "api_key": "your_openweathermap_api_key" - } -} -``` - -### YouTube API - -```json -{ - "youtube": { - "api_key": "your_youtube_api_key", - "channel_id": "your_channel_id" - } -} -``` - -### Music APIs - -```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" - } -} -``` - -## Configuration Best Practices - -### Performance Optimization - -1. **Update Intervals**: Balance between fresh data and API limits - - Weather: 1800 seconds (30 minutes) - - Stocks: 600 seconds (10 minutes) - - Sports: 3600 seconds (1 hour) - - Music: 1 second (real-time) - -2. **Display Durations**: Balance content visibility - - Live sports: 20-30 seconds - - Weather: 30 seconds - - Stocks: 30-60 seconds - - Clock: 15 seconds - -3. **Favorite Teams**: Reduce API calls by focusing on specific teams - -### Caching Strategy - -```json -{ - "cache_settings": { - "persistent_cache": true, - "cache_directory": "/var/cache/ledmatrix", - "fallback_cache": "/tmp/ledmatrix_cache" - } -} -``` - -### Error Handling - -- Failed API calls use cached data -- Network timeouts are handled gracefully -- Invalid data is filtered out -- Logging provides debugging information - -## Configuration Validation - -### Required Settings - -1. **Hardware Configuration**: Must match your physical setup -2. **API Keys**: Required for enabled services -3. **Location**: Required for weather and timezone -4. **Team Abbreviations**: Must match official team codes - -### Optional Settings - -1. **Display Durations**: Defaults provided if missing -2. **Update Intervals**: Defaults provided if missing -3. **Favorite Teams**: Can be empty for all teams -4. **Custom Text**: Can be any string - -## Configuration Examples - -### Minimal Configuration - -```json -{ - "display": { - "hardware": { - "rows": 32, - "cols": 64, - "chain_length": 2, - "brightness": 90, - "hardware_mapping": "adafruit-hat-pwm" - } - }, - "clock": { - "enabled": true - }, - "weather": { - "enabled": true - } -} -``` - -### Full Sports Configuration - -```json -{ - "nhl_scoreboard": { - "enabled": true, - "favorite_teams": ["TB", "DAL"], - "show_favorite_teams_only": true - }, - "nba_scoreboard": { - "enabled": true, - "favorite_teams": ["DAL"], - "show_favorite_teams_only": true - }, - "nfl_scoreboard": { - "enabled": true, - "favorite_teams": ["TB", "DAL"], - "show_favorite_teams_only": true - }, - "odds_ticker": { - "enabled": true, - "enabled_leagues": ["nfl", "nba", "mlb"] - } -} -``` - -### Financial Focus Configuration - -```json -{ - "stocks": { - "enabled": true, - "symbols": ["AAPL", "MSFT", "GOOGL", "TSLA", "NVDA"], - "update_interval": 300 - }, - "crypto": { - "enabled": true, - "symbols": ["BTC-USD", "ETH-USD", "ADA-USD"] - }, - "stock_news": { - "enabled": true, - "update_interval": 1800 - } -} -``` - -## Troubleshooting Configuration - -### Common Issues - -1. **No Display**: Check hardware configuration -2. **No Data**: Verify API keys and network -3. **Wrong Times**: Check timezone setting -4. **Performance Issues**: Reduce update frequencies - -### Validation Commands - -```bash -# Validate JSON syntax -python3 -m json.tool config/config.json - -# Check configuration loading -python3 -c "from src.config_manager import ConfigManager; c = ConfigManager(); print('Config valid')" -``` - ---- - -*For detailed information about specific display managers, see the [Display Managers](WIKI_DISPLAY_MANAGERS.md) page.* \ No newline at end of file diff --git a/wiki/WIKI_DISPLAY_MANAGERS.md b/wiki/WIKI_DISPLAY_MANAGERS.md deleted file mode 100644 index 5c6a05a4..00000000 --- a/wiki/WIKI_DISPLAY_MANAGERS.md +++ /dev/null @@ -1,501 +0,0 @@ -# Display Managers Guide - -The LEDMatrix system uses a modular architecture where each feature is implemented as a separate "Display Manager". This guide covers all available display managers and their configuration options. - -## Overview - -Each display manager is responsible for: -1. **Data Fetching**: Retrieving data from APIs or local sources -2. **Data Processing**: Transforming raw data into displayable format -3. **Display Rendering**: Creating visual content for the LED matrix -4. **Caching**: Storing data to reduce API calls -5. **Configuration**: Managing settings and preferences - -## Core Display Managers - -### 🕐 Clock Manager (`src/clock.py`) -**Purpose**: Displays current time in various formats - -**Configuration**: -```json -{ - "clock": { - "enabled": true, - "format": "%I:%M %p", - "update_interval": 1 - } -} -``` - -**Features**: -- Real-time clock display -- Configurable time format -- Automatic timezone handling -- Minimal resource usage - -**Display Format**: `12:34 PM` - ---- - -### 🌤️ Weather Manager (`src/weather_manager.py`) -**Purpose**: Displays current weather, hourly forecasts, and daily forecasts - -**Configuration**: -```json -{ - "weather": { - "enabled": true, - "update_interval": 1800, - "units": "imperial", - "display_format": "{temp}°F\n{condition}" - } -} -``` - -**Features**: -- Current weather conditions -- Hourly forecast (next 24 hours) -- Daily forecast (next 7 days) -- Weather icons and animations -- UV index display -- Wind speed and direction -- Humidity and pressure data - -**Display Modes**: -- Current weather with icon -- Hourly forecast with temperature trend -- Daily forecast with high/low temps - ---- - -### 💰 Stock Manager (`src/stock_manager.py`) -**Purpose**: Displays stock prices, crypto prices, and financial data - -**Configuration**: -```json -{ - "stocks": { - "enabled": true, - "update_interval": 600, - "scroll_speed": 1, - "scroll_delay": 0.01, - "toggle_chart": false, - "symbols": ["AAPL", "MSFT", "GOOGL", "TSLA"] - }, - "crypto": { - "enabled": true, - "update_interval": 600, - "symbols": ["BTC-USD", "ETH-USD"] - } -} -``` - -**Features**: -- Real-time stock prices -- Cryptocurrency prices -- Price change indicators (green/red) -- Percentage change display -- Optional mini charts -- Scrolling ticker format -- Company/crypto logos - -**Data Sources**: -- Yahoo Finance API for stocks -- Yahoo Finance API for crypto -- Automatic market hours detection - ---- - -### 📰 Stock News Manager (`src/stock_news_manager.py`) -**Purpose**: Displays financial news headlines for configured stocks - -**Configuration**: -```json -{ - "stock_news": { - "enabled": true, - "update_interval": 3600, - "scroll_speed": 1, - "scroll_delay": 0.01, - "max_headlines_per_symbol": 1, - "headlines_per_rotation": 2 - } -} -``` - -**Features**: -- Financial news headlines -- Stock-specific news filtering -- Scrolling text display -- Configurable headline limits -- Automatic rotation - ---- - -### 🎵 Music Manager (`src/music_manager.py`) -**Purpose**: Displays currently playing music from Spotify or YouTube Music - -**Configuration**: -```json -{ - "music": { - "enabled": true, - "preferred_source": "ytm", - "YTM_COMPANION_URL": "http://192.168.86.12:9863", - "POLLING_INTERVAL_SECONDS": 1 - } -} -``` - -**Features**: -- Spotify integration -- YouTube Music integration -- Album art display -- Song title and artist -- Playback status -- Real-time updates - -**Supported Sources**: -- Spotify (requires API credentials) -- YouTube Music (requires YTMD companion server) - ---- - -### 📅 Calendar Manager (`src/calendar_manager.py`) -**Purpose**: Displays upcoming Google Calendar events - -**Configuration**: -```json -{ - "calendar": { - "enabled": true, - "credentials_file": "credentials.json", - "token_file": "token.pickle", - "update_interval": 3600, - "max_events": 3, - "calendars": ["birthdays"] - } -} -``` - -**Features**: -- Google Calendar integration -- Event date and time display -- Event title (wrapped to fit display) -- Multiple calendar support -- Configurable event limits - ---- - -### 🏈 Sports Managers - -The system includes separate managers for each sports league: - -#### NHL Managers (`src/nhl_managers.py`) -- **NHLLiveManager**: Currently playing games -- **NHLRecentManager**: Completed games (last 48 hours) -- **NHLUpcomingManager**: Scheduled games - -#### NBA Managers (`src/nba_managers.py`) -- **NBALiveManager**: Currently playing games -- **NBARecentManager**: Completed games -- **NBAUpcomingManager**: Scheduled games - -#### MLB Managers (`src/mlb_manager.py`) -- **MLBLiveManager**: Currently playing games -- **MLBRecentManager**: Completed games -- **MLBUpcomingManager**: Scheduled games - -#### NFL Managers (`src/nfl_managers.py`) -- **NFLLiveManager**: Currently playing games -- **NFLRecentManager**: Completed games -- **NFLUpcomingManager**: Scheduled games - -#### NCAA Managers -- **NCAA Football** (`src/ncaa_fb_managers.py`) -- **NCAA Baseball** (`src/ncaa_baseball_managers.py`) -- **NCAA Basketball** (`src/ncaam_basketball_managers.py`) - -#### Soccer Managers (`src/soccer_managers.py`) -- **SoccerLiveManager**: Currently playing games -- **SoccerRecentManager**: Completed games -- **SoccerUpcomingManager**: Scheduled games - -#### MiLB Managers (`src/milb_manager.py`) -- **MiLBLiveManager**: Currently playing games -- **MiLBRecentManager**: Completed games -- **MiLBUpcomingManager**: Scheduled games - -**Common Sports Configuration**: -```json -{ - "nhl_scoreboard": { - "enabled": true, - "live_priority": true, - "live_game_duration": 20, - "show_odds": true, - "test_mode": false, - "update_interval_seconds": 3600, - "live_update_interval": 30, - "show_favorite_teams_only": true, - "favorite_teams": ["TB"], - "logo_dir": "assets/sports/nhl_logos", - "show_records": true, - "display_modes": { - "nhl_live": true, - "nhl_recent": true, - "nhl_upcoming": true - } - } -} -``` - -**Sports Features**: -- Live game scores and status -- Team logos and records -- Game times and venues -- Odds integration (where available) -- Favorite team filtering -- Automatic game switching -- ESPN API integration - ---- - -### 🎲 Odds Ticker Manager (`src/odds_ticker_manager.py`) -**Purpose**: Displays betting odds for upcoming sports games - -**Configuration**: -```json -{ - "odds_ticker": { - "enabled": true, - "show_favorite_teams_only": true, - "games_per_favorite_team": 1, - "max_games_per_league": 5, - "show_odds_only": false, - "sort_order": "soonest", - "enabled_leagues": ["nfl", "mlb", "ncaa_fb", "milb"], - "update_interval": 3600, - "scroll_speed": 1, - "scroll_delay": 0.01, - "loop": true, - "future_fetch_days": 50, - "show_channel_logos": true - } -} -``` - -**Features**: -- Multi-league support (NFL, NBA, MLB, NCAA) -- Spread, money line, and over/under odds -- Team logos display -- Scrolling text format -- Game time display -- ESPN API integration - ---- - -### 🎨 Custom Display Managers - -#### Text Display Manager (`src/text_display.py`) -**Purpose**: Displays custom text messages - -**Configuration**: -```json -{ - "text_display": { - "enabled": true, - "text": "Subscribe to ChuckBuilds", - "font_path": "assets/fonts/press-start-2p.ttf", - "font_size": 8, - "scroll": true, - "scroll_speed": 40, - "text_color": [255, 0, 0], - "background_color": [0, 0, 0], - "scroll_gap_width": 32 - } -} -``` - -**Features**: -- Custom text messages -- Configurable fonts and colors -- Scrolling text support -- Static text display -- Background color options - -#### YouTube Display Manager (`src/youtube_display.py`) -**Purpose**: Displays YouTube channel statistics - -**Configuration**: -```json -{ - "youtube": { - "enabled": true, - "update_interval": 3600 - } -} -``` - -**Features**: -- Subscriber count display -- Video count display -- View count display -- YouTube API integration - -#### Of The Day Manager (`src/of_the_day_manager.py`) -**Purpose**: Displays various "of the day" content - -**Configuration**: -```json -{ - "of_the_day": { - "enabled": true, - "display_rotate_interval": 20, - "update_interval": 3600, - "subtitle_rotate_interval": 10, - "category_order": ["word_of_the_day", "slovenian_word_of_the_day", "bible_verse_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" - }, - "bible_verse_of_the_day": { - "enabled": true, - "data_file": "of_the_day/bible_verse_of_the_day.json", - "display_name": "Bible Verse of the Day" - } - } - } -} -``` - -**Features**: -- Word of the day -- Slovenian word of the day -- Bible verse of the day -- Rotating display categories -- Local JSON data files - ---- - -## Display Manager Architecture - -### Common Interface -All display managers follow a consistent interface: - -```python -class DisplayManager: - def __init__(self, config, display_manager): - # Initialize with configuration and display manager - - def update_data(self): - # Fetch and process new data - - def display(self, force_clear=False): - # Render content to the display - - def is_enabled(self): - # Check if manager is enabled -``` - -### Data Flow -1. **Configuration**: Manager reads settings from `config.json` -2. **Data Fetching**: Retrieves data from APIs or local sources -3. **Caching**: Stores data using `CacheManager` -4. **Processing**: Transforms data into display format -5. **Rendering**: Uses `DisplayManager` to show content -6. **Rotation**: Returns to main display controller - -### Error Handling -- API failures fall back to cached data -- Network timeouts are handled gracefully -- Invalid data is filtered out -- Logging provides debugging information - -## Configuration Best Practices - -### Enable/Disable Managers -```json -{ - "weather": { - "enabled": true // Set to false to disable - } -} -``` - -### Set Display Durations -```json -{ - "display": { - "display_durations": { - "weather": 30, // 30 seconds - "stocks": 60, // 1 minute - "nhl_live": 20 // 20 seconds - } - } -} -``` - -### Configure Update Intervals -```json -{ - "weather": { - "update_interval": 1800 // Update every 30 minutes - } -} -``` - -### Set Favorite Teams -```json -{ - "nhl_scoreboard": { - "show_favorite_teams_only": true, - "favorite_teams": ["TB", "DAL"] - } -} -``` - -## Performance Considerations - -### API Rate Limits -- Weather: 1000 calls/day (OpenWeatherMap) -- Stocks: 2000 calls/hour (Yahoo Finance) -- Sports: ESPN API (no documented limits) -- Music: Spotify/YouTube Music APIs - -### Caching Strategy -- Data cached based on `update_interval` -- Cache persists across restarts -- Failed API calls use cached data -- Automatic cache invalidation - -### Resource Usage -- Each manager runs independently -- Disabled managers use no resources -- Memory usage scales with enabled features -- CPU usage minimal during idle periods - -## Troubleshooting Display Managers - -### Common Issues -1. **No Data Displayed**: Check API keys and network connectivity -2. **Outdated Data**: Verify update intervals and cache settings -3. **Display Errors**: Check font files and display configuration -4. **Performance Issues**: Reduce update frequency or disable unused managers - -### Debugging -- Enable logging for specific managers -- Check cache directory for data files -- Verify API credentials in `config_secrets.json` -- Test individual managers in isolation - ---- - -*For detailed technical information about each display manager, see the [Display Manager Details](WIKI_DISPLAY_MANAGER_DETAILS.md) page.* \ No newline at end of file diff --git a/wiki/WIKI_HOME.md b/wiki/WIKI_HOME.md deleted file mode 100644 index 1e6ccd8f..00000000 --- a/wiki/WIKI_HOME.md +++ /dev/null @@ -1,98 +0,0 @@ -# LEDMatrix Wiki - -Welcome to the LEDMatrix Wiki! This comprehensive documentation will help you understand, configure, and customize your LED matrix display system. - -## 🏠 [Home](WIKI_HOME.md) - You are here -The main wiki page with overview and navigation. - -## 📋 [Quick Start Guide](WIKI_QUICK_START.md) -Get your LEDMatrix up and running in minutes with this step-by-step guide. - -## 🏗️ [System Architecture](WIKI_ARCHITECTURE.md) -Understand how the LEDMatrix system is organized and how all components work together. - -## ⚙️ [Configuration Guide](WIKI_CONFIGURATION.md) -Complete guide to configuring all aspects of your LEDMatrix system. - -## 🎯 [Display Managers](WIKI_DISPLAY_MANAGERS.md) -Detailed documentation for each display manager and their configuration options. - -## 🌐 Web Interface -- [Web Interface Installation](WEB_INTERFACE_INSTALLATION.md) -- [Web Interface V2 Enhancements](WEB_INTERFACE_V2_ENHANCED_SUMMARY.md) - -## 📰 News & Feeds -- [Sports News Manager](NEWS_MANAGER_README.md) -- [Add Custom RSS Feeds](CUSTOM_FEEDS_GUIDE.md) - -## ⏱️ Dynamic Duration -- [Feature Overview](dynamic_duration.md) -- [Implementation Guide](DYNAMIC_DURATION_GUIDE.md) -- [Stocks Implementation Details](DYNAMIC_DURATION_STOCKS_IMPLEMENTATION.md) - -## 🗄️ Caching -- [Cache Strategy](CACHE_STRATEGY.md) -- [Cache Management](cache_management.md) - -## 🧩 Troubleshooting -- [General Troubleshooting](WIKI_TROUBLESHOOTING.md) -- [MiLB Troubleshooting](MILB_TROUBLESHOOTING.md) - -## 🚀 Install & Quick Start -- [Installation Guide](INSTALLATION_GUIDE.md) -- [Quick Start](WIKI_QUICK_START.md) - ---- - -## Quick Navigation - -### Core Features -- [Display Managers](WIKI_DISPLAY_MANAGERS.md) - All display modules -- [Configuration](WIKI_CONFIGURATION.md) - Complete config guide -- [Hardware Setup](WIKI_HARDWARE.md) - Physical setup - -### Integrations -- [Sports](WIKI_SPORTS.md) - All sports leagues -- [Music](WIKI_MUSIC.md) - Spotify & YouTube Music -- [Weather](WIKI_WEATHER.md) - Weather display -- [Financial](WIKI_FINANCIAL.md) - Stocks & crypto -- [Calendar](WIKI_CALENDAR.md) - Google Calendar - -### Technical -- [Architecture](WIKI_ARCHITECTURE.md) - System design -- [API Reference](WIKI_API_REFERENCE.md) - Technical docs -- [Development](WIKI_DEVELOPMENT.md) - Extending the system - ---- - -## About LEDMatrix - -LEDMatrix is a comprehensive 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. - -### Key Features -- **Modular Design**: Each feature is a separate manager that can be enabled/disabled -- **Real-time Updates**: Live data from APIs with intelligent caching -- **Multiple Sports**: NHL, NBA, MLB, NFL, NCAA, Soccer, and more -- **Financial Data**: Stock ticker, crypto prices, and financial news -- **Weather**: Current conditions, hourly and daily forecasts -- **Music**: Spotify and YouTube Music integration -- **Custom Content**: Text display, YouTube stats, and more -- **Scheduling**: Configurable display rotation and timing -- **Caching**: Intelligent caching to reduce API calls - -### System Requirements -- Raspberry Pi 3B+ or 4 (NOT Pi 5) -- Adafruit RGB Matrix Bonnet/HAT -- 2x LED Matrix panels (64x32) -- 5V 4A DC Power Supply -- Internet connection for API access - -### Quick Links -- [YouTube Setup Video](https://www.youtube.com/watch?v=_HaqfJy1Y54) -- [Project Website](https://www.chuck-builds.com/led-matrix/) -- [GitHub Repository](https://github.com/ChuckBuilds/LEDMatrix) -- [Discord Community](https://discord.com/invite/uW36dVAtcT) - ---- - -*This wiki is designed to help you get the most out of your LEDMatrix system. Each page contains detailed information, configuration examples, and troubleshooting tips.* \ No newline at end of file diff --git a/wiki/WIKI_QUICK_START.md b/wiki/WIKI_QUICK_START.md deleted file mode 100644 index 0dc869f1..00000000 --- a/wiki/WIKI_QUICK_START.md +++ /dev/null @@ -1,407 +0,0 @@ -# Quick Start Guide - -Get your LEDMatrix system up and running in minutes! This guide covers the essential steps to get your display working. - -## Fast Path (Recommended) - -If this is a brand new install, you can run the all-in-one installer and then use the web UI: - -```bash -chmod +x first_time_install.sh -sudo ./first_time_install.sh -``` - -Then open the web UI at: - -``` -http://your-pi-ip:5001 -``` - -The steps below document the manual process for advanced users. - -## Prerequisites - -### Hardware Requirements -- Raspberry Pi 3B+ or 4 (NOT Pi 5) -- Adafruit RGB Matrix Bonnet/HAT -- 2x LED Matrix panels (64x32 each) -- 5V 4A DC Power Supply -- Micro SD card (8GB or larger) - -### Software Requirements -- Internet connection -- SSH access to Raspberry Pi -- Basic command line knowledge - -## Step 1: Prepare Raspberry Pi - -### 1.1 Create Raspberry Pi Image -1. Download [Raspberry Pi Imager](https://www.raspberrypi.com/software/) -2. Choose your Raspberry Pi model -3. Select "Raspbian OS Lite (64-bit)" -4. Choose your micro SD card -5. Click "Next" then "Edit Settings" - -### 1.2 Configure OS Settings -1. **General Tab**: - - Set hostname: `ledpi` - - Enable SSH - - Set username and password - - Configure WiFi - -2. **Services Tab**: - - Enable SSH - - Use password authentication - -3. Click "Save" and write the image - -### 1.3 Boot and Connect -1. Insert SD card into Raspberry Pi -2. Power on and wait for boot -3. Connect via SSH: - ```bash - ssh ledpi@ledpi - ``` - -## Step 2: Install LEDMatrix - -### 2.1 Update System -```bash -sudo apt update && sudo apt upgrade -y -sudo apt install -y git python3-pip cython3 build-essential python3-dev python3-pillow scons -``` - -### 2.2 Clone Repository -```bash -git clone https://github.com/ChuckBuilds/LEDMatrix.git -cd LEDMatrix -``` - - ### 2.3 First-time installation (recommended) - -```bash -chmod +x first_time_install.sh -sudo ./first_time_install.sh -``` - - -### Or manually - -### 2.3 Install Dependencies -```bash -sudo pip3 install --break-system-packages -r requirements.txt -``` - -### 2.4 Install RGB Matrix Library -```bash -cd rpi-rgb-led-matrix-master -sudo make build-python PYTHON=$(which python3) -cd bindings/python -sudo python3 setup.py install -``` - -### 2.5 Test Installation -```bash -python3 -c 'from rgbmatrix import RGBMatrix, RGBMatrixOptions; print("Success!")' -``` - -## Step 3: Configure Hardware - -### 3.1 Remove Audio Services -```bash -sudo apt-get remove bluez bluez-firmware pi-bluetooth triggerhappy pigpio -``` - -### 3.2 Blacklist Sound Module -```bash -cat <> /var/log/ledmatrix_cache.log -``` - -### Conditional Cache Clearing - -```bash -#!/bin/bash -# Only clear cache if it's older than 24 hours - -# Check cache age and clear if needed -# (This would require additional logic to check cache timestamps) -``` - -## Related Documentation - -- [Configuration Guide](../config/README.md) -- [Troubleshooting Guide](troubleshooting.md) -- [API Integration](api_integration.md) -- [Display Controller](display_controller.md) diff --git a/wiki/dynamic_duration.md b/wiki/dynamic_duration.md deleted file mode 100644 index dc5ff3e6..00000000 --- a/wiki/dynamic_duration.md +++ /dev/null @@ -1,243 +0,0 @@ -# Dynamic Duration Implementation - -## Overview - -Dynamic Duration is a feature that calculates the exact time needed to display scrolling content (like news headlines or stock tickers) based on the content's length, scroll speed, and display characteristics, rather than using a fixed duration. This ensures optimal viewing time for users while maintaining smooth content flow. - -## How It Works - -The dynamic duration calculation considers several factors: - -1. **Content Width**: The total width of the text/image content to be displayed -2. **Display Width**: The width of the LED matrix display -3. **Scroll Speed**: How many pixels the content moves per frame -4. **Scroll Delay**: Time between each frame update -5. **Buffer Time**: Additional time added for smooth cycling (configurable percentage) - -### Calculation Formula - -``` -Total Scroll Distance = Display Width + Content Width -Frames Needed = Total Scroll Distance / Scroll Speed -Base Time = Frames Needed × Scroll Delay -Buffer Time = Base Time × Duration Buffer -Calculated Duration = Base Time + Buffer Time -``` - -The final duration is then capped between the configured minimum and maximum values. - -## Configuration - -Add the following settings to your `config/config.json` file: - -### For Stocks (`stocks` section) -```json -{ - "stocks": { - "dynamic_duration": true, - "min_duration": 30, - "max_duration": 300, - "duration_buffer": 0.1, - // ... other existing settings - } -} -``` - -### For Stock News (`stock_news` section) -```json -{ - "stock_news": { - "dynamic_duration": true, - "min_duration": 30, - "max_duration": 300, - "duration_buffer": 0.1, - // ... other existing settings - } -} -``` - -### For Odds Ticker (`odds_ticker` section) -```json -{ - "odds_ticker": { - "dynamic_duration": true, - "min_duration": 30, - "max_duration": 300, - "duration_buffer": 0.1, - // ... other existing settings - } -} -``` - -### Configuration Options - -- **`dynamic_duration`** (boolean): Enable/disable dynamic duration calculation -- **`min_duration`** (seconds): Minimum display time regardless of content length -- **`max_duration`** (seconds): Maximum display time to prevent excessive delays -- **`duration_buffer`** (decimal): Additional time as a percentage of calculated time (e.g., 0.1 = 10% extra) - -## Implementation Details - -### StockManager Updates - -The `StockManager` class has been enhanced with dynamic duration capabilities: - -```python -# In __init__ method -self.dynamic_duration_enabled = self.stocks_config.get('dynamic_duration', True) -self.min_duration = self.stocks_config.get('min_duration', 30) -self.max_duration = self.stocks_config.get('max_duration', 300) -self.duration_buffer = self.stocks_config.get('duration_buffer', 0.1) -self.dynamic_duration = 60 # Default duration in seconds -self.total_scroll_width = 0 # Track total width for calculation -``` - -#### New Methods - -**`calculate_dynamic_duration()`** -- Calculates the exact time needed to display all stock information -- Considers display width, content width, scroll speed, and delays -- Applies min/max duration limits -- Includes detailed debug logging - -**`get_dynamic_duration()`** -- Returns the calculated dynamic duration for external use -- Used by the DisplayController to determine display timing - -### StockNewsManager Updates - -Similar enhancements have been applied to the `StockNewsManager`: - -```python -# In __init__ method -self.dynamic_duration_enabled = self.stock_news_config.get('dynamic_duration', True) -self.min_duration = self.stock_news_config.get('min_duration', 30) -self.max_duration = self.stock_news_config.get('max_duration', 300) -self.duration_buffer = self.stock_news_config.get('duration_buffer', 0.1) -self.dynamic_duration = 60 # Default duration in seconds -self.total_scroll_width = 0 # Track total width for calculation -``` - -#### New Methods - -**`calculate_dynamic_duration()`** -- Calculates display time for news headlines -- Uses the same logic as StockManager but with stock news configuration -- Handles text width calculation from cached images - -**`get_dynamic_duration()`** -- Returns the calculated duration for news display - -### OddsTickerManager Updates - -The `OddsTickerManager` class has been enhanced with dynamic duration capabilities: - -```python -# In __init__ method -self.dynamic_duration_enabled = self.odds_ticker_config.get('dynamic_duration', True) -self.min_duration = self.odds_ticker_config.get('min_duration', 30) -self.max_duration = self.odds_ticker_config.get('max_duration', 300) -self.duration_buffer = self.odds_ticker_config.get('duration_buffer', 0.1) -self.dynamic_duration = 60 # Default duration in seconds -self.total_scroll_width = 0 # Track total width for calculation -``` - -#### New Methods - -**`calculate_dynamic_duration()`** -- Calculates display time for odds ticker content -- Uses the same logic as other managers but with odds ticker configuration -- Handles width calculation from the composite ticker image - -**`get_dynamic_duration()`** -- Returns the calculated duration for odds ticker display - -### DisplayController Integration - -The `DisplayController` has been updated to use dynamic durations: - -```python -# In get_current_duration() method -# Handle dynamic duration for stocks -if mode_key == 'stocks' and self.stocks: - try: - dynamic_duration = self.stocks.get_dynamic_duration() - logger.info(f"Using dynamic duration for stocks: {dynamic_duration} seconds") - return dynamic_duration - except Exception as e: - logger.error(f"Error getting dynamic duration for stocks: {e}") - return self.display_durations.get(mode_key, 60) - -# Handle dynamic duration for stock_news -if mode_key == 'stock_news' and self.news: - try: - dynamic_duration = self.news.get_dynamic_duration() - logger.info(f"Using dynamic duration for stock_news: {dynamic_duration} seconds") - return dynamic_duration - except Exception as e: - logger.error(f"Error getting dynamic duration for stock_news: {e}") - return self.display_durations.get(mode_key, 60) - -# Handle dynamic duration for odds_ticker -if mode_key == 'odds_ticker' and self.odds_ticker: - try: - dynamic_duration = self.odds_ticker.get_dynamic_duration() - logger.info(f"Using dynamic duration for odds_ticker: {dynamic_duration} seconds") - return dynamic_duration - except Exception as e: - logger.error(f"Error getting dynamic duration for odds_ticker: {e}") - return self.display_durations.get(mode_key, 60) - -## Benefits - -1. **Optimal Viewing Time**: Content is displayed for exactly the right amount of time -2. **Smooth Transitions**: Buffer time ensures smooth cycling between content -3. **Configurable Limits**: Min/max durations prevent too short or too long displays -4. **Consistent Experience**: All scrolling content uses the same timing logic -5. **Debug Visibility**: Detailed logging helps troubleshoot timing issues - -## Testing - -The implementation includes comprehensive logging to verify calculations: - -``` -Stock dynamic duration calculation: - Display width: 128px - Text width: 450px - Total scroll distance: 578px - Frames needed: 578.0 - Base time: 5.78s - Buffer time: 0.58s (10%) - Calculated duration: 6s - Final duration: 30s (capped to minimum) -``` - -## Troubleshooting - -### Duration Always at Minimum -If your calculated duration is always capped at the minimum value, check: -- Scroll speed settings (higher speed = shorter duration) -- Scroll delay settings (lower delay = shorter duration) -- Content width calculation -- Display width configuration - -### Duration Too Long -If content displays for too long: -- Reduce the `duration_buffer` percentage -- Increase `scroll_speed` or decrease `scroll_delay` -- Lower the `max_duration` limit - -### Dynamic Duration Not Working -If dynamic duration isn't being used: -- Verify `dynamic_duration: true` in configuration -- Check that the manager instances are properly initialized -- Review error logs for calculation failures - -## Related Files - -- `config/config.json` - Configuration settings -- `src/stock_manager.py` - Stock display with dynamic duration -- `src/stock_news_manager.py` - Stock news with dynamic duration -- `src/odds_ticker_manager.py` - Odds ticker with dynamic duration -- `src/display_controller.py` - Integration and duration management -- `src/news_manager.py` - Original implementation reference