فهرست منبع

add preferred port

tuanchris 2 ماه پیش
والد
کامیت
a20140630a
5فایلهای تغییر یافته به همراه244 افزوده شده و 17 حذف شده
  1. 28 1
      main.py
  2. 11 2
      modules/connection/connection_manager.py
  3. 3 0
      modules/core/state.py
  4. 171 14
      static/js/settings.js
  5. 31 0
      templates/settings.html

+ 28 - 1
main.py

@@ -1082,7 +1082,34 @@ async def serial_status():
     logger.debug(f"Serial status check - connected: {connected}, port: {port}")
     return {
         "connected": connected,
-        "port": port
+        "port": port,
+        "preferred_port": state.preferred_port
+    }
+
+@app.get("/api/preferred-port")
+async def get_preferred_port():
+    """Get the currently configured preferred port for auto-connect."""
+    return {
+        "preferred_port": state.preferred_port
+    }
+
+@app.post("/api/preferred-port")
+async def set_preferred_port(request: Request):
+    """Set the preferred port for auto-connect."""
+    data = await request.json()
+    preferred_port = data.get("preferred_port")
+
+    # Allow setting to None to clear the preference
+    if preferred_port == "" or preferred_port == "none":
+        preferred_port = None
+
+    state.preferred_port = preferred_port
+    state.save()
+
+    logger.info(f"Preferred port set to: {preferred_port}")
+    return {
+        "success": True,
+        "preferred_port": state.preferred_port
     }
 
 @app.post("/pause_execution")

+ 11 - 2
modules/connection/connection_manager.py

@@ -220,12 +220,21 @@ def connect_device(homing=True):
 
     ports = list_serial_ports()
 
-    if state.port and state.port in ports:
+    # Priority for auto-connect:
+    # 1. Preferred port (user's explicit choice) if available
+    # 2. Last used port if available
+    # 3. First available port as fallback
+    if state.preferred_port and state.preferred_port in ports:
+        logger.info(f"Connecting to preferred port: {state.preferred_port}")
+        state.conn = SerialConnection(state.preferred_port)
+    elif state.port and state.port in ports:
+        logger.info(f"Connecting to last used port: {state.port}")
         state.conn = SerialConnection(state.port)
     elif ports:
+        logger.info(f"Connecting to first available port: {ports[0]}")
         state.conn = SerialConnection(ports[0])
     else:
-        logger.error("Auto connect failed.")
+        logger.error("Auto connect failed: No serial ports available")
         # state.conn = WebSocketConnection('ws://fluidnc.local:81')
 
     if (state.conn.is_connected() if state.conn else False):

+ 3 - 0
modules/core/state.py

@@ -49,6 +49,7 @@ class AppState:
         self.mqtt_handler = None  # Will be set by the MQTT handler
         self.conn = None
         self.port = None
+        self.preferred_port = None  # User's preferred port for auto-connect
         self.wled_ip = None
         self.led_provider = "none"  # "wled", "dw_leds", or "none"
         self.led_controller = None
@@ -220,6 +221,7 @@ class AppState:
             "custom_clear_from_in": self.custom_clear_from_in,
             "custom_clear_from_out": self.custom_clear_from_out,
             "port": self.port,
+            "preferred_port": self.preferred_port,
             "wled_ip": self.wled_ip,
             "led_provider": self.led_provider,
             "dw_led_num_leds": self.dw_led_num_leds,
@@ -271,6 +273,7 @@ class AppState:
         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)
+        self.preferred_port = data.get("preferred_port", None)
         self.wled_ip = data.get('wled_ip', None)
         self.led_provider = data.get('led_provider', "none")
         self.dw_led_num_leds = data.get('dw_led_num_leds', 60)

+ 171 - 14
static/js/settings.js

@@ -112,17 +112,18 @@ async function updateSerialPorts() {
             const ports = await response.json();
             const portsElement = document.getElementById('availablePorts');
             const portSelect = document.getElementById('portSelect');
-            
+            const preferredPortSelect = document.getElementById('preferredPortSelect');
+
             if (portsElement) {
                 portsElement.textContent = ports.length > 0 ? ports.join(', ') : 'No ports available';
             }
-            
+
             if (portSelect) {
                 // Clear existing options except the first one
                 while (portSelect.options.length > 1) {
                     portSelect.remove(1);
                 }
-                
+
                 // Add new options
                 ports.forEach(port => {
                     const option = document.createElement('option');
@@ -141,12 +142,116 @@ async function updateSerialPorts() {
                     }
                 }
             }
+
+            // Also update the preferred port select dropdown
+            if (preferredPortSelect) {
+                // Store current selection
+                const currentPreferred = preferredPortSelect.value;
+
+                // Clear existing options except the first one (no preference)
+                while (preferredPortSelect.options.length > 1) {
+                    preferredPortSelect.remove(1);
+                }
+
+                // Add all available ports
+                ports.forEach(port => {
+                    const option = document.createElement('option');
+                    option.value = port;
+                    option.textContent = port;
+                    preferredPortSelect.appendChild(option);
+                });
+
+                // Restore selection if it's still available
+                if (currentPreferred && ports.includes(currentPreferred)) {
+                    preferredPortSelect.value = currentPreferred;
+                }
+            }
         }
     } catch (error) {
         logMessage(`Error fetching serial ports: ${error.message}`, LOG_TYPE.ERROR);
     }
 }
 
