mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 13:02:59 +00:00
Feature/vegas scroll mode (#215)
* feat(display): add Vegas-style continuous scroll mode Implement an opt-in Vegas ticker mode that composes all enabled plugin content into a single continuous horizontal scroll. Includes a modular package (src/vegas_mode/) with double-buffered streaming, 125 FPS render pipeline using the existing ScrollHelper, live priority interruption support, and a web UI for configuration with drag-drop plugin ordering. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(vegas): add three-mode display system (SCROLL, FIXED_SEGMENT, STATIC) Adds a flexible display mode system for Vegas scroll mode that allows plugins to control how their content appears in the continuous scroll: - SCROLL: Content scrolls continuously (multi-item plugins like sports) - FIXED_SEGMENT: Fixed block that scrolls by (clock, weather) - STATIC: Scroll pauses, plugin displays, then resumes (alerts) Changes: - Add VegasDisplayMode enum to base_plugin.py with backward-compatible mapping from legacy get_vegas_content_type() - Add static pause handling to coordinator with scroll position save/restore - Add mode-aware content composition to stream_manager - Add vegas_mode info to /api/v3/plugins/installed endpoint - Add mode indicators to Vegas settings UI - Add comprehensive plugin developer documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas,widgets): address validation, thread safety, and XSS issues Vegas mode fixes: - config.py: align validation limits with UI (scroll_speed max 200, separator_width max 128) - coordinator.py: fix race condition by properly initializing _pending_config - plugin_adapter.py: remove unused import - render_pipeline.py: preserve deque type in reset() method - stream_manager.py: fix lock handling and swap_buffers to truly swap API fixes: - api_v3.py: normalize boolean checkbox values, validate numeric fields, ensure JSON arrays Widget fixes: - day-selector.js: remove escapeHtml from JSON.stringify to prevent corruption - password-input.js: use deterministic color class mapping for Tailwind JIT - radio-group.js: replace inline onchange with addEventListener to prevent XSS - select-dropdown.js: guard global registry access - slider.js: add escapeAttr for attributes, fix null dereference in setValue Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): improve exception handling and static pause state management coordinator.py: - _check_live_priority: use logger.exception for full traceback - _end_static_pause: guard scroll resume on interruption (stop/live priority) - _update_static_mode_plugins: log errors instead of silently swallowing render_pipeline.py: - compose_scroll_content: use specific exceptions and logger.exception - render_frame: use specific exceptions and logger.exception - hot_swap_content: use specific exceptions and logger.exception Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): add interrupt mechanism and improve config/exception handling - Add interrupt checker callback to Vegas coordinator for responsive handling of on-demand requests and wifi status during Vegas mode - Fix config.py update() to include dynamic duration fields - Fix is_plugin_included() consistency with get_ordered_plugins() - Update _apply_pending_config to propagate config to StreamManager - Change _fetch_plugin_content to use logger.exception for traceback - Replace bare except in _refresh_plugin_list with specific exceptions - Add aria-label accessibility to Vegas toggle checkbox - Fix XSS vulnerability in plugin metadata rendering with escapeHtml Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): improve logging, validation, lock handling, and config updates - display_controller.py: use logger.exception for Vegas errors with traceback - base_plugin.py: validate vegas_panel_count as positive integer with warning - coordinator.py: fix _apply_pending_config to avoid losing concurrent updates by clearing _pending_config while holding lock - plugin_adapter.py: remove broad catch-all, use narrower exception types (AttributeError, TypeError, ValueError, OSError, RuntimeError) and logger.exception for traceback preservation - api_v3.py: only update vegas_config['enabled'] when key is present in data to prevent incorrect disabling when checkbox is omitted Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): improve cycle advancement, logging, and accessibility - Add advance_cycle() method to StreamManager for clearing buffer between cycles - Call advance_cycle() in RenderPipeline.start_new_cycle() for fresh content - Use logger.exception() for interrupt check and static pause errors (full tracebacks) - Add id="vegas_scroll_label" to h3 for aria-labelledby reference - Call updatePluginConfig() after rendering plugin list for proper initialization Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): add thread-safety, preserve updates, and improve logging - display_controller.py: Use logger.exception() for Vegas import errors - plugin_adapter.py: Add thread-safe cache lock, remove unused exception binding - stream_manager.py: In-place merge in process_updates() preserves non-updated plugins - api_v3.py: Change vegas_scroll_enabled default from False to True Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): add debug logging and narrow exception types - stream_manager.py: Log when get_vegas_display_mode() is unavailable - stream_manager.py: Narrow exception type from Exception to (AttributeError, TypeError) - api_v3.py: Log exceptions when reading Vegas display metadata with plugin context Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): fix method call and improve exception logging - Fix _check_vegas_interrupt() calling nonexistent _check_wifi_status(), now correctly calls _check_wifi_status_message() - Update _refresh_plugin_list() exception handler to use logger.exception() with plugin_id and class name for remote debugging Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(web): replace complex toggle with standard checkbox for Vegas mode The Tailwind pseudo-element toggle (after:content-[''], etc.) wasn't rendering because these classes weren't in the CSS bundle. Replaced with a simple checkbox that matches other form controls in the template. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * debug(vegas): add detailed logging to _refresh_plugin_list Track why plugins aren't being found for Vegas scroll: - Log count of loaded plugins - Log enabled status for each plugin - Log content_type and display_mode checks - Log when plugin_manager lacks loaded_plugins Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): use correct attribute name for plugin manager StreamManager and VegasModeCoordinator were checking for plugin_manager.loaded_plugins but PluginManager stores active plugins in plugin_manager.plugins. This caused Vegas scroll to find zero plugins despite plugins being available. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): convert scroll_speed from px/sec to px/frame correctly The config scroll_speed is in pixels per second, but ScrollHelper in frame_based_scrolling mode interprets it as pixels per frame. Previously this caused the speed to be clamped to max 5.0 regardless of the configured value. Now properly converts: pixels_per_frame = scroll_speed * scroll_delay With defaults (50 px/s, 0.02s delay), this gives 1 px/frame = 50 px/s. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(vegas): add FPS logging every 5 seconds Logs actual FPS vs target FPS to help diagnose performance issues. Shows frame count in each 5-second interval. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): improve plugin content capture reliability - Call update_data() before capture to ensure fresh plugin data - Try display() without force_clear first, fallback if TypeError - Retry capture with force_clear=True if first attempt is blank - Use histogram-based blank detection instead of point sampling (more reliable for content positioned anywhere in frame) This should help capture content from plugins that don't implement get_vegas_content() natively. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): handle callable width/height on display_manager DisplayManager.width and .height may be methods or properties depending on the implementation. Use callable() check to call them if needed, ensuring display_width and display_height are always integers. Fixes potential TypeError when width/height are methods. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): use logger.exception for display mode errors Replace logger.error with logger.exception to capture full stack trace when get_vegas_display_mode() fails on a plugin. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): protect plugin list updates with buffer lock Move assignment of _ordered_plugins and index resets under _buffer_lock to prevent race conditions with _prefetch_content() which reads these variables under the same lock. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): catch all exceptions in get_vegas_display_mode Broaden exception handling from AttributeError/TypeError to Exception so any plugin error in get_vegas_display_mode() doesn't abort the entire plugin list refresh. The loop continues with the default FIXED_SEGMENT mode. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(vegas): refresh stream manager when config updates After updating stream_manager.config, force a refresh to pick up changes to plugin_order, excluded_plugins, and buffer_ahead settings. Also use logger.exception to capture full stack traces on config update errors. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * debug(vegas): add detailed logging for blank image detection * feat(vegas): extract full scroll content from plugins using ScrollHelper Plugins like ledmatrix-stocks and odds-ticker use ScrollHelper with a cached_image that contains their full scrolling content. Instead of falling back to single-frame capture, now check for scroll_helper.cached_image first to get the complete scrolling content for Vegas mode. * debug(vegas): add comprehensive INFO-level logging for plugin content flow - Log each plugin being processed with class name - Log which content methods are tried (native, scroll_helper, fallback) - Log success/failure of each method with image dimensions - Log brightness check results for blank image detection - Add visual separators in logs for easier debugging - Log plugin list refresh with enabled/excluded status Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(vegas): trigger scroll content generation when cache is empty When a plugin has a scroll_helper but its cached_image is not yet populated, try to trigger content generation by: 1. Calling _create_scrolling_display() if available (stocks pattern) 2. Calling display(force_clear=True) as a fallback This allows plugins like stocks to provide their full scroll content even when Vegas mode starts before the plugin has run its normal display cycle. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: improve exception handling in plugin_adapter scroll content retrieval Replace broad except Exception handlers with narrow exception types (AttributeError, TypeError, ValueError, OSError) and use logger.exception instead of logger.warning/info to capture full stack traces for better diagnosability. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: narrow exception handling in coordinator and plugin_adapter - coordinator.py: Replace broad Exception catch around get_vegas_display_mode() with (AttributeError, TypeError) and use logger.exception for stack traces - plugin_adapter.py: Narrow update_data() exception handler to (AttributeError, RuntimeError, OSError) and use logger.exception Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: improve Vegas mode robustness and API validation - display_controller: Guard against None plugin_manager in Vegas init - coordinator: Restore scrolling state in resume() to match pause() - api_v3: Validate Vegas numeric fields with range checks and 400 errors Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Chuck <chuck@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
388
docs/VEGAS_SCROLL_MODE.md
Normal file
388
docs/VEGAS_SCROLL_MODE.md
Normal file
@@ -0,0 +1,388 @@
|
||||
# Vegas Scroll Mode - Plugin Developer Guide
|
||||
|
||||
Vegas scroll mode displays content from multiple plugins in a continuous horizontal scroll, similar to the news tickers seen in Las Vegas casinos. This guide explains how to integrate your plugin with Vegas mode.
|
||||
|
||||
## Overview
|
||||
|
||||
When Vegas mode is enabled, the display controller composes content from all enabled plugins into a single continuous scroll. Each plugin can control how its content appears in the scroll using one of three **display modes**:
|
||||
|
||||
| Mode | Behavior | Best For |
|
||||
|------|----------|----------|
|
||||
| **SCROLL** | Content scrolls continuously within the stream | Multi-item plugins (sports scores, odds, news) |
|
||||
| **FIXED_SEGMENT** | Fixed-width block that scrolls by | Static info (clock, weather, current temp) |
|
||||
| **STATIC** | Scroll pauses, plugin displays for duration, then resumes | Important alerts, detailed views |
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Minimal Integration (Zero Code Changes)
|
||||
|
||||
If you do nothing, your plugin will work with Vegas mode using these defaults:
|
||||
|
||||
- Plugins with `get_vegas_content_type() == 'multi'` use **SCROLL** mode
|
||||
- Plugins with `get_vegas_content_type() == 'static'` use **FIXED_SEGMENT** mode
|
||||
- Content is captured by calling your plugin's `display()` method
|
||||
|
||||
### Basic Integration
|
||||
|
||||
To provide optimized Vegas content, implement `get_vegas_content()`:
|
||||
|
||||
```python
|
||||
from PIL import Image
|
||||
|
||||
class MyPlugin(BasePlugin):
|
||||
def get_vegas_content(self):
|
||||
"""Return content for Vegas scroll mode."""
|
||||
# Return a single image for fixed content
|
||||
return self._render_current_view()
|
||||
|
||||
# OR return multiple images for multi-item content
|
||||
# return [self._render_item(item) for item in self.items]
|
||||
```
|
||||
|
||||
### Full Integration
|
||||
|
||||
For complete control over Vegas behavior, implement these methods:
|
||||
|
||||
```python
|
||||
from src.plugin_system.base_plugin import BasePlugin, VegasDisplayMode
|
||||
|
||||
class MyPlugin(BasePlugin):
|
||||
def get_vegas_content_type(self) -> str:
|
||||
"""Legacy method - determines default mode mapping."""
|
||||
return 'multi' # or 'static' or 'none'
|
||||
|
||||
def get_vegas_display_mode(self) -> VegasDisplayMode:
|
||||
"""Specify how this plugin behaves in Vegas scroll."""
|
||||
return VegasDisplayMode.SCROLL
|
||||
|
||||
def get_supported_vegas_modes(self) -> list:
|
||||
"""Return list of modes users can configure."""
|
||||
return [VegasDisplayMode.SCROLL, VegasDisplayMode.FIXED_SEGMENT]
|
||||
|
||||
def get_vegas_content(self):
|
||||
"""Return PIL Image(s) for the scroll."""
|
||||
return [self._render_game(g) for g in self.games]
|
||||
|
||||
def get_vegas_segment_width(self) -> int:
|
||||
"""For FIXED_SEGMENT: width in panels (optional)."""
|
||||
return 2 # Use 2 panels width
|
||||
```
|
||||
|
||||
## Display Modes Explained
|
||||
|
||||
### SCROLL Mode
|
||||
|
||||
Content scrolls continuously within the Vegas stream. Best for plugins with multiple items.
|
||||
|
||||
```python
|
||||
def get_vegas_display_mode(self):
|
||||
return VegasDisplayMode.SCROLL
|
||||
|
||||
def get_vegas_content(self):
|
||||
# Return list of images - each scrolls individually
|
||||
images = []
|
||||
for game in self.games:
|
||||
img = Image.new('RGB', (200, 32))
|
||||
# ... render game info ...
|
||||
images.append(img)
|
||||
return images
|
||||
```
|
||||
|
||||
**When to use:**
|
||||
- Sports scores with multiple games
|
||||
- Stock/odds tickers with multiple items
|
||||
- News feeds with multiple headlines
|
||||
|
||||
### FIXED_SEGMENT Mode
|
||||
|
||||
Content is rendered as a fixed-width block that scrolls by with other content.
|
||||
|
||||
```python
|
||||
def get_vegas_display_mode(self):
|
||||
return VegasDisplayMode.FIXED_SEGMENT
|
||||
|
||||
def get_vegas_content(self):
|
||||
# Return single image at your preferred width
|
||||
img = Image.new('RGB', (128, 32)) # 2 panels wide
|
||||
# ... render clock/weather/etc ...
|
||||
return img
|
||||
|
||||
def get_vegas_segment_width(self):
|
||||
# Optional: specify width in panels
|
||||
return 2
|
||||
```
|
||||
|
||||
**When to use:**
|
||||
- Clock display
|
||||
- Current weather/temperature
|
||||
- System status indicators
|
||||
- Any "at a glance" information
|
||||
|
||||
### STATIC Mode
|
||||
|
||||
Scroll pauses completely, your plugin displays using its normal `display()` method for its configured duration, then scroll resumes.
|
||||
|
||||
```python
|
||||
def get_vegas_display_mode(self):
|
||||
return VegasDisplayMode.STATIC
|
||||
|
||||
def get_display_duration(self):
|
||||
# How long to pause and show this plugin
|
||||
return 10.0 # 10 seconds
|
||||
```
|
||||
|
||||
**When to use:**
|
||||
- Important alerts that need attention
|
||||
- Detailed information that's hard to read while scrolling
|
||||
- Interactive or animated content
|
||||
- Content that requires the full display
|
||||
|
||||
## User Configuration
|
||||
|
||||
Users can override the default display mode per-plugin in their config:
|
||||
|
||||
```json
|
||||
{
|
||||
"my_plugin": {
|
||||
"enabled": true,
|
||||
"vegas_mode": "static", // Override: "scroll", "fixed", or "static"
|
||||
"vegas_panel_count": 2, // Width in panels for fixed mode
|
||||
"display_duration": 10 // Duration for static mode
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `get_vegas_display_mode()` method checks config first, then falls back to your implementation.
|
||||
|
||||
## Content Rendering Guidelines
|
||||
|
||||
### Image Dimensions
|
||||
|
||||
- **Height**: Must match display height (typically 32 pixels)
|
||||
- **Width**:
|
||||
- SCROLL: Any width, content will scroll
|
||||
- FIXED_SEGMENT: `panels × single_panel_width` (e.g., 2 × 64 = 128px)
|
||||
|
||||
### Color Mode
|
||||
|
||||
Always use RGB mode for images:
|
||||
|
||||
```python
|
||||
img = Image.new('RGB', (width, 32), color=(0, 0, 0))
|
||||
```
|
||||
|
||||
### Performance Tips
|
||||
|
||||
1. **Cache rendered images** - Don't re-render on every call
|
||||
2. **Pre-render on update()** - Render images when data changes, not when Vegas requests them
|
||||
3. **Keep images small** - Memory adds up with multiple plugins
|
||||
|
||||
```python
|
||||
class MyPlugin(BasePlugin):
|
||||
def __init__(self, ...):
|
||||
super().__init__(...)
|
||||
self._cached_vegas_images = None
|
||||
self._cache_valid = False
|
||||
|
||||
def update(self):
|
||||
# Fetch new data
|
||||
self.data = self._fetch_data()
|
||||
# Invalidate cache so next Vegas request re-renders
|
||||
self._cache_valid = False
|
||||
|
||||
def get_vegas_content(self):
|
||||
if not self._cache_valid:
|
||||
self._cached_vegas_images = self._render_all_items()
|
||||
self._cache_valid = True
|
||||
return self._cached_vegas_images
|
||||
```
|
||||
|
||||
## Fallback Behavior
|
||||
|
||||
If your plugin doesn't implement `get_vegas_content()`, Vegas mode will:
|
||||
|
||||
1. Create a temporary canvas matching display dimensions
|
||||
2. Call your `display()` method
|
||||
3. Capture the resulting image
|
||||
4. Use that image in the scroll
|
||||
|
||||
This works but is less efficient than providing native Vegas content.
|
||||
|
||||
## Excluding from Vegas Mode
|
||||
|
||||
To exclude your plugin from Vegas scroll entirely:
|
||||
|
||||
```python
|
||||
def get_vegas_content_type(self):
|
||||
return 'none'
|
||||
```
|
||||
|
||||
Or users can exclude via config:
|
||||
|
||||
```json
|
||||
{
|
||||
"display": {
|
||||
"vegas_scroll": {
|
||||
"excluded_plugins": ["my_plugin"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
Here's a complete example of a weather plugin with full Vegas integration:
|
||||
|
||||
```python
|
||||
from PIL import Image, ImageDraw
|
||||
from src.plugin_system.base_plugin import BasePlugin, VegasDisplayMode
|
||||
|
||||
class WeatherPlugin(BasePlugin):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.temperature = None
|
||||
self.conditions = None
|
||||
self._vegas_image = None
|
||||
|
||||
def update(self):
|
||||
"""Fetch weather data."""
|
||||
data = self._fetch_weather_api()
|
||||
self.temperature = data['temp']
|
||||
self.conditions = data['conditions']
|
||||
self._vegas_image = None # Invalidate cache
|
||||
|
||||
def display(self, force_clear=False):
|
||||
"""Standard display for normal rotation."""
|
||||
if force_clear:
|
||||
self.display_manager.clear()
|
||||
|
||||
# Full weather display with details
|
||||
self.display_manager.draw_text(
|
||||
f"{self.temperature}°F",
|
||||
x=10, y=8, color=(255, 255, 255)
|
||||
)
|
||||
self.display_manager.draw_text(
|
||||
self.conditions,
|
||||
x=10, y=20, color=(200, 200, 200)
|
||||
)
|
||||
self.display_manager.update_display()
|
||||
|
||||
# --- Vegas Mode Integration ---
|
||||
|
||||
def get_vegas_content_type(self):
|
||||
"""Legacy compatibility."""
|
||||
return 'static'
|
||||
|
||||
def get_vegas_display_mode(self):
|
||||
"""Use FIXED_SEGMENT for compact weather display."""
|
||||
# Allow user override via config
|
||||
return super().get_vegas_display_mode()
|
||||
|
||||
def get_supported_vegas_modes(self):
|
||||
"""Weather can work as fixed or static."""
|
||||
return [VegasDisplayMode.FIXED_SEGMENT, VegasDisplayMode.STATIC]
|
||||
|
||||
def get_vegas_segment_width(self):
|
||||
"""Weather needs 2 panels to show clearly."""
|
||||
return self.config.get('vegas_panel_count', 2)
|
||||
|
||||
def get_vegas_content(self):
|
||||
"""Render compact weather for Vegas scroll."""
|
||||
if self._vegas_image is not None:
|
||||
return self._vegas_image
|
||||
|
||||
# Create compact display (2 panels = 128px typical)
|
||||
panel_width = 64 # From display.hardware.cols
|
||||
panels = self.get_vegas_segment_width() or 2
|
||||
width = panel_width * panels
|
||||
height = 32
|
||||
|
||||
img = Image.new('RGB', (width, height), color=(0, 0, 40))
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
# Draw compact weather
|
||||
temp_text = f"{self.temperature}°"
|
||||
draw.text((10, 8), temp_text, fill=(255, 255, 255))
|
||||
draw.text((60, 8), self.conditions[:10], fill=(200, 200, 200))
|
||||
|
||||
self._vegas_image = img
|
||||
return img
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### VegasDisplayMode Enum
|
||||
|
||||
```python
|
||||
from src.plugin_system.base_plugin import VegasDisplayMode
|
||||
|
||||
VegasDisplayMode.SCROLL # "scroll" - continuous scrolling
|
||||
VegasDisplayMode.FIXED_SEGMENT # "fixed" - fixed block in scroll
|
||||
VegasDisplayMode.STATIC # "static" - pause scroll to display
|
||||
```
|
||||
|
||||
### BasePlugin Vegas Methods
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `get_vegas_content()` | `Image` or `List[Image]` or `None` | Content for Vegas scroll |
|
||||
| `get_vegas_content_type()` | `str` | Legacy: 'multi', 'static', or 'none' |
|
||||
| `get_vegas_display_mode()` | `VegasDisplayMode` | How plugin behaves in Vegas |
|
||||
| `get_supported_vegas_modes()` | `List[VegasDisplayMode]` | Modes available for user config |
|
||||
| `get_vegas_segment_width()` | `int` or `None` | Width in panels for FIXED_SEGMENT |
|
||||
|
||||
### Configuration Options
|
||||
|
||||
**Per-plugin config:**
|
||||
```json
|
||||
{
|
||||
"plugin_id": {
|
||||
"vegas_mode": "scroll|fixed|static",
|
||||
"vegas_panel_count": 2,
|
||||
"display_duration": 15
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Global Vegas config:**
|
||||
```json
|
||||
{
|
||||
"display": {
|
||||
"vegas_scroll": {
|
||||
"enabled": true,
|
||||
"scroll_speed": 50,
|
||||
"separator_width": 32,
|
||||
"plugin_order": ["clock", "weather", "sports"],
|
||||
"excluded_plugins": ["debug_plugin"],
|
||||
"target_fps": 125,
|
||||
"buffer_ahead": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Plugin not appearing in Vegas scroll
|
||||
|
||||
1. Check `get_vegas_content_type()` doesn't return `'none'`
|
||||
2. Verify plugin is not in `excluded_plugins` list
|
||||
3. Ensure plugin is enabled
|
||||
|
||||
### Content looks wrong in scroll
|
||||
|
||||
1. Verify image height matches display height (32px typical)
|
||||
2. Check image mode is 'RGB'
|
||||
3. Test with `get_vegas_content()` returning a simple test image
|
||||
|
||||
### STATIC mode not pausing
|
||||
|
||||
1. Verify `get_vegas_display_mode()` returns `VegasDisplayMode.STATIC`
|
||||
2. Check user hasn't overridden with `vegas_mode` in config
|
||||
3. Ensure `display()` method works correctly
|
||||
|
||||
### Performance issues
|
||||
|
||||
1. Implement image caching in `get_vegas_content()`
|
||||
2. Pre-render images in `update()` instead of on-demand
|
||||
3. Reduce image dimensions if possible
|
||||
Reference in New Issue
Block a user