فهرست منبع

set effect color

tuanchris 3 ماه پیش
والد
کامیت
55f31a648d
4فایلهای تغییر یافته به همراه204 افزوده شده و 17 حذف شده
  1. 42 0
      main.py
  2. 55 3
      modules/led/dw_led_controller.py
  3. 89 14
      static/js/led-control.js
  4. 18 0
      templates/wled.html

+ 42 - 0
main.py

@@ -1497,6 +1497,48 @@ async def dw_leds_color(request: dict):
         logger.error(f"Failed to set DW LED color: {str(e)}")
         logger.error(f"Failed to set DW LED color: {str(e)}")
         raise HTTPException(status_code=500, detail=str(e))
         raise HTTPException(status_code=500, detail=str(e))
 
 
+@app.post("/api/dw_leds/colors")
+async def dw_leds_colors(request: dict):
+    """Set effect colors (color1, color2, color3)"""
+    if not state.led_controller or state.led_provider != "dw_leds":
+        raise HTTPException(status_code=400, detail="DW LEDs not configured")
+
+    # Parse colors from request
+    color1 = None
+    color2 = None
+    color3 = None
+
+    if "color1" in request:
+        c = request["color1"]
+        if isinstance(c, list) and len(c) == 3:
+            color1 = tuple(c)
+        else:
+            raise HTTPException(status_code=400, detail="color1 must be [R, G, B] array")
+
+    if "color2" in request:
+        c = request["color2"]
+        if isinstance(c, list) and len(c) == 3:
+            color2 = tuple(c)
+        else:
+            raise HTTPException(status_code=400, detail="color2 must be [R, G, B] array")
+
+    if "color3" in request:
+        c = request["color3"]
+        if isinstance(c, list) and len(c) == 3:
+            color3 = tuple(c)
+        else:
+            raise HTTPException(status_code=400, detail="color3 must be [R, G, B] array")
+
+    if not any([color1, color2, color3]):
+        raise HTTPException(status_code=400, detail="Must provide at least one color")
+
+    try:
+        controller = state.led_controller.get_controller()
+        return controller.set_colors(color1=color1, color2=color2, color3=color3)
+    except Exception as e:
+        logger.error(f"Failed to set DW LED colors: {str(e)}")
+        raise HTTPException(status_code=500, detail=str(e))
+
 @app.get("/api/dw_leds/effects")
 @app.get("/api/dw_leds/effects")
 async def dw_leds_effects():
 async def dw_leds_effects():
     """Get list of available effects"""
     """Get list of available effects"""

+ 55 - 3
modules/led/dw_led_controller.py

@@ -41,9 +41,9 @@ class DWLEDController:
         self._current_palette_id = 0
         self._current_palette_id = 0
         self._speed = speed
         self._speed = speed
         self._intensity = intensity
         self._intensity = intensity
-        self._color1 = (255, 0, 0)  # Red
-        self._color2 = (0, 0, 255)  # Blue
-        self._color3 = (0, 255, 0)  # Green
+        self._color1 = (255, 0, 0)  # Red (primary)
+        self._color2 = (0, 0, 0)  # Black (background/off)
+        self._color3 = (0, 0, 255)  # Blue (tertiary)
 
 
         # Threading
         # Threading
         self._pixels = None
         self._pixels = None
@@ -246,6 +246,58 @@ class DWLEDController:
             "message": "Color set"
             "message": "Color set"
         }
         }
 
 
