Просмотр исходного кода

Fix stale SpoolBuddy update status after daemon restart

  After an SSH update completed, the UI kept showing "Update complete,
  daemon restarting..." and the old "update available" banner because
  nothing cleared the stale state. Registration now resets update_status
  when the daemon comes back, and WebSocket handlers for spoolbuddy_update
  and spoolbuddy_online invalidate the frontend queries immediately.
maziggy 2 месяцев назад
Родитель
Сommit
811813165b

+ 1 - 0
CHANGELOG.md

@@ -7,6 +7,7 @@ All notable changes to Bambuddy will be documented in this file.
 ### Fixed
 ### Fixed
 - **SpoolBuddy Update Check Always Shows "Up to Date"** — The SpoolBuddy daemon update check compared the device's firmware version against GitHub releases instead of the running Bambuddy backend version. This meant the check could incorrectly report "up to date" even when the daemon was behind. Fixed by comparing directly against `APP_VERSION` from the backend config.
 - **SpoolBuddy Update Check Always Shows "Up to Date"** — The SpoolBuddy daemon update check compared the device's firmware version against GitHub releases instead of the running Bambuddy backend version. This meant the check could incorrectly report "up to date" even when the daemon was behind. Fixed by comparing directly against `APP_VERSION` from the backend config.
 - **SpoolBuddy Updates Now Use SSH** — Replaced the fragile self-update mechanism (daemon pulls its own code via git, permission errors on `.git/`, hardcoded `main` branch) with SSH-based updates driven by the Bambuddy backend. Bambuddy now SSHes into the SpoolBuddy Pi and runs git fetch/checkout, pip install, systemctl restart, and kiosk browser restart remotely. Updates automatically use the same branch as Bambuddy. SSH key pairing is fully automatic — Bambuddy generates an ED25519 keypair and includes the public key in the device registration response; the daemon deploys it to `authorized_keys` on first connect. The install script creates the `spoolbuddy` user with a bash shell and sudoers entries for daemon and kiosk restart. A "Force Update" button allows re-deploying even when versions match. The SSH public key is also shown in SpoolBuddy Settings → Updates → SSH Setup for manual pairing if needed.
 - **SpoolBuddy Updates Now Use SSH** — Replaced the fragile self-update mechanism (daemon pulls its own code via git, permission errors on `.git/`, hardcoded `main` branch) with SSH-based updates driven by the Bambuddy backend. Bambuddy now SSHes into the SpoolBuddy Pi and runs git fetch/checkout, pip install, systemctl restart, and kiosk browser restart remotely. Updates automatically use the same branch as Bambuddy. SSH key pairing is fully automatic — Bambuddy generates an ED25519 keypair and includes the public key in the device registration response; the daemon deploys it to `authorized_keys` on first connect. The install script creates the `spoolbuddy` user with a bash shell and sudoers entries for daemon and kiosk restart. A "Force Update" button allows re-deploying even when versions match. The SSH public key is also shown in SpoolBuddy Settings → Updates → SSH Setup for manual pairing if needed.
