From aeb61e58d9ba3218f33049da6ff0423e6e31897b Mon Sep 17 00:00:00 2001 From: maziggy Date: Sat, 4 Apr 2026 13:38:16 +0200 Subject: [PATCH] Fix spool manager deducting double filament after print completion (#880) Skip AMS remain% weight sync in on_ams_change while a print session is active. The MQTT FINISH message triggers both the AMS weight sync (SET from remain%) and the usage tracker (ADD from 3MF data) in the same event loop cycle, causing double deduction. The active-session check is snapshotted before any await to prevent a race with on_print_complete popping the session during interleaved execution. --- CHANGELOG.md | 1 + backend/app/main.py | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eae3a6d53..d5b2800f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ All notable changes to Bambuddy will be documented in this file. - **Camera Snapshot Temp Files World-Readable** — Camera snapshot and plate detection endpoints created temporary JPEG files in `/tmp` with default 0644 permissions, making them readable by any local user. Switched from `NamedTemporaryFile(delete=False)` to `mkstemp` with explicit 0600 permissions so only the application user can read them. Cleanup was already handled via `finally` blocks. Reported responsibly by Sacha Vaudey via security@bambuddy.cool. ### Fixed +- **Spool Manager Deducts Double the Filament Used** ([#880](https://github.com/maziggy/bambuddy/issues/880)) — After a print completed, the built-in spool manager subtracted twice the actual filament consumption. The printer's MQTT status message contains both updated AMS remain percentages and the `FINISH` state, which triggered two independent deduction paths in the same event loop cycle: the AMS weight sync (absolute SET from remain%) and the usage tracker (additive delta from 3MF data). The AMS weight sync now skips updates while a print session is active, letting the usage tracker handle deductions precisely via 3MF slicer data. - **Thumbnails Broken After Backend Restart** — Archive and library thumbnails returned 401 Unauthorized after a backend restart because stream tokens are stored in memory and lost on restart. The frontend now detects failed token-protected image loads and automatically refreshes the stream token, so thumbnails recover without a page reload. - **SpoolBuddy Kiosk Screen Blanks on Boot** — The touchscreen display would blank immediately after the RPi booted, requiring a touch to wake. Added `consoleblank=0` to the kernel cmdline to disable Linux console blanking during the Plymouth-to-labwc transition, and changed the `wlr-randr` anti-blank loop to fire immediately instead of sleeping 60 seconds first. - **Queue Widget Ignores Plate-Clear Setting** ([#752](https://github.com/maziggy/bambuddy/issues/752)) — The "Clear Plate & Start Next" button on printer cards appeared even when "Require plate-clear confirmation" was disabled in Settings → Queue. The backend correctly auto-dispatched without waiting, but the frontend widget always showed the prompt. The widget now respects the setting and shows a passive queue link instead when plate-clear confirmation is disabled. diff --git a/backend/app/main.py b/backend/app/main.py index 785cd6bea..db421d41a 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -643,6 +643,12 @@ async def on_ams_change(printer_id: int, ams_data: list): """Handle AMS data changes - sync to Spoolman if enabled and auto mode.""" logger = logging.getLogger(__name__) + # Snapshot BEFORE any await: if a print is active, skip weight sync later. + # on_print_complete may pop _active_sessions during our awaits (#880). + from backend.app.services.usage_tracker import _active_sessions + + _print_active = printer_id in _active_sessions + # MQTT relay - publish AMS change try: printer_info = printer_manager.get_printer(printer_id) @@ -828,6 +834,12 @@ async def on_ams_change(printer_id: int, ams_data: list): # Sync spool weight_used from AMS remain — only INCREASE, never decrease. # The AMS remain% is low-resolution (integer %, i.e. 10g steps for 1kg spool) # and must not overwrite precise values from the usage tracker (3MF/G-code). + # Skip during active prints: the usage tracker handles deduction + # precisely via 3MF data on print completion. Without this guard the + # AMS remain% SET and the usage tracker ADD both fire from the same + # MQTT message, doubling the deduction (#880). + if _print_active: + continue remain_raw = tray.get("remain") if ( remain_raw is not None