+    def set_colors(self, color1: Optional[Tuple[int, int, int]] = None,
+                   color2: Optional[Tuple[int, int, int]] = None,
+                   color3: Optional[Tuple[int, int, int]] = None) -> Dict:
+        """
+        Set effect colors (does not change effect or auto-power on)
+
+        Args:
+            color1: Primary color RGB tuple (0-255)
+            color2: Secondary/background color RGB tuple (0-255)
+            color3: Tertiary color RGB tuple (0-255)
+
+        Returns:
+            Dict with status
+        """
+        if not self._initialized:
+            if not self._initialize_hardware():
+                return {"connected": False, "error": self._init_error or "Hardware not initialized"}
+
+        colors_set = []
+        with self._lock:
+            if color1 is not None:
+                self._color1 = color1
+                if self._segment:
+                    self._segment.colors[0] = rgb_to_color(*color1)
+                colors_set.append(f"color1={color1}")
+
+            if color2 is not None:
+                self._color2 = color2
+                if self._segment:
+                    self._segment.colors[1] = rgb_to_color(*color2)
+                colors_set.append(f"color2={color2}")
+
+            if color3 is not None:
+                self._color3 = color3
+                if self._segment:
+                    self._segment.colors[2] = rgb_to_color(*color3)
+                colors_set.append(f"color3={color3}")
+
+            # Reset effect to apply new colors
+            if self._segment and colors_set:
+                self._segment.reset()
+
+        return {
+            "connected": True,
+            "colors": {
+                "color1": self._color1,
+                "color2": self._color2,
+                "color3": self._color3
+            },
+            "message": f"Colors updated: {', '.join(colors_set)}"
+        }
+
     def set_effect(self, effect_id: int, speed: Optional[int] = None,
     def set_effect(self, effect_id: int, speed: Optional[int] = None,
                    intensity: Optional[int] = None) -> Dict:
                    intensity: Optional[int] = None) -> Dict:
         """
         """

+ 89 - 14
static/js/led-control.js

@@ -156,6 +156,19 @@ async function initializeDWLedsControls() {
         });
         });
     });
     });
 
 
