فهرست منبع

Set custom speed for clear pattern

tuanchris 5 ماه پیش
والد
کامیت
503ece3e09
5فایلهای تغییر یافته به همراه145 افزوده شده و 6 حذف شده
  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)}")
         logger.error(f"Failed to set custom clear patterns: {str(e)}")
         raise HTTPException(status_code=500, detail=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")
 @app.post("/preview_thr_batch")
 async def preview_thr_batch(request: dict):
 async def preview_thr_batch(request: dict):
     start = time.time()
     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
                 state.execution_progress = None
             return
             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)
         state.execution_progress = (0, total_coordinates, None, 0)
         
         
         # stop actions without resetting the playlist
         # 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:
                     if state.led_controller:
                         effect_playing(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
                 # Update progress for all coordinates including the first one
                 pbar.update(1)
                 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
         # Ensure we still update machine position even if there's an error
         connection_manager.update_machine_position()
         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,
     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. 
     and translate the motion to gcode jog command and sent to grbl. 
@@ -510,6 +519,7 @@ def move_polar(theta, rho):
     Args:
     Args:
         theta (_type_): _description_
         theta (_type_): _description_
         rho (_type_): _description_
         rho (_type_): _description_
+        speed (int, optional): Speed override. If None, uses state.speed
     """
     """
     # Adding soft limit to reduce hardware sound
     # Adding soft limit to reduce hardware sound
     # soft_limit_inner = 0.01
     # soft_limit_inner = 0.01
@@ -545,9 +555,12 @@ def move_polar(theta, rho):
     new_x_abs = state.machine_x + x_increment
     new_x_abs = state.machine_x + x_increment
     new_y_abs = state.machine_y + y_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_theta = theta
     state.current_rho = rho
     state.current_rho = rho
     state.machine_x = new_x_abs
     state.machine_x = new_x_abs

+ 11 - 0
modules/core/state.py

@@ -46,6 +46,7 @@ class AppState:
         self._playlist_mode = "loop"
         self._playlist_mode = "loop"
         self._pause_time = 0
         self._pause_time = 0
         self._clear_pattern = "none"
         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_in = None  # Custom clear from center pattern
         self.custom_clear_from_out = None  # Custom clear from perimeter pattern
         self.custom_clear_from_out = None  # Custom clear from perimeter pattern
         self.load()
         self.load()
@@ -135,6 +136,14 @@ class AppState:
     @clear_pattern.setter
     @clear_pattern.setter
     def clear_pattern(self, value):
     def clear_pattern(self, value):
         self._clear_pattern = 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):
     def to_dict(self):
         """Return a dictionary representation of the state."""
         """Return a dictionary representation of the state."""
@@ -159,6 +168,7 @@ class AppState:
             "playlist_mode": self._playlist_mode,
             "playlist_mode": self._playlist_mode,
             "pause_time": self._pause_time,
             "pause_time": self._pause_time,
             "clear_pattern": self._clear_pattern,
             "clear_pattern": self._clear_pattern,
+            "clear_pattern_speed": self._clear_pattern_speed,
             "custom_clear_from_in": self.custom_clear_from_in,
             "custom_clear_from_in": self.custom_clear_from_in,
             "custom_clear_from_out": self.custom_clear_from_out,
             "custom_clear_from_out": self.custom_clear_from_out,
             "port": self.port,
             "port": self.port,
@@ -187,6 +197,7 @@ class AppState:
         self._playlist_mode = data.get("playlist_mode", "loop")
         self._playlist_mode = data.get("playlist_mode", "loop")
         self._pause_time = data.get("pause_time", 0)
         self._pause_time = data.get("pause_time", 0)
         self._clear_pattern = data.get("clear_pattern", "none")
         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_in = data.get("custom_clear_from_in", None)
         self.custom_clear_from_out = data.get("custom_clear_from_out", None)
         self.custom_clear_from_out = data.get("custom_clear_from_out", None)
         self.port = data.get("port", 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(() => []),
         fetch('/list_theta_rho_files').then(response => response.json()).catch(() => []),
         
         
         // Load current custom clear patterns
         // 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
         // Update connection status
         setCachedConnectionStatus(statusData);
         setCachedConnectionStatus(statusData);
         updateConnectionUI(statusData);
         updateConnectionUI(statusData);
@@ -268,6 +271,12 @@ document.addEventListener('DOMContentLoaded', async () => {
             
             
             console.log('Autocomplete initialized with', patterns.length, 'patterns');
             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 => {
     }).catch(error => {
         logMessage(`Error initializing settings page: ${error.message}`, LOG_TYPE.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
 // Button click handlers

+ 37 - 0
templates/settings.html

@@ -262,6 +262,43 @@ endblock %}
       </div>
       </div>
     </div>
     </div>
   </section>
   </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">
   <section class="bg-white rounded-xl shadow-sm overflow-hidden">
     <h2
     <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"
       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"