+- **SpoolBuddy Update Status Stale After Restart** — After a SpoolBuddy update completed, the UI continued showing "Update complete, daemon restarting..." and the old "update available" banner because stale status was never cleared. Fixed by clearing `update_status` on device re-registration (daemon restart), and adding WebSocket handlers for `spoolbuddy_update` and `spoolbuddy_online` events so the frontend immediately refreshes device state and update check results.
 - **Virtual Printer Proxy A1 Printing Fails** ([#757](https://github.com/maziggy/bambuddy/issues/757)) — BambuStudio could not send prints to A1 (and potentially P1S) virtual printers in proxy mode. The slicer connects to undocumented proprietary ports 2024-2026 on these models, which the proxy was not forwarding, causing BambuStudio to show an access code dialog instead of printing. Added transparent TCP pass-through proxying for ports 2024-2026. These ports are silently ignored on models that don't use them (X1C, H2C, P2S). Reported by @Utility9298.
 - **Virtual Printer Proxy A1 Printing Fails** ([#757](https://github.com/maziggy/bambuddy/issues/757)) — BambuStudio could not send prints to A1 (and potentially P1S) virtual printers in proxy mode. The slicer connects to undocumented proprietary ports 2024-2026 on these models, which the proxy was not forwarding, causing BambuStudio to show an access code dialog instead of printing. Added transparent TCP pass-through proxying for ports 2024-2026. These ports are silently ignored on models that don't use them (X1C, H2C, P2S). Reported by @Utility9298.
 - **Spool Assignment on Empty AMS Slots** ([#784](https://github.com/maziggy/bambuddy/issues/784)) — Empty AMS slots (no physical spool detected) showed "Assign Spool" and "Configure" buttons in the hover popup. Assigning a spool to an empty slot created a stuck state because no "Unassign" button is available for empty slots. Removed both buttons from empty AMS and HT AMS slot popups. External spool holders are unaffected. Reported by @RosdasHH.
 - **Spool Assignment on Empty AMS Slots** ([#784](https://github.com/maziggy/bambuddy/issues/784)) — Empty AMS slots (no physical spool detected) showed "Assign Spool" and "Configure" buttons in the hover popup. Assigning a spool to an empty slot created a stuck state because no "Unassign" button is available for empty slots. Removed both buttons from empty AMS and HT AMS slot popups. External spool holders are unaffected. Reported by @RosdasHH.
 
 

+ 4 - 0
backend/app/api/routes/spoolbuddy.py

@@ -101,6 +101,10 @@ async def register_device(
         device.nfc_connection = req.nfc_connection
         device.nfc_connection = req.nfc_connection
         device.has_backlight = req.has_backlight
         device.has_backlight = req.has_backlight
         device.last_seen = now
         device.last_seen = now
+        # Clear stale update status on re-registration (daemon restarted after update)
+        if device.update_status in ("complete", "error"):
+            device.update_status = None
+            device.update_message = None
         logger.info("SpoolBuddy device re-registered: %s (%s)", req.device_id, req.hostname)
         logger.info("SpoolBuddy device re-registered: %s (%s)", req.device_id, req.hostname)
     else:
     else:
         device = SpoolBuddyDevice(
         device = SpoolBuddyDevice(

+ 8 - 0
frontend/src/hooks/useWebSocket.ts

@@ -287,10 +287,18 @@ export function useWebSocket() {
 
 
       case 'spoolbuddy_online':
       case 'spoolbuddy_online':
         window.dispatchEvent(new CustomEvent('spoolbuddy-online', { detail: message }));
         window.dispatchEvent(new CustomEvent('spoolbuddy-online', { detail: message }));
+        debouncedInvalidate('spoolbuddy-devices');
+        debouncedInvalidate('spoolbuddy-update-check');
         break;
         break;
 
 
       case 'spoolbuddy_offline':
       case 'spoolbuddy_offline':
         window.dispatchEvent(new CustomEvent('spoolbuddy-offline', { detail: message }));
         window.dispatchEvent(new CustomEvent('spoolbuddy-offline', { detail: message }));
+        debouncedInvalidate('spoolbuddy-devices');
+        break;
+
+      case 'spoolbuddy_update':
+        debouncedInvalidate('spoolbuddy-devices');
+        debouncedInvalidate('spoolbuddy-update-check');
         break;
         break;
     }
     }
   }, [queryClient, debouncedInvalidate, throttledPrinterStatusUpdate]);
   }, [queryClient, debouncedInvalidate, throttledPrinterStatusUpdate]);

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
static/assets/index-BSgCAUZw.js


+ 1 - 1
static/index.html

@@ -23,7 +23,7 @@
 
 
     <!-- Splash screens for iOS -->
     <!-- Splash screens for iOS -->
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
-    <script type="module" crossorigin src="/assets/index-ABN02nc3.js"></script>
+    <script type="module" crossorigin src="/assets/index-BSgCAUZw.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-CJ-drcFM.css">
     <link rel="stylesheet" crossorigin href="/assets/index-CJ-drcFM.css">
   </head>
   </head>
   <body>
   <body>

Некоторые файлы не были показаны из-за большого количества измененных файлов