Procházet zdrojové kódy

Set custom speed for clear pattern

tuanchris před 5 měsíci
rodič
revize
503ece3e09
5 změnil soubory, kde provedl 145 přidání a 6 odebrání
  1. 32 0
      main.py
  2. 17 4
      modules/core/pattern_manager.py
  3. 11 0
      modules/core/state.py
  4. 48 2
      static/js/settings.js
  5. 37 0
      templates/settings.html

+ 32 - 0
main.py

@@ -825,6 +825,38 @@ async def set_custom_clear_patterns(request: dict):
         logger.error(f"Failed to set custom clear patterns: {str(e)}")
         raise HTTPException(status_code=500, detail=str(e))
 
+@app.get("/api/clear_pattern_speed")
+async def get_clear_pattern_speed():
+    """Get the current clearing pattern speed setting."""
+    return {
+        "success": True,
+        "clear_pattern_speed": state.clear_pattern_speed
+    }
+
+@app.post("/api/clear_pattern_speed")
+async def set_clear_pattern_speed(request: dict):
+    """Set the clearing pattern speed."""
+    try:
+        speed = int(request.get("clear_pattern_speed", 200))
+        
+        # Validate speed range (same as regular speed limits)
+        if not (50 <= speed <= 2000):
+            raise HTTPException(status_code=400, detail="Speed must be between 50 and 2000")
+        
+        state.clear_pattern_speed = speed
+        state.save()
+        
+        logger.info(f"Clear pattern speed updated to {speed}")
+        return {
+            "success": True,
+            "clear_pattern_speed": state.clear_pattern_speed
+        }
+    except ValueError:
+        raise HTTPException(status_code=400, detail="Invalid speed value")
+    except Exception as e:
+        logger.error(f"Failed to set clear pattern speed: {str(e)}")
+        raise HTTPException(status_code=500, detail=str(e))
+
 @app.post("/preview_thr_batch")
 async def preview_thr_batch(request: dict):
     start = time.time()

+ 17 - 4
modules/core/pattern_manager.py

@@ -256,6 +256,15 @@ async def run_theta_rho_file(file_path, is_playlist=False):
                 state.execution_progress = None
             return
 
+        # Determine if this is a clearing pattern and set appropriate speed
+        is_clear_file = is_clear_pattern(file_path)
+        pattern_speed = state.clear_pattern_speed if is_clear_file else state.speed
+        
+        if is_clear_file:
+            logger.info(f"Running clearing pattern at speed {pattern_speed}")
+        else:
+            logger.info(f"Running normal pattern at speed {pattern_speed}")
+
         state.execution_progress = (0, total_coordinates, None, 0)
         
         # stop actions without resetting the playlist
@@ -304,7 +313,7 @@ async def run_theta_rho_file(file_path, is_playlist=False):
                     if state.led_controller:
                         effect_playing(state.led_controller)
 
-                move_polar(theta, rho)
+                move_polar(theta, rho, pattern_speed)
                 
                 # Update progress for all coordinates including the first one
                 pbar.update(1)
@@ -496,7 +505,7 @@ def stop_actions(clear_playlist = True):
         # Ensure we still update machine position even if there's an error
         connection_manager.update_machine_position()
 
-def move_polar(theta, rho):
+def move_polar(theta, rho, speed=None):
     """
     This functions take in a pair of theta rho coordinate, compute the distance to travel based on current theta, rho,
     and translate the motion to gcode jog command and sent to grbl. 
@@ -510,6 +519,7 @@ def move_polar(theta, rho):
     Args:
         theta (_type_): _description_
         rho (_type_): _description_
+        speed (int, optional): Speed override. If None, uses state.speed
     """
     # Adding soft limit to reduce hardware sound
     # soft_limit_inner = 0.01
@@ -545,9 +555,12 @@ def move_polar(theta, rho):
     new_x_abs = state.machine_x + x_increment
     new_y_abs = state.machine_y + y_increment
     
