Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 156 additions & 0 deletions WEB_INTERFACE_V2_ENHANCED_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# LED Matrix Web Interface V2 - Enhanced Summary

## Overview
The enhanced LED Matrix Web Interface V2 now includes comprehensive configuration options, improved display preview, CPU utilization monitoring, and all features from the original web interface while maintaining a modern, user-friendly design.

## Key Enhancements

### 1. Complete LED Matrix Configuration Options
- **Hardware Settings**: All LED Matrix hardware options are now configurable through the web UI
- Rows, Columns, Chain Length, Parallel chains
- Brightness (with real-time slider)
- Hardware Mapping (Adafruit HAT PWM, HAT, Regular, Pi1)
- GPIO Slowdown, Scan Mode
- PWM Bits, PWM Dither Bits, PWM LSB Nanoseconds
- Limit Refresh Rate, Hardware Pulsing, Inverse Colors
- Show Refresh Rate, Short Date Format options

### 2. Enhanced System Monitoring
- **CPU Utilization**: Real-time CPU usage percentage display
- **Memory Usage**: Improved memory monitoring using psutil
- **Disk Usage**: Added disk space monitoring
- **CPU Temperature**: Existing temperature monitoring preserved
- **System Uptime**: Real-time uptime display
- **Service Status**: LED Matrix service status monitoring

### 3. Improved Display Preview
- **8x Scaling**: Increased from 4x to 8x scaling for better visibility
- **Better Error Handling**: Proper fallback when no display data is available
- **Smoother Updates**: Increased update frequency from 10fps to 20fps
- **Enhanced Styling**: Better border and background styling for the preview area

### 4. Comprehensive Configuration Tabs
- **Overview**: System stats with CPU, memory, temperature, disk usage
- **Schedule**: Display on/off scheduling
- **Display**: Complete LED Matrix hardware configuration
- **Sports**: Sports leagues configuration (placeholder for full implementation)
- **Weather**: Weather service configuration
- **Stocks**: Stock and cryptocurrency ticker configuration
- **Features**: Additional features like clock, text display, etc.
- **Music**: Music display configuration (YouTube Music, Spotify)
- **Calendar**: Google Calendar integration settings
- **News**: RSS news feeds management with custom feeds
- **API Keys**: Secure API key management for all services
- **Editor**: Visual display editor for custom layouts
- **Actions**: System control actions (start/stop, reboot, updates)
- **Raw JSON**: Direct JSON configuration editing with validation
- **Logs**: System logs viewing and refresh

### 5. Enhanced JSON Editor
- **Real-time Validation**: Live JSON syntax validation
- **Visual Status Indicators**: Color-coded status (Valid/Invalid/Warning)
- **Format Function**: Automatic JSON formatting
- **Error Details**: Detailed error messages with line numbers
- **Syntax Highlighting**: Monospace font with proper styling

### 6. News Manager Integration
- **RSS Feed Management**: Add/remove custom RSS feeds
- **Feed Selection**: Enable/disable built-in news feeds
- **Headlines Configuration**: Configure headlines per feed
- **Rotation Settings**: Enable headline rotation
- **Status Monitoring**: Real-time news manager status

### 7. Form Handling & Validation
- **Async Form Submission**: All forms use modern async/await patterns
- **Real-time Feedback**: Immediate success/error notifications
- **Input Validation**: Client-side and server-side validation
- **Auto-save Features**: Some settings auto-save on change

### 8. Responsive Design Improvements
- **Mobile Friendly**: Better mobile responsiveness
- **Flexible Layout**: Grid-based responsive layout
- **Tab Wrapping**: Tabs wrap on smaller screens
- **Scrollable Content**: Tab content scrolls when needed

### 9. Backend Enhancements
- **psutil Integration**: Added psutil for better system monitoring
- **Route Compatibility**: All original web interface routes preserved
- **Error Handling**: Improved error handling and logging
- **Configuration Management**: Better config file handling

### 10. User Experience Improvements
- **Loading States**: Loading indicators for async operations
- **Connection Status**: WebSocket connection status indicator
- **Notifications**: Toast-style notifications for all actions
- **Tooltips & Descriptions**: Helpful descriptions for all settings
- **Visual Feedback**: Hover effects and transitions

## Technical Implementation