+// Function to load and display preferred port setting
+async function loadPreferredPort() {
+    try {
+        const response = await fetch('/api/preferred-port');
+        if (response.ok) {
+            const data = await response.json();
+            const preferredPortSelect = document.getElementById('preferredPortSelect');
+            const currentPreferredPort = document.getElementById('currentPreferredPort');
+            const preferredPortDisplay = document.getElementById('preferredPortDisplay');
+
+            if (preferredPortSelect && data.preferred_port) {
+                // Check if the preferred port is in the options
+                const optionExists = Array.from(preferredPortSelect.options).some(
+                    opt => opt.value === data.preferred_port
+                );
+
+                if (optionExists) {
+                    preferredPortSelect.value = data.preferred_port;
+                } else {
+                    // Add the preferred port as an option (it might not be currently available)
+                    const option = document.createElement('option');
+                    option.value = data.preferred_port;
+                    option.textContent = `${data.preferred_port} (not currently available)`;
+                    preferredPortSelect.appendChild(option);
+                    preferredPortSelect.value = data.preferred_port;
+                }
+            }
+
+            // Show current preferred port indicator
+            if (currentPreferredPort && preferredPortDisplay && data.preferred_port) {
+                preferredPortDisplay.textContent = `Currently set to: ${data.preferred_port}`;
+                currentPreferredPort.classList.remove('hidden');
+            } else if (currentPreferredPort) {
+                currentPreferredPort.classList.add('hidden');
+            }
+        }
+    } catch (error) {
+        logMessage(`Error loading preferred port: ${error.message}`, LOG_TYPE.ERROR);
+    }
+}
+
+// Function to save preferred port setting
+async function savePreferredPort() {
+    const preferredPortSelect = document.getElementById('preferredPortSelect');
+    if (!preferredPortSelect) return;
+
+    const preferredPort = preferredPortSelect.value || null;
+
+    try {
+        const response = await fetch('/api/preferred-port', {
+            method: 'POST',
+            headers: { 'Content-Type': 'application/json' },
+            body: JSON.stringify({ preferred_port: preferredPort })
+        });
+
+        if (response.ok) {
+            const data = await response.json();
+            const currentPreferredPort = document.getElementById('currentPreferredPort');
+            const preferredPortDisplay = document.getElementById('preferredPortDisplay');
+
+            if (data.preferred_port) {
+                showStatusMessage(`Preferred port set to: ${data.preferred_port}`, 'success');
+                if (currentPreferredPort && preferredPortDisplay) {
+                    preferredPortDisplay.textContent = `Currently set to: ${data.preferred_port}`;
+                    currentPreferredPort.classList.remove('hidden');
+                }
+            } else {
+                showStatusMessage('Preferred port cleared - will auto-detect on startup', 'success');
+                if (currentPreferredPort) {
+                    currentPreferredPort.classList.add('hidden');
+                }
+            }
+        } else {
+            throw new Error('Failed to save preferred port');
+        }
+    } catch (error) {
+        showStatusMessage(`Failed to save preferred port: ${error.message}`, 'error');
+    }
+}
+
 function setWledButtonState(isSet) {
     const saveWledConfig = document.getElementById('saveWledConfig');
     if (!saveWledConfig) return;
@@ -259,28 +364,31 @@ document.addEventListener('DOMContentLoaded', async () => {
 
         // Load LED configuration (replaces old WLED-only loading)
         fetch('/get_led_config').then(response => response.json()).catch(() => ({ provider: 'none', wled_ip: null })),
-        
+
         // Load current version and check for updates
         fetch('/api/version').then(response => response.json()).catch(() => ({ current: '1.0.0', latest: '1.0.0', update_available: false })),
-        
+
         // Load available serial ports
         fetch('/list_serial_ports').then(response => response.json()).catch(() => []),
-        
+
         // Load available pattern files for clear pattern selection
         getCachedPatternFiles().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 })),
-        
+
         // Load current clear pattern speed
         fetch('/api/clear_pattern_speed').then(response => response.json()).catch(() => ({ clear_pattern_speed: 200 })),
-        
+
         // Load current app name
         fetch('/api/app-name').then(response => response.json()).catch(() => ({ app_name: 'Dune Weaver' })),
 
         // Load Still Sands settings
