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.
This commit is contained in:
maziggy
2026-04-04 13:38:16 +02:00
parent 2a6df22075
commit aeb61e58d9
2 changed files with 13 additions and 0 deletions
+1
View File
@@ -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.
+12
View File
@@ -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