-    # dynamic_speed = compute_dynamic_speed(rho, max_speed=state.speed)
+    # Use provided speed or fall back to state.speed
+    actual_speed = speed if speed is not None else state.speed
+    
+    # dynamic_speed = compute_dynamic_speed(rho, max_speed=actual_speed)
     
-    connection_manager.send_grbl_coordinates(round(new_x_abs, 3), round(new_y_abs,3), state.speed)
+    connection_manager.send_grbl_coordinates(round(new_x_abs, 3), round(new_y_abs,3), actual_speed)
     state.current_theta = theta
     state.current_rho = rho
     state.machine_x = new_x_abs

+ 11 - 0
modules/core/state.py

@@ -46,6 +46,7 @@ class AppState:
         self._playlist_mode = "loop"
         self._pause_time = 0
         self._clear_pattern = "none"
+        self._clear_pattern_speed = 200  # Default speed for clearing patterns
         self.custom_clear_from_in = None  # Custom clear from center pattern
         self.custom_clear_from_out = None  # Custom clear from perimeter pattern
         self.load()
@@ -135,6 +136,14 @@ class AppState:
     @clear_pattern.setter
     def clear_pattern(self, value):
         self._clear_pattern = value
+        
+    @property
+    def clear_pattern_speed(self):
+        return self._clear_pattern_speed
+
+    @clear_pattern_speed.setter
+    def clear_pattern_speed(self, value):
+        self._clear_pattern_speed = value
 
     def to_dict(self):
         """Return a dictionary representation of the state."""
@@ -159,6 +168,7 @@ class AppState:
             "playlist_mode": self._playlist_mode,
             "pause_time": self._pause_time,
             "clear_pattern": self._clear_pattern,
+            "clear_pattern_speed": self._clear_pattern_speed,
             "custom_clear_from_in": self.custom_clear_from_in,
             "custom_clear_from_out": self.custom_clear_from_out,
             "port": self.port,
@@ -187,6 +197,7 @@ class AppState:
         self._playlist_mode = data.get("playlist_mode", "loop")
         self._pause_time = data.get("pause_time", 0)
         self._clear_pattern = data.get("clear_pattern", "none")
+        self._clear_pattern_speed = data.get("clear_pattern_speed", 200)
         self.custom_clear_from_in = data.get("custom_clear_from_in", None)
         self.custom_clear_from_out = data.get("custom_clear_from_out", None)
         self.port = data.get("port", None)

+ 48 - 2
static/js/settings.js

@@ -174,8 +174,11 @@ document.addEventListener('DOMContentLoaded', async () => {
         fetch('/list_theta_rho_files').then(response => response.json()).catch(() => []),
         
         // Load current custom clear patterns
-        fetch('/api/custom_clear_patterns').then(response => response.json()).catch(() => ({ custom_clear_from_in: null, custom_clear_from_out: null }))
-    ]).then(([statusData, wledData, updateData, ports, patterns, clearPatterns]) => {
+        fetch('/api/custom_clear_patterns').then(response => response.json()).catch(() => ({ custom_clear_from_in: null, custom_clear_from_out: null })),
+        
+        // Load current clear pattern speed
+        fetch('/api/clear_pattern_speed').then(response => response.json()).catch(() => ({ clear_pattern_speed: 200 }))
+    ]).then(([statusData, wledData, updateData, ports, patterns, clearPatterns, clearSpeedData]) => {
         // Update connection status
         setCachedConnectionStatus(statusData);
         updateConnectionUI(statusData);
@@ -268,6 +271,12 @@ document.addEventListener('DOMContentLoaded', async () => {
             
             console.log('Autocomplete initialized with', patterns.length, 'patterns');
         }
+        
+        // Set clear pattern speed
+        const clearPatternSpeedInput = document.getElementById('clearPatternSpeedInput');
+        if (clearPatternSpeedInput && clearSpeedData && clearSpeedData.clear_pattern_speed) {
+            clearPatternSpeedInput.value = clearSpeedData.clear_pattern_speed;
+        }
     }).catch(error => {
         logMessage(`Error initializing settings page: ${error.message}`, LOG_TYPE.ERROR);
     });
@@ -454,6 +463,43 @@ function setupEventListeners() {
             }
         });
     }
