Browse Source

Added Wifi signal strength to printer card

maziggy 5 months ago
parent
commit
cef6cd593b

+ 9 - 2
backend/app/services/bambu_ftp.py

@@ -241,13 +241,20 @@ class BambuFTPClient:
         # Try AVBL command (available space) - some FTP servers support this
         try:
             response = self._ftp.sendcmd("AVBL")
+            logger.debug(f"AVBL response: {response}")
             # Response format: "213 <bytes available>"
             if response.startswith("213"):
                 parts = response.split()
                 if len(parts) >= 2:
                     result["free_bytes"] = int(parts[1])
-        except Exception:
-            pass
+        except Exception as e:
+            logger.debug(f"AVBL command not supported: {e}")
+            # Try STAT command as fallback
+            try:
+                response = self._ftp.sendcmd("STAT")
+                logger.debug(f"STAT response: {response}")
+            except Exception:
+                pass
 
         # Calculate used space by listing root directories
         try:

+ 12 - 1
backend/app/services/bambu_mqtt.py

@@ -347,6 +347,17 @@ class BambuMQTTClient:
             logger.info(f"[{self.serial_number}] Received system data: {system_data}")
             self._handle_system_response(system_data)
 
+        # Parse WiFi signal at top level (some printers send it here)
+        if "wifi_signal" in payload:
+            wifi_signal = payload["wifi_signal"]
+            if isinstance(wifi_signal, (int, float)):
+                self.state.wifi_signal = int(wifi_signal)
+            elif isinstance(wifi_signal, str):
+                try:
+                    self.state.wifi_signal = int(wifi_signal.replace("dBm", "").strip())
+                except ValueError:
+                    pass
+
         if "print" in payload:
             print_data = payload["print"]
 
@@ -1220,8 +1231,8 @@ class BambuMQTTClient:
         # Parse WiFi signal strength (dBm)
         if "wifi_signal" in data:
             wifi_signal = data["wifi_signal"]
+            logger.info(f"[{self.serial_number}] wifi_signal received: {wifi_signal}")
             if isinstance(wifi_signal, (int, float)):
-                # Convert string dBm to int (e.g., "-52dBm" -> -52)
                 self.state.wifi_signal = int(wifi_signal)
             elif isinstance(wifi_signal, str):
                 # Handle string format like "-52dBm"

+ 2 - 0
backend/app/services/printer_manager.py

@@ -287,6 +287,8 @@ def printer_state_to_dict(state: PrinterState, printer_id: int | None = None) ->
         "ams_status_main": state.ams_status_main,
         "ams_status_sub": state.ams_status_sub,
         "tray_now": state.tray_now,
+        # WiFi signal strength
+        "wifi_signal": state.wifi_signal,
     }
     # Add cover URL if there's an active print and printer_id is provided
     if printer_id and state.state == "RUNNING" and state.gcode_file:

+ 11 - 3
frontend/src/components/FileManagerModal.tsx

