mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 21:03:01 +00:00
AI bug squash sesh
This commit is contained in:
@@ -5,3 +5,4 @@ eventlet>=0.33.3
|
|||||||
Pillow>=10.0.0
|
Pillow>=10.0.0
|
||||||
psutil>=5.9.0
|
psutil>=5.9.0
|
||||||
werkzeug>=2.3.0
|
werkzeug>=2.3.0
|
||||||
|
freetype-py>=2.3.0
|
||||||
@@ -347,6 +347,16 @@ class DisplayController:
|
|||||||
|
|
||||||
# Update display durations to include all modes
|
# Update display durations to include all modes
|
||||||
self.display_durations = self.config['display'].get('display_durations', {})
|
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
|
# Add defaults for soccer if missing
|
||||||
default_durations = {
|
default_durations = {
|
||||||
'clock': 15,
|
'clock': 15,
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ class DisplayManager:
|
|||||||
self.draw = ImageDraw.Draw(self.image)
|
self.draw = ImageDraw.Draw(self.image)
|
||||||
self.draw.text((10, 10), "Matrix Error", fill=(255, 0, 0))
|
self.draw.text((10, 10), "Matrix Error", fill=(255, 0, 0))
|
||||||
logger.error(f"Matrix initialization failed, using fallback mode. Error: {e}")
|
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
|
@property
|
||||||
def width(self):
|
def width(self):
|
||||||
@@ -229,8 +229,8 @@ class DisplayManager:
|
|||||||
pixel_x = x + glyph_left + j
|
pixel_x = x + glyph_left + j
|
||||||
pixel_y = y - glyph_top + i
|
pixel_y = y - glyph_top + i
|
||||||
# Only draw if within bounds
|
# Only draw if within bounds
|
||||||
if (0 <= pixel_x < self.matrix.width and
|
if (0 <= pixel_x < self.width and
|
||||||
0 <= pixel_y < self.matrix.height):
|
0 <= pixel_y < self.height):
|
||||||
self.draw.point((pixel_x, pixel_y), fill=color)
|
self.draw.point((pixel_x, pixel_y), fill=color)
|
||||||
|
|
||||||
# Move to next character
|
# Move to next character
|
||||||
@@ -353,7 +353,7 @@ class DisplayManager:
|
|||||||
# Calculate x position if not provided (center text)
|
# Calculate x position if not provided (center text)
|
||||||
if x is None:
|
if x is None:
|
||||||
text_width = self.get_text_width(text, current_font)
|
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
|
# Set default y position if not provided
|
||||||
if y is None:
|
if y is None:
|
||||||
@@ -567,7 +567,18 @@ class DisplayManager:
|
|||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
"""Clean up resources."""
|
"""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
|
# Reset the singleton state when cleaning up
|
||||||
DisplayManager._instance = None
|
DisplayManager._instance = None
|
||||||
DisplayManager._initialized = False
|
DisplayManager._initialized = False
|
||||||
|
|||||||
@@ -337,7 +337,11 @@ class BaseNCAABaseballManager:
|
|||||||
away_spread = f"+{away_spread}"
|
away_spread = f"+{away_spread}"
|
||||||
|
|
||||||
# Define colors for odds text
|
# 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
|
odds_color = (255, 0, 0) # Red text
|
||||||
outline_color = (0, 0, 0) # Black outline
|
outline_color = (0, 0, 0) # Black outline
|
||||||
|
|
||||||
|
|||||||
@@ -318,7 +318,11 @@ class BaseNHLManager:
|
|||||||
|
|
||||||
# Log game details for debugging
|
# 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] 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
|
# Validate logo files
|
||||||
for team in ["home", "away"]:
|
for team in ["home", "away"]:
|
||||||
|
|||||||
@@ -393,8 +393,10 @@ def system_action():
|
|||||||
result = subprocess.run(['sudo', 'reboot'],
|
result = subprocess.run(['sudo', 'reboot'],
|
||||||
capture_output=True, text=True)
|
capture_output=True, text=True)
|
||||||
elif action == 'git_pull':
|
elif action == 'git_pull':
|
||||||
|
home_dir = str(Path.home())
|
||||||
|
project_dir = os.path.join(home_dir, 'LEDMatrix')
|
||||||
result = subprocess.run(['git', 'pull'],
|
result = subprocess.run(['git', 'pull'],
|
||||||
capture_output=True, text=True, cwd='/workspace')
|
capture_output=True, text=True, cwd=project_dir, check=False)
|
||||||
else:
|
else:
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': 'error',
|
'status': 'error',
|
||||||
|
|||||||
Reference in New Issue
Block a user