### Dependencies Added
- `psutil>=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.
Binary file modified assets/broadcast_logos/espn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 7 additions & 8 deletions requirements_web_v2.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
Flask==2.3.3
Flask-SocketIO==5.3.6
Pillow>=9.0.0
python-socketio>=5.0.0
eventlet>=0.33.0
freetype-py==2.5.1
requests>=2.32.0
pytz==2023.3
flask>=2.3.0
flask-socketio>=5.3.0
python-socketio>=5.8.0
eventlet>=0.33.3
Pillow>=10.0.0
psutil>=5.9.0
werkzeug>=2.3.0
114 changes: 67 additions & 47 deletions src/news_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __init__(self, config: Dict[str, Any], display_manager):
self.news_data = {}
self.current_headline_index = 0
self.scroll_position = 0
self.cached_text_image = None
self.scrolling_image = None # Pre-rendered image for smooth scrolling
self.cached_text = None
self.cache_manager = CacheManager()
self.current_headlines = []
Expand Down Expand Up @@ -214,6 +214,7 @@ def prepare_headlines_for_display(self):

# Calculate text dimensions for perfect scrolling
self.calculate_scroll_dimensions()
self.create_scrolling_image()

self.current_headlines = display_headlines
logger.debug(f"Prepared {len(display_headlines)} headlines for display")
Expand Down Expand Up @@ -251,6 +252,29 @@ def calculate_scroll_dimensions(self):
self.total_scroll_width = len(self.cached_text) * 8 # Fallback estimate
self.calculate_dynamic_duration()

def create_scrolling_image(self):
"""Create a pre-rendered image for smooth scrolling."""
if not self.cached_text:
self.scrolling_image = None
return

try:
font = ImageFont.truetype(self.font_path, self.font_size)
except Exception as e:
logger.warning(f"Failed to load custom font for pre-rendering: {e}. Using default.")
font = ImageFont.load_default()

height = self.display_manager.height
width = self.total_scroll_width

self.scrolling_image = Image.new('RGB', (width, height), (0, 0, 0))
draw = ImageDraw.Draw(self.scrolling_image)

text_height = self.font_size
y_pos = (height - text_height) // 2
draw.text((0, y_pos), self.cached_text, font=font, fill=self.text_color)
logger.debug("Pre-rendered scrolling news image created.")

def calculate_dynamic_duration(self):
"""Calculate the exact time needed to display all headlines"""
# If dynamic duration is disabled, use fixed duration from config
Expand Down Expand Up @@ -309,57 +333,46 @@ def should_update(self) -> bool:
return (time.time() - self.last_update) > self.update_interval

def get_news_display(self) -> Image.Image:
"""Generate the scrolling news ticker display"""
"""Generate the scrolling news ticker display by cropping the pre-rendered image."""
try:
if not self.cached_text:
logger.debug("No cached text available, showing loading image")
if not self.scrolling_image:
logger.debug("No pre-rendered image available, showing loading image.")
return self.create_no_news_image()

# Create display image

width = self.display_manager.width
height = self.display_manager.height

# Use modulo for continuous scrolling
self.scroll_position = (self.scroll_position + self.scroll_speed) % self.total_scroll_width

# Crop the visible part of the image
x = self.scroll_position
visible_end = x + width

img = Image.new('RGB', (width, height), (0, 0, 0))
draw = ImageDraw.Draw(img)

# Load font
try:
font = ImageFont.truetype(self.font_path, self.font_size)
logger.debug(f"Successfully loaded custom font: {self.font_path}")
except Exception as e:
logger.warning(f"Failed to load custom font '{self.font_path}': {e}. Using default font.")
font = ImageFont.load_default()

# Calculate vertical position (center the text)
text_height = self.font_size
y_pos = (height - text_height) // 2

# Calculate scroll position for smooth animation
if self.total_scroll_width > 0:
# Scroll from right to left
x_pos = width - self.scroll_position

# Draw the text
draw.text((x_pos, y_pos), self.cached_text, font=font, fill=self.text_color)

# If text has scrolled partially off screen, draw it again for seamless loop
if x_pos + self.total_scroll_width < width:
draw.text((x_pos + self.total_scroll_width, y_pos), self.cached_text, font=font, fill=self.text_color)
if visible_end <= self.total_scroll_width:
# No wrap-around needed
img = self.scrolling_image.crop((x, 0, visible_end, height))
else:
# Handle wrap-around
img = Image.new('RGB', (width, height))

# Update scroll position
self.scroll_position += self.scroll_speed
width1 = self.total_scroll_width - x
portion1 = self.scrolling_image.crop((x, 0, self.total_scroll_width, height))
img.paste(portion1, (0, 0))

# Reset scroll when text has completely passed
if self.scroll_position >= self.total_scroll_width:
self.scroll_position = 0
self.rotation_count += 1

# Check if we should rotate headlines
if (self.rotation_enabled and
self.rotation_count >= self.rotation_threshold and
any(len(headlines) > self.headlines_per_feed for headlines in self.news_data.values())):
self.prepare_headlines_for_display()
self.rotation_count = 0
width2 = width - width1
portion2 = self.scrolling_image.crop((0, 0, width2, height))
img.paste(portion2, (width1, 0))

# Check for rotation when scroll completes a cycle
if self.scroll_position < self.scroll_speed: # Check if we just wrapped around
self.rotation_count += 1
if (self.rotation_enabled and
self.rotation_count >= self.rotation_threshold and
any(len(headlines) > self.headlines_per_feed for headlines in self.news_data.values())):
logger.info("News rotation threshold reached. Preparing new headlines.")
self.prepare_headlines_for_display()
self.rotation_count = 0

return img

Expand Down Expand Up @@ -438,16 +451,22 @@ def display_news(self, force_clear: bool = False):
self.display_manager.image = img
self.display_manager.update_display()

# Add scroll delay to control speed
time.sleep(self.scroll_delay)

# Debug: log scroll position
if hasattr(self, 'scroll_position') and hasattr(self, 'total_scroll_width'):
logger.debug(f"Scroll position: {self.scroll_position}/{self.total_scroll_width}")

return True

except Exception as e:
logger.error(f"Error in news display: {e}")
# Create error image
error_img = self.create_error_image(str(e))
self.display_manager.image = error_img
self.display_manager.update_display()
return False

def run_news_display(self):
"""Standalone method to run news display in its own loop"""
Expand Down Expand Up @@ -516,5 +535,6 @@ def get_feed_status(self) -> Dict[str, Any]:

def get_dynamic_duration(self) -> int:
"""Get the calculated dynamic duration for display"""
# Return the current calculated duration without fetching data
return self.dynamic_duration
# For smooth scrolling, use a very short duration so display controller calls us frequently
# The scroll_speed controls how many pixels we move per call
return 0.1 # 0.1 second duration - display controller will call us 10 times per second
Loading