Files
LEDMatrix/docs/archive/STATIC_IMAGE_MULTI_UPLOAD_PLAN.md
Chuck ddd300a117 Docs/consolidate documentation (#217)
* docs: rename FONT_MANAGER_USAGE.md to FONT_MANAGER.md

Renamed for clearer naming convention.
Part of documentation consolidation effort.

* docs: consolidate Plugin Store guides (2→1)

Merged:
- PLUGIN_STORE_USER_GUIDE.md
- PLUGIN_STORE_QUICK_REFERENCE.md

Into: PLUGIN_STORE_GUIDE.md

- Unified writing style to professional technical
- Added Quick Reference section at top for easy access
- Removed duplicate content
- Added cross-references to related documentation
- Updated formatting to match style guidelines

* docs: create user-focused Web Interface Guide

Created WEB_INTERFACE_GUIDE.md consolidating:
- V3_INTERFACE_README.md (technical details)
- User-facing interface documentation

- Focused on end-user tasks and navigation
- Removed technical implementation details
- Added common tasks section
- Included troubleshooting
- Professional technical writing style

* docs: consolidate WiFi setup guides (4→1)

Merged:
- WIFI_SETUP.md
- OPTIMAL_WIFI_AP_FAILOVER_SETUP.md
- AP_MODE_MANUAL_ENABLE.md
- WIFI_ETHERNET_AP_MODE_FIX.md (behavior documentation)

Into: WIFI_NETWORK_SETUP.md

- Comprehensive coverage of WiFi setup and configuration
- Clear explanation of AP mode failover and grace period
- Configuration scenarios and best practices
- Troubleshooting section combining all sources
- Professional technical writing style
- Added quick reference table for behavior

* docs: consolidate troubleshooting guides (4→1)

Merged:
- TROUBLESHOOTING_QUICK_START.md
- WEB_INTERFACE_TROUBLESHOOTING.md
- CAPTIVE_PORTAL_TROUBLESHOOTING.md
- WEATHER_TROUBLESHOOTING.md

Into: TROUBLESHOOTING.md

- Organized by issue category (web, WiFi, plugins)
- Comprehensive diagnostic commands reference
- Quick diagnosis steps at the top
- Service file template preserved
- Complete diagnostic script included
- Professional technical writing style

* docs: create consolidated Advanced Features guide

Merged:
- VEGAS_SCROLL_MODE.md
- ON_DEMAND_DISPLAY_QUICK_START.md
- ON_DEMAND_DISPLAY_API.md
- ON_DEMAND_CACHE_MANAGEMENT.md
- BACKGROUND_SERVICE_README.md
- PERMISSION_MANAGEMENT_GUIDE.md

Into: ADVANCED_FEATURES.md

- Comprehensive guide covering all advanced features
- Vegas scroll mode with integration examples
- On-demand display with API reference
- Cache management troubleshooting
- Background service documentation
- Permission management patterns
- Professional technical writing style

* docs: create Getting Started guide for first-time users

Created GETTING_STARTED.md:
- Quick start guide (5 minutes)
- Initial configuration walkthrough
- Common first-time issues and solutions
- Next steps and quick reference
- User-friendly tone for beginners
- Links to detailed documentation

* docs: archive consolidated source files and ephemeral docs

Archived files that have been consolidated:
- Plugin Store guides (2 files → PLUGIN_STORE_GUIDE.md)
- Web Interface guide (V3_INTERFACE_README.md → WEB_INTERFACE_GUIDE.md)
- WiFi Setup guides (4 files → WIFI_NETWORK_SETUP.md)
- Troubleshooting guides (4 files → TROUBLESHOOTING.md)
- Advanced Features (6 files → ADVANCED_FEATURES.md)

Archived ephemeral/debug documentation:
- DEBUG_WEB_ISSUE.md
- BROWSER_ERRORS_EXPLANATION.md
- FORM_VALIDATION_FIXES.md
- WEB_UI_RELIABILITY_IMPROVEMENTS.md
- CAPTIVE_PORTAL_TESTING.md
- NEXT_STEPS_COMMANDS.md
- STATIC_IMAGE_MULTI_UPLOAD_PLAN.md
- RECONNECT_AFTER_CAPTIVE_PORTAL_TESTING.md

Archived implementation summaries:
- PLUGIN_CONFIG_TABS_SUMMARY.md
- PLUGIN_CONFIG_SYSTEM_VERIFICATION.md
- PLUGIN_SCHEMA_AUDIT_SUMMARY.md
- STARTUP_OPTIMIZATION_SUMMARY.md
- PLUGIN_DISPATCH_IMPLEMENTATION.md
- NESTED_SCHEMA_IMPLEMENTATION.md
- AP_MODE_MANUAL_ENABLE_CHANGES.md
- PLUGIN_CONFIG_SYSTEM_EXPLANATION.md

Total archived: 27 files
Preserves git history while cleaning up main docs directory

* docs: rename API_REFERENCE.md to REST_API_REFERENCE.md

Renamed for clarity - this is specifically the REST API reference
for the web interface, not a general API reference.

* docs: update README.md to reflect consolidated documentation structure

Updated documentation index:
- Reflects new consolidated guides (51 → 16-17 files)
- Updated Quick Start sections with new file names
- Added consolidation history (January 2026)
- Updated file references (API_REFERENCE → REST_API_REFERENCE)
- Documented archival of 33 files
- Added benefits of consolidation
- Updated statistics and highlights
- Removed outdated references
- Professional writing style maintained throughout

* docs: add Vegas scroll mode system architecture documentation

Added comprehensive internal architecture section for Vegas mode:
- Component overview with diagram
- VegasModeCoordinator responsibilities and main loop
- StreamManager buffering strategy and content flow
- PluginAdapter integration and fallback behavior
- RenderPipeline 125 FPS rendering process
- Component interaction flows
- Thread safety patterns
- Performance characteristics

Covers:
- How the four components work together
- Initialization and render loop flows
- Config update handling
- Frame rate management and optimization
- Memory usage and CPU characteristics

---------

Co-authored-by: Chuck <chuck@example.com>
2026-01-29 10:32:00 -05:00

11 KiB

Static Image Plugin - Multi-Image Upload & Rotation Implementation Plan

Overview

Enhance the static-image plugin to support:

  1. Multiple image uploads via web UI
  2. Image rotation (sequential, random, time-based, date-based)
  3. Robust asset management (storage, validation, cleanup)
  4. Future-proof architecture for advanced rotation logic

Architecture Design

1. Configuration Schema Enhancement

Current Schema

{
  "image_path": "assets/static_images/default.png"
}

Enhanced Schema (Backward Compatible)

{
  "image_config": {
    "mode": "single" | "multiple",
    "rotation_mode": "sequential" | "random" | "time_based" | "date_based",
    "images": [
      {
        "id": "uuid-or-hash",
        "path": "assets/plugins/static-image/uploads/image_1234567890.png",
        "uploaded_at": "2025-01-15T10:30:00Z",
        "display_order": 0,
        "schedule": null  // Future: {"start_time": "08:00", "end_time": "18:00", "days": [1,2,3,4,5]}
      }
    ]
  },
  
  // Legacy support - maps to single image mode
  "image_path": "assets/static_images/default.png",
  
  // Rotation settings
  "rotation_settings": {
    "sequential_loop": true,
    "random_seed": null,  // null = use time, or fixed seed for reproducible rotation
    "time_intervals": {
      "enabled": false,
      "interval_seconds": 3600  // Change image every hour
    },
    "date_ranges": []  // Future: [{"start": "2025-12-01", "end": "2025-12-25", "image_id": "..."}]
  }
}

2. Asset Storage Structure

assets/
├── plugins/
│   └── static-image/
│       └── uploads/
│           ├── image_1705312200_abc123.png
│           ├── image_1705312400_def456.jpg
│           └── .metadata.json  // Maps IDs to filenames

Storage Strategy:

  • Files stored in assets/plugins/static-image/uploads/
  • Filenames: image_{timestamp}_{hash}.{ext} (prevents collisions)
  • Metadata JSON tracks: ID → filename mapping, upload dates, file sizes
  • Cleanup: Remove files not referenced in config

3. Backend API Endpoints

POST /api/v3/plugins/assets/upload

Purpose: Upload image files for a specific plugin

Request:

  • multipart/form-data
  • plugin_id: string (required)
  • files: File[] (multiple files supported)
  • rotation_mode: string (optional, default: "sequential")

Response:

{
  "status": "success",
  "uploaded_files": [
    {
      "id": "uuid-here",
      "filename": "image_1705312200_abc123.png",
      "path": "assets/plugins/static-image/uploads/image_1705312200_abc123.png",
      "size": 45678,
      "uploaded_at": "2025-01-15T10:30:00Z"
    }
  ]
}

Validation:

  • File type: PNG, JPG, JPEG, BMP, GIF
  • Max file size: 5MB per file
  • Max files per upload: 10
  • Total storage limit: 50MB per plugin

DELETE /api/v3/plugins/assets/delete

Purpose: Delete uploaded image

Request:

  • plugin_id: string
  • image_id: string (from upload response)

Response:

{
  "status": "success",
  "deleted_file": "image_1705312200_abc123.png"
}

GET /api/v3/plugins/assets/list

Purpose: List all uploaded images for a plugin

Response:

{
  "status": "success",
  "images": [
    {
      "id": "uuid-here",
      "filename": "image_1705312200_abc123.png",
      "path": "assets/plugins/static-image/uploads/image_1705312200_abc123.png",
      "size": 45678,
      "uploaded_at": "2025-01-15T10:30:00Z"
    }
  ]
}

4. Frontend Form Generator Enhancement

Schema Format for File Upload

{
  "type": "object",
  "properties": {
    "images": {
      "type": "array",
      "x-widget": "file-upload",
      "x-upload-config": {
        "endpoint": "/api/v3/plugins/assets/upload",
        "plugin_id_field": "plugin_id",
        "max_files": 10,
        "allowed_types": ["image/png", "image/jpeg", "image/bmp", "image/gif"],
        "max_size_mb": 5
      },
      "items": {
        "type": "object",
        "properties": {
          "id": {"type": "string"},
          "path": {"type": "string"},
          "uploaded_at": {"type": "string", "format": "date-time"}
        }
      },
      "description": "Upload images to display. Multiple images will rotate based on rotation mode."
    },
    "rotation_mode": {
      "type": "string",
      "enum": ["sequential", "random", "time_based", "date_based"],
      "default": "sequential",
      "description": "How to rotate through images"
    }
  }
}

UI Components

  1. File Upload Widget:

    • Drag-and-drop zone
    • File list with thumbnails
    • Remove button per file
    • Upload progress indicator
    • Image preview before upload
  2. Rotation Mode Selector:

    • Dropdown with rotation options
    • Settings panel per mode:
      • Sequential: Loop option
      • Random: Seed option
      • Time-based: Interval input
      • Date-based: Calendar picker (future)

5. Plugin Manager Updates

Rotation Logic in manager.py

class StaticImagePlugin(BasePlugin):
    def __init__(self, ...):
        # ... existing code ...
        
        # Enhanced image handling
        self.image_config = config.get('image_config', {})
        self.rotation_mode = self.image_config.get('rotation_mode', 'sequential')
        self.rotation_settings = config.get('rotation_settings', {})
        self.images_list = self.image_config.get('images', [])
        self.current_image_index = 0
        self.last_rotation_time = time.time()
        
        # Initialize rotation
        self._setup_rotation()
    
    def _setup_rotation(self):
        """Initialize rotation based on mode"""
        if self.rotation_mode == 'random':
            import random
            seed = self.rotation_settings.get('random_seed')
            if seed:
                random.seed(seed)
        
        if not self.images_list:
            # Fallback to legacy image_path
            if self.image_path:
                self.images_list = [{'path': self.image_path}]
    
    def _get_next_image(self) -> Optional[str]:
        """Get next image path based on rotation mode"""
        if not self.images_list:
            return None
        
        if self.rotation_mode == 'sequential':
            path = self.images_list[self.current_image_index]['path']
            self.current_image_index = (self.current_image_index + 1) % len(self.images_list)
            return path
        
        elif self.rotation_mode == 'random':
            import random
            return random.choice(self.images_list)['path']
        
        elif self.rotation_mode == 'time_based':
            interval = self.rotation_settings.get('time_intervals', {}).get('interval_seconds', 3600)
            now = time.time()
            if now - self.last_rotation_time >= interval:
                self.current_image_index = (self.current_image_index + 1) % len(self.images_list)
                self.last_rotation_time = now
            return self.images_list[self.current_image_index]['path']
        
        elif self.rotation_mode == 'date_based':
            # Future implementation
            return self._get_date_based_image()
        
        return self.images_list[0]['path']
    
    def display(self, force_clear: bool = False):
        """Display current image based on rotation"""
        image_path = self._get_next_image()
        if not image_path or not os.path.exists(image_path):
            self._display_error()
            return
        
        self.image_path = image_path  # For compatibility
        self._load_image()
        
        # ... rest of display logic ...

6. Asset Management System

File Operations

  • Upload: Save to assets/plugins/{plugin_id}/uploads/
  • Validation: Check file type, size, dimensions
  • Metadata: Track in .metadata.json
  • Cleanup: Remove orphaned files on config save
  • Permissions: Ensure writable by web service

Security

  • Validate file extensions (whitelist)
  • Check file content (magic bytes, not just extension)
  • Limit file sizes
  • Sanitize filenames
  • Prevent path traversal

7. Migration Strategy

Backward Compatibility

  1. Legacy Support:

    • If image_path exists but no image_config, auto-convert
    • Create image_config with single image from image_path
  2. Config Migration:

def _migrate_legacy_config(self, config):
    """Migrate legacy image_path to new image_config format"""
    if 'image_path' in config and 'image_config' not in config:
        config['image_config'] = {
            'mode': 'single',
            'rotation_mode': 'sequential',
            'images': [{
                'id': str(uuid.uuid4()),
                'path': config['image_path'],
                'uploaded_at': datetime.now().isoformat(),
                'display_order': 0
            }]
        }
    return config

Implementation Phases

Phase 1: Core Upload System

  1. Enhanced config schema
  2. Backend upload endpoint
  3. Asset storage structure
  4. File validation

Phase 2: Frontend Integration

  1. File upload widget in form generator
  2. Image preview/management UI
  3. Rotation mode selector

Phase 3: Plugin Rotation Logic

  1. Update plugin manager with rotation
  2. Sequential rotation
  3. Random rotation

Phase 4: Advanced Features

  1. Time-based rotation
  2. Date-based rotation (future)
  3. Cleanup/orphan removal

File Structure Changes

plugins/static-image/
├── manager.py              # Enhanced with rotation logic
├── config_schema.json      # Updated with upload/rotation fields
├── manifest.json           # No changes
└── README.md               # Update documentation

web_interface/
├── blueprints/
│   └── api_v3.py           # Add upload/delete/list endpoints
└── templates/v3/
    └── partials/
        └── plugins.html     # File upload widget

assets/
└── plugins/
    └── static-image/
        └── uploads/        # NEW - user uploaded images
            └── .metadata.json

Testing Checklist

  • Single image upload works
  • Multiple image upload works
  • File validation (type, size)
  • Sequential rotation cycles correctly
  • Random rotation works
  • Time-based rotation changes at intervals
  • Legacy config migration preserves existing images
  • Orphaned file cleanup on config save
  • Web UI displays upload widget correctly
  • Image preview shows before upload
  • Delete removes file and updates config
  • Error handling for missing/invalid files

Future Enhancements

  1. Date-based rotation: Display different images on specific dates
  2. Time-of-day rotation: Show images based on time ranges
  3. Transition effects: Fade between images
  4. Image filters: Apply effects (brightness, contrast)
  5. Bulk operations: Select multiple images for deletion
  6. Image organization: Folders/tags for images
  7. Remote images: Support URLs (with caching)