+    // Effect color pickers - apply immediately on change
+    document.querySelectorAll('.effect-color-picker').forEach(picker => {
+        picker.addEventListener('change', async () => {
+            const color1 = document.getElementById('dw-leds-color1')?.value;
+            const color2 = document.getElementById('dw-leds-color2')?.value;
+            const color3 = document.getElementById('dw-leds-color3')?.value;
+
+            if (color1 && color2 && color3) {
+                await applyAllColors(color1, color2, color3);
+            }
+        });
+    });
+
     // Effect selector
     // Effect selector
     document.getElementById('dw-leds-effect-select')?.addEventListener('change', async (e) => {
     document.getElementById('dw-leds-effect-select')?.addEventListener('change', async (e) => {
         const effectId = parseInt(e.target.value);
         const effectId = parseInt(e.target.value);
@@ -173,6 +186,10 @@ async function initializeDWLedsControls() {
 
 
             if (data.connected) {
             if (data.connected) {
                 showStatus(`Effect changed`, 'success');
                 showStatus(`Effect changed`, 'success');
+                // Update power button state if backend auto-powered on
+                if (data.power_on !== undefined) {
+                    updatePowerButtonUI(data.power_on);
+                }
             } else {
             } else {
                 showStatus(data.error || 'Failed to set effect', 'error');
                 showStatus(data.error || 'Failed to set effect', 'error');
             }
             }
@@ -198,6 +215,10 @@ async function initializeDWLedsControls() {
 
 
             if (data.connected) {
             if (data.connected) {
                 showStatus(`Palette changed`, 'success');
                 showStatus(`Palette changed`, 'success');
+                // Update power button state if backend auto-powered on
+                if (data.power_on !== undefined) {
+                    updatePowerButtonUI(data.power_on);
+                }
             } else {
             } else {
                 showStatus(data.error || 'Failed to set palette', 'error');
                 showStatus(data.error || 'Failed to set palette', 'error');
             }
             }
@@ -308,6 +329,10 @@ async function applyColor(hexColor) {
 
 
         if (data.connected) {
         if (data.connected) {
             showStatus(`Color set to ${hexColor.toUpperCase()}`, 'success');
             showStatus(`Color set to ${hexColor.toUpperCase()}`, 'success');
+            // Update power button state if backend auto-powered on
+            if (data.power_on !== undefined) {
+                updatePowerButtonUI(data.power_on);
+            }
         } else {
         } else {
             showStatus(data.error || 'Failed to set color', 'error');
             showStatus(data.error || 'Failed to set color', 'error');
         }
         }
@@ -316,6 +341,51 @@ async function applyColor(hexColor) {
     }
     }
 }
 }
 
 
+// Helper function to apply all effect colors
+async function applyAllColors(hexColor1, hexColor2, hexColor3) {
+    try {
+        const payload = {};
+
+        if (hexColor1) {
+            const r = parseInt(hexColor1.slice(1, 3), 16);
+            const g = parseInt(hexColor1.slice(3, 5), 16);
+            const b = parseInt(hexColor1.slice(5, 7), 16);
+            payload.color1 = [r, g, b];
+        }
+
+        if (hexColor2) {
+            const r = parseInt(hexColor2.slice(1, 3), 16);
+            const g = parseInt(hexColor2.slice(3, 5), 16);
+            const b = parseInt(hexColor2.slice(5, 7), 16);
+            payload.color2 = [r, g, b];
+        }
+
+        if (hexColor3) {
+            const r = parseInt(hexColor3.slice(1, 3), 16);
+            const g = parseInt(hexColor3.slice(3, 5), 16);
+            const b = parseInt(hexColor3.slice(5, 7), 16);
+            payload.color3 = [r, g, b];
+        }
+
+        const response = await fetch('/api/dw_leds/colors', {
+            method: 'POST',
+            headers: { 'Content-Type': 'application/json' },
+            body: JSON.stringify(payload)
+        });
+
+        if (!response.ok) throw new Error(`HTTP ${response.status}`);
+        const data = await response.json();
+
+        if (data.connected) {
+            showStatus(`Effect colors updated`, 'success');
+        } else {
+            showStatus(data.error || 'Failed to set colors', 'error');
+        }
+    } catch (error) {
+        showStatus(`Failed to set colors: ${error.message}`, 'error');
+    }
+}
+
 // Load available effects and palettes
 // Load available effects and palettes
 async function loadEffectsAndPalettes() {
 async function loadEffectsAndPalettes() {
     try {
     try {
@@ -340,7 +410,7 @@ async function loadEffectsAndPalettes() {
             // Add effects to automation selectors
             // Add effects to automation selectors
             if (idleEffectSelect && effectsData.effects) {
             if (idleEffectSelect && effectsData.effects) {
                 idleEffectSelect.innerHTML = '<option value="off">Off</option>';
                 idleEffectSelect.innerHTML = '<option value="off">Off</option>';
-                effectsData.effects.forEach(([id, name]) => {
+                effectsData.effects.forEach(([, name]) => {
                     const option = document.createElement('option');
                     const option = document.createElement('option');
                     option.value = name.toLowerCase();
                     option.value = name.toLowerCase();
                     option.textContent = name;
                     option.textContent = name;
@@ -350,7 +420,7 @@ async function loadEffectsAndPalettes() {
 
 
             if (playingEffectSelect && effectsData.effects) {
             if (playingEffectSelect && effectsData.effects) {
                 playingEffectSelect.innerHTML = '<option value="off">Off</option>';
                 playingEffectSelect.innerHTML = '<option value="off">Off</option>';
-                effectsData.effects.forEach(([id, name]) => {
+                effectsData.effects.forEach(([, name]) => {
                     const option = document.createElement('option');
                     const option = document.createElement('option');
                     option.value = name.toLowerCase();
                     option.value = name.toLowerCase();
                     option.textContent = name;
                     option.textContent = name;
@@ -393,6 +463,22 @@ async function loadEffectsAndPalettes() {
     }
     }
 }
 }
 
 
+// Helper function to update power button UI based on power state
+function updatePowerButtonUI(powerOn) {
+    const powerButton = document.getElementById('dw-leds-power-toggle');
+    const powerButtonText = document.getElementById('dw-leds-power-text');
+
+    if (powerButton && powerButtonText) {
+        if (powerOn) {
+            powerButton.className = 'flex items-center justify-center gap-2 rounded-lg bg-red-600 px-4 py-3 text-sm font-semibold text-white shadow-md hover:bg-red-700 transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-red-400 focus:ring-offset-2';
+            powerButtonText.textContent = 'Turn OFF';
+        } else {
+            powerButton.className = 'flex items-center justify-center gap-2 rounded-lg bg-green-600 px-4 py-3 text-sm font-semibold text-white shadow-md hover:bg-green-700 transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-green-400 focus:ring-offset-2';
+            powerButtonText.textContent = 'Turn ON';
+        }
+    }
+}
+
 // Check DW LEDs connection status
 // Check DW LEDs connection status
 async function checkDWLedsStatus() {
 async function checkDWLedsStatus() {
     try {
     try {
@@ -406,18 +492,7 @@ async function checkDWLedsStatus() {
             showStatus(`Connected: ${data.num_leds} LEDs on GPIO ${data.gpio_pin} - Power: ${powerState}`, 'success');
             showStatus(`Connected: ${data.num_leds} LEDs on GPIO ${data.gpio_pin} - Power: ${powerState}`, 'success');
 
 
             // Update power button appearance
             // Update power button appearance
-            const powerButton = document.getElementById('dw-leds-power-toggle');
-            const powerButtonText = document.getElementById('dw-leds-power-text');
-
-            if (powerButton && powerButtonText) {
-                if (data.power_on) {
-                    powerButton.className = 'flex items-center justify-center gap-2 rounded-lg bg-red-600 px-4 py-3 text-sm font-semibold text-white shadow-md hover:bg-red-700 transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-red-400 focus:ring-offset-2';
-                    powerButtonText.textContent = 'Turn OFF';
-                } else {
-                    powerButton.className = 'flex items-center justify-center gap-2 rounded-lg bg-green-600 px-4 py-3 text-sm font-semibold text-white shadow-md hover:bg-green-700 transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-green-400 focus:ring-offset-2';
-                    powerButtonText.textContent = 'Turn ON';
-                }
-            }
+            updatePowerButtonUI(data.power_on);
 
 
             // Update slider values
             // Update slider values
             const brightnessSlider = document.getElementById('dw-leds-brightness');
             const brightnessSlider = document.getElementById('dw-leds-brightness');

+ 18 - 0
templates/wled.html

@@ -235,6 +235,23 @@
         </div>
         </div>
       </div>
       </div>
 
 
+      <!-- Effect Color Slots -->
+      <div class="flex items-center gap-4">
+        <h3 class="text-slate-800 text-base font-semibold">Effect Colors:</h3>
+        <div class="flex items-center gap-2">
+          <label class="text-xs font-medium text-slate-600">Slot 1</label>
+          <input type="color" id="dw-leds-color1" value="#ff0000" class="w-14 h-14 rounded-lg border-2 border-slate-300 cursor-pointer effect-color-picker">
+        </div>
+        <div class="flex items-center gap-2">
+          <label class="text-xs font-medium text-slate-600">Slot 2</label>
+          <input type="color" id="dw-leds-color2" value="#000000" class="w-14 h-14 rounded-lg border-2 border-slate-300 cursor-pointer effect-color-picker">
+        </div>
+        <div class="flex items-center gap-2">
+          <label class="text-xs font-medium text-slate-600">Slot 3</label>
+          <input type="color" id="dw-leds-color3" value="#0000ff" class="w-14 h-14 rounded-lg border-2 border-slate-300 cursor-pointer effect-color-picker">
+        </div>
+      </div>
+
       <!-- Effect Settings -->
       <!-- Effect Settings -->
       <div class="flex flex-col gap-4 pt-4 border-t border-slate-200">
       <div class="flex flex-col gap-4 pt-4 border-t border-slate-200">
         <h3 class="text-slate-800 text-base font-semibold">Automation Settings</h3>
         <h3 class="text-slate-800 text-base font-semibold">Automation Settings</h3>
@@ -265,6 +282,7 @@
       </div>
       </div>
     </div>
     </div>
   </section>
   </section>
+
 </div>
 </div>
 
 
 <script src="/static/js/led-control.js"></script>
 <script src="/static/js/led-control.js"></script>