-        fetch('/api/scheduled-pause').then(response => response.json()).catch(() => ({ enabled: false, time_slots: [] }))
-    ]).then(([statusData, ledConfigData, updateData, ports, patterns, clearPatterns, clearSpeedData, appNameData, scheduledPauseData]) => {
+        fetch('/api/scheduled-pause').then(response => response.json()).catch(() => ({ enabled: false, time_slots: [] })),
+
+        // Load preferred port setting
+        fetch('/api/preferred-port').then(response => response.json()).catch(() => ({ preferred_port: null }))
+    ]).then(([statusData, ledConfigData, updateData, ports, patterns, clearPatterns, clearSpeedData, appNameData, scheduledPauseData, preferredPortData]) => {
         // Update connection status
         setCachedConnectionStatus(statusData);
         updateConnectionUI(statusData);
@@ -357,7 +465,7 @@ document.addEventListener('DOMContentLoaded', async () => {
             while (portSelect.options.length > 1) {
                 portSelect.remove(1);
             }
-            
+
             // Add new options
             ports.forEach(port => {
                 const option = document.createElement('option');
@@ -371,7 +479,50 @@ document.addEventListener('DOMContentLoaded', async () => {
                 portSelect.value = ports[0];
             }
         }
-        
+
+        // Update preferred port selection
+        const preferredPortSelect = document.getElementById('preferredPortSelect');
+        const currentPreferredPort = document.getElementById('currentPreferredPort');
+        const preferredPortDisplay = document.getElementById('preferredPortDisplay');
+
+        if (preferredPortSelect) {
+            // Clear existing options except the first one (no preference)
+            while (preferredPortSelect.options.length > 1) {
+                preferredPortSelect.remove(1);
+            }
+
+            // Add all available ports
+            ports.forEach(port => {
+                const option = document.createElement('option');
+                option.value = port;
+                option.textContent = port;
+                preferredPortSelect.appendChild(option);
+            });
+
+            // Set the current preferred port value
+            if (preferredPortData && preferredPortData.preferred_port) {
+                // Check if the preferred port is in the available ports
+                const isAvailable = ports.includes(preferredPortData.preferred_port);
+
+                if (isAvailable) {
+                    preferredPortSelect.value = preferredPortData.preferred_port;
+                } else {
+                    // Add the preferred port as an option (it might not be currently available)
+                    const option = document.createElement('option');
+                    option.value = preferredPortData.preferred_port;
+                    option.textContent = `${preferredPortData.preferred_port} (not currently available)`;
+                    preferredPortSelect.appendChild(option);
+                    preferredPortSelect.value = preferredPortData.preferred_port;
+                }
+
+                // Show the current preferred port indicator
+                if (currentPreferredPort && preferredPortDisplay) {
+                    preferredPortDisplay.textContent = `Currently set to: ${preferredPortData.preferred_port}`;
+                    currentPreferredPort.classList.remove('hidden');
+                }
+            }
+        }
+
         // Initialize autocomplete for clear patterns
         const clearFromInInput = document.getElementById('customClearFromInInput');
         const clearFromOutInput = document.getElementById('customClearFromOutInput');
@@ -630,7 +781,13 @@ function setupEventListeners() {
             }
         });
     }
-    
+
+    // Save preferred port button
+    const savePreferredPortButton = document.getElementById('savePreferredPort');
+    if (savePreferredPortButton) {
+        savePreferredPortButton.addEventListener('click', savePreferredPort);
+    }
+
     // Save custom clear patterns button
     const saveClearPatterns = document.getElementById('saveClearPatterns');
     if (saveClearPatterns) {

+ 31 - 0
templates/settings.html

@@ -330,6 +330,37 @@ input:checked + .slider:before {
           </p>
         </label>
       </div>
+      <!-- Preferred Port Configuration -->
+      <div class="px-6 py-5 border-t border-slate-100">
+        <label class="flex flex-col gap-1.5">
+          <span class="text-slate-700 text-sm font-medium leading-normal flex items-center gap-2">
+            <span class="material-icons text-slate-600 text-base">star</span>
+            Preferred Port for Auto-Connect
+          </span>
+          <div class="flex gap-3 items-center">
+            <select
+              id="preferredPortSelect"
+              class="form-select 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-medium leading-normal transition-colors"
+            >
+              <option value="">No preference (auto-detect)</option>
+            </select>
+            <button
+              id="savePreferredPort"
+              class="flex items-center justify-center gap-2 min-w-[100px] 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 flex-shrink-0"
+            >
+              <span class="material-icons text-lg">save</span>
+              <span class="truncate">Save</span>
+            </button>
+          </div>
+          <p class="text-xs text-slate-500 mt-2">
+            When multiple ports are available, this port will be used automatically on startup. If set to "No preference", the system will try the last connected port or the first available port.
+          </p>
+          <p id="currentPreferredPort" class="text-xs text-sky-600 mt-1 hidden">
+            <span class="material-icons text-xs align-middle">check_circle</span>
+            <span id="preferredPortDisplay"></span>
+          </p>
+        </label>
+      </div>
     </div>
   </section>
   <!-- Homing Configuration Section -->