@@ -155,9 +155,17 @@ export function FileManagerModal({ printerId, printerName, onClose }: FileManage
             </div>
             <div className="flex items-center gap-4">
               {/* Storage info */}
-              {storageData?.used_bytes != null && storageData.used_bytes > 0 && (
-                <div className="text-sm text-bambu-gray">
-                  Used: {formatStorageSize(storageData.used_bytes)}
+              {storageData && (storageData.used_bytes != null || storageData.free_bytes != null) && (
+                <div className="text-sm text-bambu-gray flex items-center gap-2">
+                  {storageData.used_bytes != null && (
+                    <span>Used: {formatStorageSize(storageData.used_bytes)}</span>
+                  )}
+                  {storageData.used_bytes != null && storageData.free_bytes != null && (
+                    <span className="text-bambu-dark-tertiary">|</span>
+                  )}
+                  {storageData.free_bytes != null && (
+                    <span>Free: {formatStorageSize(storageData.free_bytes)}</span>
+                  )}
                 </div>
               )}
               <button

+ 11 - 4
frontend/src/hooks/useWebSocket.ts

@@ -75,10 +75,17 @@ export function useWebSocket() {
         if (message.printer_id !== undefined) {
           queryClient.setQueryData(
             ['printerStatus', message.printer_id],
-            (old: Record<string, unknown> | undefined) => ({
-              ...old,
-              ...message.data,
-            })
+            (old: Record<string, unknown> | undefined) => {
+              const merged = {
+                ...old,
+                ...message.data,
+              };
+              // Preserve last known wifi_signal if new value is null
+              if (merged.wifi_signal == null && old?.wifi_signal != null) {
+                merged.wifi_signal = old.wifi_signal;
+              }
+              return merged;
+            }
           );
         }
         break;

+ 40 - 0
frontend/src/pages/PrintersPage.tsx

@@ -4,6 +4,7 @@ import {
   Plus,
   Wifi,
   WifiOff,
+  Signal,
   Thermometer,
   Clock,
   MoreVertical,
@@ -37,6 +38,15 @@ function formatTime(seconds: number): string {
   return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
 }
 
+function getWifiStrength(rssi: number | null | undefined): { label: string; color: string; bars: number } {
+  if (rssi == null) return { label: '', color: 'text-bambu-gray', bars: 0 };
+  if (rssi >= -50) return { label: 'Excellent', color: 'text-bambu-green', bars: 4 };
+  if (rssi >= -60) return { label: 'Good', color: 'text-bambu-green', bars: 3 };
+  if (rssi >= -70) return { label: 'Fair', color: 'text-yellow-400', bars: 2 };
+  if (rssi >= -80) return { label: 'Weak', color: 'text-orange-400', bars: 1 };
+  return { label: 'Very weak', color: 'text-red-400', bars: 1 };
+}
+
 function CoverImage({ url, printName }: { url: string | null; printName?: string }) {
   const [loaded, setLoaded] = useState(false);
   const [error, setError] = useState(false);
@@ -118,6 +128,15 @@ function PrinterCard({
     refetchInterval: 30000, // Fallback polling, WebSocket handles real-time
   });
 
+  // Cache WiFi signal to prevent it disappearing on updates
+  const [cachedWifiSignal, setCachedWifiSignal] = useState<number | null>(null);
+  useEffect(() => {
+    if (status?.wifi_signal != null) {
+      setCachedWifiSignal(status.wifi_signal);
+    }
+  }, [status?.wifi_signal]);
+  const wifiSignal = status?.wifi_signal ?? cachedWifiSignal;
+
   // Fetch smart plug for this printer
   const { data: smartPlug } = useQuery({
     queryKey: ['smartPlugByPrinter', printer.id],
@@ -190,6 +209,7 @@ function PrinterCard({
             </p>
           </div>
           <div className="flex items-center gap-2">
+            {/* Connection status badge */}
             <span
               className={`flex items-center gap-1.5 px-2 py-1 rounded-full text-xs ${
                 status?.connected
@@ -204,6 +224,26 @@ function PrinterCard({
               )}
               {status?.connected ? 'Connected' : 'Offline'}
             </span>
+            {/* WiFi signal strength indicator */}
+            {status?.connected && wifiSignal != null && (
+              <span
+                className={`flex items-center gap-1 px-2 py-1 rounded-full text-xs ${
+                  wifiSignal >= -50
+                    ? 'bg-bambu-green/20 text-bambu-green'
+                    : wifiSignal >= -60
+                    ? 'bg-bambu-green/20 text-bambu-green'
+                    : wifiSignal >= -70
+                    ? 'bg-amber-500/20 text-amber-600'
+                    : wifiSignal >= -80
+                    ? 'bg-orange-500/20 text-orange-600'
+                    : 'bg-red-500/20 text-red-600'
+                }`}
+                title={`WiFi: ${wifiSignal} dBm - ${getWifiStrength(wifiSignal).label}`}
+              >
+                <Signal className="w-3 h-3" />
+                {wifiSignal}dBm
+              </span>
+            )}
             {/* HMS Status Indicator */}
             {status?.connected && (
               <button

File diff suppressed because it is too large
+ 0 - 0
static/assets/index-B01KJJLK.css


File diff suppressed because it is too large
+ 0 - 0
static/assets/index-BCXYYo2S.css


File diff suppressed because it is too large
+ 0 - 0
static/assets/index-DeHI9Fkw.js


+ 2 - 2
static/index.html

@@ -7,8 +7,8 @@
     <link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png" />
     <link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.png" />
     <link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png" />
-    <script type="module" crossorigin src="/assets/index-BFqTr5zP.js"></script>
-    <link rel="stylesheet" crossorigin href="/assets/index-B01KJJLK.css">
+    <script type="module" crossorigin src="/assets/index-DeHI9Fkw.js"></script>
+    <link rel="stylesheet" crossorigin href="/assets/index-BCXYYo2S.css">
   </head>
   <body>
     <div id="root"></div>

Some files were not shown because too many files changed in this diff