diff --git a/requirements_web_v2.txt b/requirements_web_v2.txt index 537de8b3..4696b7b3 100644 --- a/requirements_web_v2.txt +++ b/requirements_web_v2.txt @@ -4,4 +4,5 @@ python-socketio>=5.8.0 eventlet>=0.33.3 Pillow>=10.0.0 psutil>=5.9.0 -werkzeug>=2.3.0 \ No newline at end of file +werkzeug>=2.3.0 +freetype-py>=2.3.0 \ No newline at end of file diff --git a/src/display_controller.py b/src/display_controller.py index 1d105024..4ba8f6c4 100644 --- a/src/display_controller.py +++ b/src/display_controller.py @@ -347,6 +347,16 @@ class DisplayController: # Update display durations to include all modes self.display_durations = self.config['display'].get('display_durations', {}) + # Backward-compatibility: map legacy weather keys to current keys if provided in config + try: + if 'weather' in self.display_durations and 'weather_current' not in self.display_durations: + self.display_durations['weather_current'] = self.display_durations['weather'] + if 'hourly_forecast' in self.display_durations and 'weather_hourly' not in self.display_durations: + self.display_durations['weather_hourly'] = self.display_durations['hourly_forecast'] + if 'daily_forecast' in self.display_durations and 'weather_daily' not in self.display_durations: + self.display_durations['weather_daily'] = self.display_durations['daily_forecast'] + except Exception: + pass # Add defaults for soccer if missing default_durations = { 'clock': 15, diff --git a/src/display_manager.py b/src/display_manager.py index e271ec0c..5e26a310 100644 --- a/src/display_manager.py +++ b/src/display_manager.py @@ -108,7 +108,7 @@ class DisplayManager: self.draw = ImageDraw.Draw(self.image) self.draw.text((10, 10), "Matrix Error", fill=(255, 0, 0)) logger.error(f"Matrix initialization failed, using fallback mode. Error: {e}") - raise + # Do not raise here; allow fallback mode so web preview and non-hardware environments work @property def width(self): @@ -229,8 +229,8 @@ class DisplayManager: pixel_x = x + glyph_left + j pixel_y = y - glyph_top + i # Only draw if within bounds - if (0 <= pixel_x < self.matrix.width and - 0 <= pixel_y < self.matrix.height): + if (0 <= pixel_x < self.width and + 0 <= pixel_y < self.height): self.draw.point((pixel_x, pixel_y), fill=color) # Move to next character @@ -353,7 +353,7 @@ class DisplayManager: # Calculate x position if not provided (center text) if x is None: text_width = self.get_text_width(text, current_font) - x = (self.matrix.width - text_width) // 2 + x = (self.width - text_width) // 2 # Set default y position if not provided if y is None: @@ -567,7 +567,18 @@ class DisplayManager: def cleanup(self): """Clean up resources.""" - self.matrix.Clear() + if hasattr(self, 'matrix') and self.matrix is not None: + try: + self.matrix.Clear() + except Exception as e: + logger.warning(f"Error clearing matrix during cleanup: {e}") + # Ensure image/draw are reset to a blank state + if hasattr(self, 'image') and hasattr(self, 'draw'): + try: + self.image = Image.new('RGB', (self.width, self.height)) + self.draw = ImageDraw.Draw(self.image) + except Exception: + pass # Reset the singleton state when cleaning up DisplayManager._instance = None DisplayManager._initialized = False diff --git a/src/ncaa_baseball_managers.py b/src/ncaa_baseball_managers.py index 7dc6c5c4..948adc86 100644 --- a/src/ncaa_baseball_managers.py +++ b/src/ncaa_baseball_managers.py @@ -337,7 +337,11 @@ class BaseNCAABaseballManager: away_spread = f"+{away_spread}" # Define colors for odds text - odds_font = self.display_manager.status_font + # Use a small readable font for odds; fall back to default if not available + try: + odds_font = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6) + except IOError: + odds_font = ImageFont.load_default() odds_color = (255, 0, 0) # Red text outline_color = (0, 0, 0) # Black outline diff --git a/src/nhl_managers.py b/src/nhl_managers.py index 5ccec6bc..88d53557 100644 --- a/src/nhl_managers.py +++ b/src/nhl_managers.py @@ -318,7 +318,11 @@ class BaseNHLManager: # Log game details for debugging self.logger.debug(f"[NHL] Extracted game details: {details['away_abbr']} vs {details['home_abbr']}") - self.logger.debug(f"[NHL] Game status: is_final={details['is_final']}, is_within_window={details['is_within_window']}") + # Use .get() to avoid KeyError if optional keys are missing + self.logger.debug( + f"[NHL] Game status: is_final={details.get('is_final')}, " + f"is_upcoming={details.get('is_upcoming')}, is_live={details.get('is_live')}" + ) # Validate logo files for team in ["home", "away"]: diff --git a/test_milb_live_debug.py b/test/test_milb_live_debug.py similarity index 100% rename from test_milb_live_debug.py rename to test/test_milb_live_debug.py diff --git a/web_interface_v2.py b/web_interface_v2.py index 6123e6ec..5ee01ec7 100644 --- a/web_interface_v2.py +++ b/web_interface_v2.py @@ -393,8 +393,10 @@ def system_action(): result = subprocess.run(['sudo', 'reboot'], capture_output=True, text=True) elif action == 'git_pull': + home_dir = str(Path.home()) + project_dir = os.path.join(home_dir, 'LEDMatrix') result = subprocess.run(['git', 'pull'], - capture_output=True, text=True, cwd='/workspace') + capture_output=True, text=True, cwd=project_dir, check=False) else: return jsonify({ 'status': 'error', diff --git a/CACHE_STRATEGY.md b/wiki/CACHE_STRATEGY.md similarity index 100% rename from CACHE_STRATEGY.md rename to wiki/CACHE_STRATEGY.md diff --git a/CUSTOM_FEEDS_GUIDE.md b/wiki/CUSTOM_FEEDS_GUIDE.md similarity index 100% rename from CUSTOM_FEEDS_GUIDE.md rename to wiki/CUSTOM_FEEDS_GUIDE.md diff --git a/DYNAMIC_DURATION_GUIDE.md b/wiki/DYNAMIC_DURATION_GUIDE.md similarity index 100% rename from DYNAMIC_DURATION_GUIDE.md rename to wiki/DYNAMIC_DURATION_GUIDE.md diff --git a/DYNAMIC_DURATION_STOCKS_IMPLEMENTATION.md b/wiki/DYNAMIC_DURATION_STOCKS_IMPLEMENTATION.md similarity index 100% rename from DYNAMIC_DURATION_STOCKS_IMPLEMENTATION.md rename to wiki/DYNAMIC_DURATION_STOCKS_IMPLEMENTATION.md diff --git a/MILB_TROUBLESHOOTING.md b/wiki/MILB_TROUBLESHOOTING.md similarity index 100% rename from MILB_TROUBLESHOOTING.md rename to wiki/MILB_TROUBLESHOOTING.md diff --git a/NEWS_MANAGER_README.md b/wiki/NEWS_MANAGER_README.md similarity index 100% rename from NEWS_MANAGER_README.md rename to wiki/NEWS_MANAGER_README.md