diff --git a/.cursor/rules/coding-standards.mdc b/.cursor/rules/coding-standards.mdc new file mode 100644 index 00000000..5abeb94e --- /dev/null +++ b/.cursor/rules/coding-standards.mdc @@ -0,0 +1,38 @@ +--- +globs: *.py +--- + +# Python Coding Standards + +## Code Quality Principles +- **Simplicity First**: Prefer clear, readable code over clever optimizations +- **Explicit over Implicit**: Make intentions clear through naming and structure +- **Fail Fast**: Validate inputs and handle errors early +- **Documentation**: Use docstrings for classes and complex functions + +## Naming Conventions +- **Classes**: PascalCase (e.g., `NHLRecentManager`) +- **Functions/Variables**: snake_case (e.g., `fetch_game_data`) +- **Constants**: UPPER_SNAKE_CASE (e.g., `ESPN_NHL_SCOREBOARD_URL`) +- **Private methods**: Leading underscore (e.g., `_fetch_data`) + +## Error Handling +- **Logging**: Use structured logging with context (e.g., `[NHL Recent]`) +- **Exceptions**: Catch specific exceptions, not bare `except:` +- **User-friendly messages**: Explain what went wrong and potential solutions +- **Graceful degradation**: Continue operation when non-critical features fail + +## Manager Pattern +All sports managers should follow this structure: +```python +class BaseManager: + def __init__(self, config, display_manager, cache_manager) + def update(self) # Fetch and process data + def display(self, force_clear=False) # Render to display +``` + +## Configuration Management +- **Type hints**: Use for function parameters and return values +- **Configuration validation**: Check required fields on initialization +- **Default values**: Provide sensible defaults in code, not config +- **Environment awareness**: Handle different deployment contexts \ No newline at end of file diff --git a/.cursor/rules/configuration-management.mdc b/.cursor/rules/configuration-management.mdc new file mode 100644 index 00000000..37f68300 --- /dev/null +++ b/.cursor/rules/configuration-management.mdc @@ -0,0 +1,42 @@ +--- +globs: config/*.json,src/*.py +--- + +# Configuration Management + +## Configuration Structure +- **Main config**: [config/config.json](mdc:config/config.json) - Primary configuration +- **Secrets**: [config/config_secrets.json](mdc:config/config_secrets.json) - API keys and sensitive data +- **Templates**: [config/config.template.json](mdc:config/config.template.json) - Default values + +## Configuration Principles +- **Validation**: Check required fields and data types on startup +- **Defaults**: Provide sensible defaults in code, not just config +- **Environment awareness**: Handle development vs production differences +- **Security**: Never commit secrets to version control + +## Manager Configuration Pattern +```python +def __init__(self, config, display_manager, cache_manager): + self.mode_config = config.get("sport_scoreboard", {}) + self.favorite_teams = self.mode_config.get("favorite_teams", []) + self.show_favorite_only = self.mode_config.get("show_favorite_teams_only", False) +``` + +## Required Configuration Sections +- **Display settings**: Update intervals, display durations +- **API settings**: Timeouts, retry logic, rate limiting +- **Background service**: Threading, caching, priority settings +- **Team preferences**: Favorite teams, filtering options + +## Configuration Validation +- **Type checking**: Ensure numeric values are numbers, lists are lists +- **Range validation**: Check that intervals are reasonable +- **Dependency checking**: Verify required services are available +- **Fallback values**: Provide defaults when config is missing or invalid + +## Best Practices +- **Documentation**: Comment complex configuration options +- **Examples**: Provide working examples in templates +- **Migration**: Handle configuration changes between versions +- **Testing**: Validate configuration in test environments \ No newline at end of file diff --git a/.cursor/rules/error-handling-logging.mdc b/.cursor/rules/error-handling-logging.mdc new file mode 100644 index 00000000..0bf404ee --- /dev/null +++ b/.cursor/rules/error-handling-logging.mdc @@ -0,0 +1,50 @@ +--- +globs: src/*.py +--- + +# Error Handling and Logging + +## Logging Standards +- **Structured prefixes**: Use consistent tags like `[NHL Recent]`, `[NFL Live]` +- **Context information**: Include relevant details (team names, game status, dates) +- **Appropriate levels**: + - `info`: Normal operations and status updates + - `debug`: Detailed information for troubleshooting + - `warning`: Non-critical issues that should be noted + - `error`: Problems that need attention + +## Error Handling Patterns +```python +try: + data = self._fetch_data() + if not data or 'events' not in data: + self.logger.warning("[Manager] No events found in API response") + return +except requests.exceptions.RequestException as e: + self.logger.error(f"[Manager] API error: {e}") + return None +``` + +## User-Friendly Messages +- **Explain the situation**: "No games available during off-season" +- **Provide context**: "NHL season typically runs October-June" +- **Suggest solutions**: "Check back when season starts" +- **Distinguish issues**: API problems vs no data vs filtering results + +## Graceful Degradation +- **Fallback content**: Show alternative games when favorites unavailable +- **Cached data**: Use cached data when API fails +- **Service continuity**: Continue operation when non-critical features fail +- **Clear communication**: Explain what's happening to users + +## Debugging Support +- **Comprehensive logging**: Log API responses, filtering results, display updates +- **State tracking**: Log current state and transitions +- **Performance monitoring**: Track timing and resource usage +- **Error context**: Include stack traces for debugging + +## Off-Season Awareness +- **Seasonal messaging**: Different messages for different times of year +- **Helpful context**: Explain why no games are available +- **Future planning**: Mention when season starts +- **Realistic expectations**: Set appropriate expectations during off-season \ No newline at end of file diff --git a/.cursor/rules/git-workflow.mdc b/.cursor/rules/git-workflow.mdc new file mode 100644 index 00000000..c28c603a --- /dev/null +++ b/.cursor/rules/git-workflow.mdc @@ -0,0 +1,51 @@ +--- +alwaysApply: true +--- + +# Git Workflow and Branching + +## Branch Naming Conventions +- **Features**: `feature/description-of-feature` (e.g., `feature/weather-forecast-improvements`) +- **Bug fixes**: `fix/description-of-bug` (e.g., `fix/nhl-manager-improvements`) +- **Hotfixes**: `hotfix/critical-issue-description` +- **Refactoring**: `refactor/description-of-refactor` + +## Commit Message Format +``` +type(scope): description + +[optional body] + +[optional footer] +``` + +**Types**: feat, fix, docs, style, refactor, test, chore +**Examples**: +- `feat(nhl): Add enhanced logging for data visibility` +- `fix(display): Resolve rendering performance issue` +- `docs(api): Update ESPN API integration guide` + +## Pull Request Guidelines +- **Self-review**: Review your own PR before requesting review +- **Testing**: Test thoroughly on Raspberry Pi hardware +- **Documentation**: Update relevant documentation if needed +- **Clean history**: Squash commits if necessary for clean history + +## Code Review Checklist +- **Code Quality**: Proper error handling, logging, type hints +- **Architecture**: Follows project patterns, doesn't break existing functionality +- **Performance**: No negative impact on display performance +- **Testing**: Works on Raspberry Pi hardware +- **Documentation**: Comments added for complex logic + +## Merge Strategies +- **Squash and Merge**: Preferred for feature branches and bug fixes +- **Merge Commit**: For complex features with multiple logical commits +- **Rebase and Merge**: For simple, single-commit changes + +## Best Practices +- **Keep branches small and focused** +- **Commit frequently with meaningful messages** +- **Update branch regularly with main** +- **Test changes incrementally** +- **Delete feature branches after merge** \ No newline at end of file diff --git a/.cursor/rules/project-structure.mdc b/.cursor/rules/project-structure.mdc new file mode 100644 index 00000000..c9878a27 --- /dev/null +++ b/.cursor/rules/project-structure.mdc @@ -0,0 +1,23 @@ +--- +alwaysApply: true +--- + +# LEDMatrix Project Structure + +## Core Architecture +- **Main entry point**: [run.py](mdc:run.py) - Primary application launcher +- **Configuration**: [config/config.json](mdc:config/config.json) - Main configuration file +- **Display management**: [src/display_controller.py](mdc:src/display_controller.py) - Core display logic +- **Web interface**: [web_interface_v2.py](mdc:web_interface_v2.py) - Modern web UI + +## Source Code Organization +- **Managers**: [src/](mdc:src/) - All sports/weather/stock managers +- **Assets**: [assets/](mdc:assets/) - Logos, fonts, and static resources +- **Tests**: [test/](mdc:test/) - Unit and integration tests +- **Documentation**: [LEDMatrix.wiki/](mdc:LEDMatrix.wiki/) - Comprehensive guides + +## Key Design Principles +- **Single Responsibility**: Each manager handles one sport/domain +- **Consistent Patterns**: All managers follow similar structure +- **Configuration-Driven**: Behavior controlled via [config/config.json](mdc:config/config.json) +- **Raspberry Pi Focus**: Optimized for Pi hardware, not Windows development \ No newline at end of file diff --git a/.cursor/rules/raspberry-pi-development.mdc b/.cursor/rules/raspberry-pi-development.mdc new file mode 100644 index 00000000..829b7591 --- /dev/null +++ b/.cursor/rules/raspberry-pi-development.mdc @@ -0,0 +1,41 @@ +--- +alwaysApply: true +--- + +# Raspberry Pi Development Guidelines + +## Hardware Constraints +- **Pi-only execution**: Code must run on Raspberry Pi, not Windows development machine +- **LED matrix library**: Uses [rpi-rgb-led-matrix-master/](mdc:rpi-rgb-led-matrix-master/) for hardware control +- **Memory limitations**: Optimize for Pi's limited RAM +- **Performance**: Consider Pi's CPU capabilities in design + +## Development Workflow +- **Local development**: Write and test code on Windows +- **Pi deployment**: Deploy and test on actual Pi hardware +- **SSH access**: Use SSH for Pi-based testing and debugging +- **Service management**: Use systemd services for production deployment + +## Testing Strategy +- **Unit tests**: Test logic without hardware dependencies +- **Integration tests**: Test with mock display managers +- **Hardware tests**: Validate on actual Pi with LED matrix +- **Performance tests**: Monitor memory and CPU usage + +## Deployment Considerations +- **Service files**: [ledmatrix.service](mdc:ledmatrix.service), [ledmatrix-web.service](mdc:ledmatrix-web.service) +- **Installation scripts**: [first_time_install.sh](mdc:first_time_install.sh), [install_service.sh](mdc:install_service.sh) +- **Dependencies**: [requirements.txt](mdc:requirements.txt) for Pi environment +- **Permissions**: Handle file permissions for Pi user + +## Performance Optimization +- **Caching**: Use [src/cache_manager.py](mdc:src/cache_manager.py) for data persistence +- **Background services**: Non-blocking data fetching +- **Memory management**: Clean up resources regularly +- **Display optimization**: Minimize unnecessary redraws + +## Debugging on Pi +- **Logging**: Comprehensive logging for remote debugging +- **Error reporting**: Clear error messages for troubleshooting +- **Status monitoring**: Health checks and status reporting +- **Remote access**: Web interface for configuration and monitoring \ No newline at end of file diff --git a/.cursor/rules/sports-managers.mdc b/.cursor/rules/sports-managers.mdc new file mode 100644 index 00000000..fe6c6fc8 --- /dev/null +++ b/.cursor/rules/sports-managers.mdc @@ -0,0 +1,42 @@ +--- +globs: src/*_managers.py +--- + +# Sports Manager Development + +## Manager Architecture +All sports managers inherit from base classes and follow consistent patterns: +- **Base classes**: [src/nhl_managers.py](mdc:src/nhl_managers.py), [src/nfl_managers.py](mdc:src/nfl_managers.py) +- **Common functionality**: Data fetching, caching, display rendering +- **Configuration-driven**: Behavior controlled via config sections + +## Required Methods +```python +def __init__(self, config, display_manager, cache_manager) +def update(self) # Fetch fresh data +def display(self, force_clear=False) # Render current data +``` + +## Data Flow Pattern +1. **Fetch**: Get data from API (with caching) +2. **Process**: Extract relevant game information +3. **Filter**: Apply favorite team preferences +4. **Display**: Render to LED matrix + +## Logging Standards +- **Structured prefixes**: `[NHL Recent]`, `[NFL Live]`, etc. +- **Context information**: Include team names, game status, dates +- **Debug levels**: Use appropriate log levels (info, debug, warning, error) +- **User-friendly messages**: Explain what's happening and why + +## Error Handling +- **API failures**: Log and continue with cached data if available +- **No data scenarios**: Distinguish between API issues vs no games available +- **Off-season awareness**: Provide helpful context during non-active periods +- **Fallback behavior**: Show alternative content when preferred content unavailable + +## Configuration Integration +- **Required settings**: Validate on initialization +- **Optional settings**: Provide sensible defaults +- **Background service**: Use for non-blocking data fetching +- **Caching strategy**: Implement intelligent cache management \ No newline at end of file diff --git a/.cursor/rules/testing-standards.mdc b/.cursor/rules/testing-standards.mdc new file mode 100644 index 00000000..274b76ef --- /dev/null +++ b/.cursor/rules/testing-standards.mdc @@ -0,0 +1,51 @@ +--- +globs: test/*.py,src/*.py +--- + +# Testing Standards + +## Test Organization +- **Test directory**: [test/](mdc:test/) - All test files +- **Unit tests**: Test individual components in isolation +- **Integration tests**: Test component interactions +- **Hardware tests**: Validate on Raspberry Pi with actual LED matrix + +## Testing Principles +- **Test behavior, not implementation**: Focus on what the code does, not how +- **Mock external dependencies**: Use mocks for APIs, display managers, cache +- **Test edge cases**: Empty data, API failures, configuration errors +- **Pi-specific testing**: Validate hardware integration + +## Test Structure +```python +def test_manager_initialization(): + """Test that manager initializes with valid config""" + config = {"sport_scoreboard": {"enabled": True}} + manager = ManagerClass(config, mock_display, mock_cache) + assert manager.enabled == True + +def test_api_failure_handling(): + """Test graceful handling of API failures""" + # Test that system continues when API fails + # Verify fallback to cached data + # Check appropriate error logging +``` + +## Mock Patterns +- **Display Manager**: Mock for testing without hardware +- **Cache Manager**: Mock for testing data persistence +- **API responses**: Mock for consistent test data +- **Configuration**: Use test-specific configs + +## Test Categories +- **Unit tests**: Individual manager methods +- **Integration tests**: Manager interactions with services +- **Configuration tests**: Validate config loading and validation +- **Error handling tests**: API failures, invalid data, edge cases + +## Testing Best Practices +- **Descriptive names**: Test names should explain what they test +- **Single responsibility**: Each test should verify one thing +- **Independent tests**: Tests should not depend on each other +- **Clean setup/teardown**: Reset state between tests +- **Pi compatibility**: Ensure tests work in Pi environment \ No newline at end of file diff --git a/LEDMatrix.wiki b/LEDMatrix.wiki index a01c72e1..fbd8d89a 160000 --- a/LEDMatrix.wiki +++ b/LEDMatrix.wiki @@ -1 +1 @@ -Subproject commit a01c72e156b46c08a5ef1c67db79acd73300a6f7 +Subproject commit fbd8d89a186e5757d1785737b0ee4c03ad442dbf diff --git a/clear_nhl_cache.py b/clear_nhl_cache.py new file mode 100644 index 00000000..d5b890ea --- /dev/null +++ b/clear_nhl_cache.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +""" +Script to clear NHL cache so managers will fetch fresh data. +""" + +import sys +import os +import json +from datetime import datetime + +# Add the src directory to the path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src')) + +def clear_nhl_cache(): + """Clear NHL cache to force fresh data fetch.""" + print("Clearing NHL cache...") + + try: + from cache_manager import CacheManager + + # Create cache manager + cache_manager = CacheManager() + + # Clear NHL cache for current season + now = datetime.now() + season_year = now.year + if now.month < 9: + season_year = now.year - 1 + + cache_key = f"nhl_api_data_{season_year}" + print(f"Clearing cache key: {cache_key}") + + # Clear the cache + cache_manager.clear_cache(cache_key) + print(f"Successfully cleared cache for {cache_key}") + + # Also clear any other NHL-related cache keys + nhl_keys = [ + f"nhl_api_data_{season_year}", + f"nhl_api_data_{season_year-1}", + f"nhl_api_data_{season_year+1}", + "nhl_live_games", + "nhl_recent_games", + "nhl_upcoming_games" + ] + + for key in nhl_keys: + try: + cache_manager.clear_cache(key) + print(f"Cleared cache key: {key}") + except: + pass # Key might not exist + + print("NHL cache cleared successfully!") + print("NHL managers will now fetch fresh data from ESPN API.") + + except ImportError as e: + print(f"Could not import cache manager: {e}") + print("This script needs to be run on the Raspberry Pi where the cache manager is available.") + except Exception as e: + print(f"Error clearing cache: {e}") + +def main(): + """Main function.""" + print("=" * 50) + print("NHL Cache Clearer") + print("=" * 50) + + clear_nhl_cache() + + print("\n" + "=" * 50) + print("Cache clearing complete!") + print("=" * 50) + +if __name__ == "__main__": + main() diff --git a/fix_nhl_cache.sh b/fix_nhl_cache.sh new file mode 100644 index 00000000..ce84514a --- /dev/null +++ b/fix_nhl_cache.sh @@ -0,0 +1,21 @@ +#!/bin/bash +""" +Script to fix NHL cache issues on Raspberry Pi. +This will clear the NHL cache and restart the display service. +""" + +echo "==========================================" +echo "Fixing NHL Cache Issues" +echo "==========================================" + +# Clear NHL cache +echo "Clearing NHL cache..." +python3 clear_nhl_cache.py + +# Restart the display service to force fresh data fetch +echo "Restarting display service..." +sudo systemctl restart ledmatrix.service + +echo "NHL cache cleared and service restarted!" +echo "NHL managers should now fetch fresh data from ESPN API." +echo "Check the logs to see if NHL games are now being displayed." diff --git a/test/test_nhl_manager_debug.py b/test/test_nhl_manager_debug.py new file mode 100644 index 00000000..d09c18e1 --- /dev/null +++ b/test/test_nhl_manager_debug.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +""" +Test script to debug NHL manager data fetching issues. +This will help us understand why NHL managers aren't finding games. +""" + +import sys +import os +from datetime import datetime, timedelta +import pytz + +# Add the src directory to the path so we can import the managers +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) + +def test_nhl_season_logic(): + """Test the NHL season logic.""" + print("Testing NHL season logic...") + + now = datetime.now(pytz.utc) + print(f"Current date: {now}") + print(f"Current month: {now.month}") + + # Test the off-season logic + if now.month in [6, 7, 8]: # Off-season months (June, July, August) + print("Status: Off-season") + elif now.month == 9: # September + print("Status: Pre-season (should have games)") + elif now.month == 10 and now.day < 15: # Early October + print("Status: Early season") + else: + print("Status: Regular season") + + # Test season year calculation + season_year = now.year + if now.month < 9: + season_year = now.year - 1 + + print(f"Season year: {season_year}") + print(f"Cache key would be: nhl_api_data_{season_year}") + +def test_espn_api_direct(): + """Test the ESPN API directly to see what data is available.""" + print("\nTesting ESPN API directly...") + + import requests + + url = "https://site.api.espn.com/apis/site/v2/sports/hockey/nhl/scoreboard" + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' + } + + # Test with current date range + now = datetime.now(pytz.utc) + start_date = (now - timedelta(days=30)).strftime("%Y%m%d") + end_date = (now + timedelta(days=30)).strftime("%Y%m%d") + date_range = f"{start_date}-{end_date}" + + params = { + "dates": date_range, + "limit": 1000 + } + + try: + response = requests.get(url, params=params, headers=headers, timeout=15) + response.raise_for_status() + data = response.json() + + events = data.get('events', []) + print(f"Found {len(events)} events in API response") + + if events: + print("Sample events:") + for i, event in enumerate(events[:3]): + print(f" {i+1}. {event.get('name', 'Unknown')} on {event.get('date', 'Unknown')}") + + # Check status distribution + status_counts = {} + for event in events: + competitions = event.get('competitions', []) + if competitions: + status = competitions[0].get('status', {}).get('type', {}) + state = status.get('state', 'unknown') + status_counts[state] = status_counts.get(state, 0) + 1 + + print(f"\nStatus distribution:") + for status, count in status_counts.items(): + print(f" {status}: {count} games") + else: + print("No events found in API response") + + except Exception as e: + print(f"Error testing API: {e}") + +def main(): + """Run all tests.""" + print("=" * 60) + print("NHL Manager Debug Test") + print("=" * 60) + + test_nhl_season_logic() + test_espn_api_direct() + + print("\n" + "=" * 60) + print("Debug test complete!") + print("=" * 60) + +if __name__ == "__main__": + main()