+    
+    // Save clear pattern speed button
+    const saveClearSpeed = document.getElementById('saveClearSpeed');
+    if (saveClearSpeed) {
+        saveClearSpeed.addEventListener('click', async () => {
+            const clearPatternSpeedInput = document.getElementById('clearPatternSpeedInput');
+            
+            if (!clearPatternSpeedInput) {
+                return;
+            }
+            
+            const speed = parseInt(clearPatternSpeedInput.value);
+            
+            // Validate speed
+            if (isNaN(speed) || speed < 50 || speed > 2000) {
+                showStatusMessage('Clear pattern speed must be between 50 and 2000', 'error');
+                return;
+            }
+            
+            try {
+                const response = await fetch('/api/clear_pattern_speed', {
+                    method: 'POST',
+                    headers: { 'Content-Type': 'application/json' },
+                    body: JSON.stringify({ clear_pattern_speed: speed })
+                });
+                
+                if (response.ok) {
+                    showStatusMessage('Clear pattern speed saved successfully', 'success');
+                } else {
+                    const error = await response.json();
+                    throw new Error(error.detail || 'Failed to save clear pattern speed');
+                }
+            } catch (error) {
+                showStatusMessage(`Failed to save clear pattern speed: ${error.message}`, 'error');
+            }
+        });
+    }
 }
 
 // Button click handlers

+ 37 - 0
templates/settings.html

@@ -262,6 +262,43 @@ endblock %}
       </div>
     </div>
   </section>
+  <section class="bg-white rounded-xl shadow-sm overflow-hidden">
+    <h2
+      class="text-slate-800 text-xl sm:text-2xl font-semibold leading-tight tracking-[-0.01em] px-6 py-4 border-b border-slate-200"
+    >
+      Clearing Pattern Speed
+    </h2>
+    <div class="px-6 py-5 space-y-6">
+      <p class="text-sm text-slate-600">
+        Set a custom speed for clearing patterns. This allows you to run clearing patterns at a different speed than regular patterns. If this is set, the speed will be used but won't be updated in the pattern preivew. 
+      </p>
+      
+      <div class="flex flex-col gap-1.5">
+        <label for="clearPatternSpeedInput" class="text-slate-700 text-sm font-medium leading-normal">
+          Clearing Speed (steps per minute)
+        </label>
+        <div class="flex gap-3 items-center">
+          <input
+            id="clearPatternSpeedInput"
+            type="number"
+            min="50"
+            max="2000"
+            step="50"
+            class="form-input flex-1 resize-none overflow-hidden rounded-lg text-slate-900 focus:outline-0 focus:ring-2 focus:ring-sky-500 border border-slate-300 bg-white focus:border-sky-500 h-10 placeholder:text-slate-400 px-4 text-base font-normal leading-normal transition-colors"
+            placeholder="200"
+            value=""
+          />
+          <button
+            id="saveClearSpeed"
+            class="flex items-center justify-center gap-2 min-w-[120px] cursor-pointer rounded-lg h-10 px-4 bg-sky-600 hover:bg-sky-700 text-white text-sm font-medium leading-normal tracking-[0.015em] transition-colors"
+          >
+            <span class="material-icons text-lg">save</span>
+            <span class="truncate">Save Speed</span>
+          </button>
+        </div>
+      </div>
+    </div>
+  </section>
   <section class="bg-white rounded-xl shadow-sm overflow-hidden">
     <h2
       class="text-slate-800 text-xl sm:text-2xl font-semibold leading-tight tracking-[-0.01em] px-6 py-4 border-b border-slate-200"