Add LED device abstraction layer for multi-controller support

Introduce abstract LEDClient base class with factory pattern so new
LED controller types can plug in alongside WLED. ProcessorManager is
now fully type-agnostic — all device-specific logic (health checks,
state snapshot/restore, fast send) lives behind the LEDClient interface.

- New led_client.py: LEDClient ABC, DeviceHealth, factory functions
- WLEDClient inherits LEDClient, encapsulates WLED health checks and state management
- device_type field on Device storage model (defaults to "wled")
- Rename target_type "wled" → "led" with backward-compat migration
- Frontend: "WLED" tab → "LED", device type badge, type selector in
  add-device modal, device type shown in target device dropdown
- All wled_* API fields renamed to device_* for generic naming

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 12:41:02 +03:00
parent afce183f79
commit b5a6885126
18 changed files with 667 additions and 346 deletions

View File

@@ -7,7 +7,7 @@
"auth.login": "Login",
"auth.logout": "Logout",
"auth.authenticated": "● Authenticated",
"auth.title": "Login to WLED Controller",
"auth.title": "Login to LED Grab",
"auth.message": "Please enter your API key to authenticate and access the LED Grab.",
"auth.label": "API Key:",
"auth.placeholder": "Enter your API key...",
@@ -101,13 +101,16 @@
"devices.wled_webui_link": "WLED Web UI",
"devices.wled_note_webui": "(open your device's IP in a browser).",
"devices.wled_note2": "This controller sends pixel color data and controls brightness per device.",
"device.type": "Device Type:",
"device.type.hint": "Select the type of LED controller",
"device.url.hint": "IP address or hostname of the device (e.g. http://192.168.1.100)",
"device.name": "Device Name:",
"device.name.placeholder": "Living Room TV",
"device.url": "URL:",
"device.url.placeholder": "http://192.168.1.100",
"device.led_count": "LED Count:",
"device.led_count.hint": "Number of LEDs configured in your WLED device",
"device.led_count.hint.auto": "Auto-detected from WLED device",
"device.led_count.hint": "Number of LEDs configured in the device",
"device.led_count.hint.auto": "Auto-detected from device",
"device.button.add": "Add Device",
"device.button.start": "Start",
"device.button.stop": "Stop",
@@ -115,7 +118,7 @@
"device.button.capture_settings": "Capture Settings",
"device.button.calibrate": "Calibrate",
"device.button.remove": "Remove",
"device.button.webui": "Open WLED Web UI",
"device.button.webui": "Open Device Web UI",
"device.status.connected": "Connected",
"device.status.disconnected": "Disconnected",
"device.status.error": "Error",
@@ -136,26 +139,26 @@
"device.metrics.frames_skipped": "Skipped",
"device.metrics.keepalive": "Keepalive",
"device.metrics.errors": "Errors",
"device.health.online": "WLED Online",
"device.health.offline": "WLED Offline",
"device.health.online": "Online",
"device.health.offline": "Offline",
"device.health.checking": "Checking...",
"device.tutorial.start": "Start tutorial",
"device.tip.metadata": "Device info (LED count, type, color channels) is auto-detected from WLED",
"device.tip.metadata": "Device info (LED count, type, color channels) is auto-detected from the device",
"device.tip.brightness": "Slide to adjust device brightness",
"device.tip.start": "Start or stop screen capture processing",
"device.tip.settings": "Configure general device settings (name, URL, health check)",
"device.tip.capture_settings": "Configure capture settings (display, capture template)",
"device.tip.calibrate": "Calibrate LED positions, direction, and coverage",
"device.tip.webui": "Open WLED's built-in web interface for advanced configuration",
"device.tip.add": "Click here to add a new WLED device",
"device.tip.webui": "Open the device's built-in web interface for advanced configuration",
"device.tip.add": "Click here to add a new LED device",
"settings.title": "Device Settings",
"settings.general.title": "General Settings",
"settings.capture.title": "Capture Settings",
"settings.capture.saved": "Capture settings updated",
"settings.capture.failed": "Failed to save capture settings",
"settings.brightness": "Brightness:",
"settings.brightness.hint": "Global brightness for this WLED device (0-100%)",
"settings.url.hint": "IP address or hostname of your WLED device",
"settings.brightness.hint": "Global brightness for this device (0-100%)",
"settings.url.hint": "IP address or hostname of the device",
"settings.display_index": "Display:",
"settings.display_index.hint": "Which screen to capture for this device",
"settings.fps": "Target FPS:",
@@ -164,7 +167,7 @@
"settings.capture_template.hint": "Screen capture engine and configuration for this device",
"settings.button.cancel": "Cancel",
"settings.health_interval": "Health Check Interval (s):",
"settings.health_interval.hint": "How often to check the WLED device status (5-600 seconds)",
"settings.health_interval.hint": "How often to check the device status (5-600 seconds)",
"settings.button.save": "Save Changes",
"settings.saved": "Settings saved successfully",
"settings.failed": "Failed to save settings",
@@ -176,7 +179,9 @@
"calibration.tip.span": "Drag green bars to adjust coverage span",
"calibration.tip.test": "Click an edge to toggle test LEDs",
"calibration.tip.toggle_inputs": "Click total LED count to toggle edge inputs",
"calibration.tip.skip_leds": "Skip LEDs at the start or end of the strip — skipped LEDs stay off",
"calibration.tip.border_width": "How many pixels from the screen edge to sample for LED colors",
"calibration.tip.skip_leds_start": "Skip LEDs at the start of the strip — skipped LEDs stay off",
"calibration.tip.skip_leds_end": "Skip LEDs at the end of the strip — skipped LEDs stay off",
"calibration.tutorial.start": "Start tutorial",
"calibration.start_position": "Starting Position:",
"calibration.position.bottom_left": "Bottom Left",
@@ -196,6 +201,8 @@
"calibration.skip_start.hint": "Number of LEDs to turn off at the beginning of the strip (0 = none)",
"calibration.skip_end": "Skip LEDs (End):",
"calibration.skip_end.hint": "Number of LEDs to turn off at the end of the strip (0 = none)",
"calibration.border_width": "Border (px):",
"calibration.border_width.hint": "How many pixels from the screen edge to sample for LED colors (1-100)",
"calibration.button.cancel": "Cancel",
"calibration.button.save": "Save",
"calibration.saved": "Calibration saved successfully",
@@ -313,7 +320,8 @@
"streams.validate_image.invalid": "Image not accessible",
"targets.title": "⚡ Targets",
"targets.description": "Targets bridge picture sources to output devices. Each target references a device and a source, with its own processing settings.",
"targets.subtab.wled": "WLED",
"targets.subtab.wled": "LED",
"targets.subtab.led": "LED",
"targets.section.devices": "💡 Devices",
"targets.section.targets": "⚡ Targets",
"targets.add": "Add Target",
@@ -324,7 +332,7 @@
"targets.name": "Target Name:",
"targets.name.placeholder": "My Target",
"targets.device": "Device:",
"targets.device.hint": "Which WLED device to send LED data to",
"targets.device.hint": "Select the LED device to send data to",
"targets.device.none": "-- Select a device --",
"targets.source": "Source:",
"targets.source.hint": "Which picture source to capture and process",
@@ -341,7 +349,7 @@
"targets.smoothing": "Smoothing:",
"targets.smoothing.hint": "Temporal blending between frames (0=none, 1=full). Reduces flicker.",
"targets.standby_interval": "Standby Interval:",
"targets.standby_interval.hint": "How often to resend the last frame when the screen is static, keeping WLED in live mode (0.5-5.0s)",
"targets.standby_interval.hint": "How often to resend the last frame when the screen is static, keeping the device in live mode (0.5-5.0s)",
"targets.created": "Target created successfully",
"targets.updated": "Target updated successfully",
"targets.deleted": "Target deleted successfully",