[GH-ISSUE #942] 3 P1S bugs: spurious print-start notifications on restart, missing auto_switch_filament, weight tracking fails after restart #650

Closed
opened 2026-05-06 12:31:40 +02:00 by BreizhHardware · 1 comment

Originally created by @rahulrana21 on GitHub (Apr 11, 2026).
Original GitHub issue: https://github.com/maziggy/bambuddy/issues/942

Originally assigned to: @maziggy on GitHub.

Summary

Three related bugs found while using Bambuddy exclusively (no BambuStudio) for P1S printing. All three were root-caused from MQTT/code analysis.


Bug 1 — Spurious "Print Started" notifications and phantom archives on Bambuddy restart

File: backend/app/services/bambu_mqtt.py

When Bambuddy restarts while a print is in progress, the printer sends a pushall response. The is_new_print detection fires because _previous_gcode_state is reset to None on startup, so None != "RUNNING" is True.

This causes:

  • A duplicate "Print Started" notification sent to all providers
  • A phantom PrintArchive record created in the DB with no filament slot data

Root cause:

is_new_print = (
    self.state.state == "RUNNING"
    and self._previous_gcode_state != "RUNNING"   # None != "RUNNING" → True after restart
    and current_file
    and not self._was_running                       # False after restart → True
)

Fix — mirror the guard already present in is_file_change:

is_new_print = (
    self.state.state == "RUNNING"
    and self._previous_gcode_state != "RUNNING"
    and self._previous_gcode_state is not None   # ADD: ignore first message after restart
    and current_file
    and not self._was_running
)

Bug 2 — AMS auto-switch (backup spool) never enabled

File: backend/app/services/bambu_mqtt.pystart_print()

BambuStudio sends {"print": {"command": "print_option", "auto_switch_filament": true}} when starting a print with AMS. This enables the printer to automatically switch to a backup slot when one slot runs out (requires matching tray_info_idx on both slots).

Bambuddy never sends this command. The printer either keeps its last BambuStudio setting (unreliable) or defaults to false. Result: printer pauses and asks for manual filament reload instead of switching to the backup slot.

Bambuddy already has _set_print_option() infrastructure for exactly this pattern (used for auto_recovery_step_loss).

Fix — add after _client.publish() at the end of start_print():

# Enable AMS auto-switch between slots with same filament when one runs out
if use_ams:
    self._set_print_option("auto_switch_filament", True)

Bug 3 — Filament weight tracking fails for P1S after Bambuddy restart

Files: backend/app/services/background_dispatch.py, backend/app/services/usage_tracker.py

_print_ams_mappings in main.py is an in-memory dict mapping archive_id → ams_mapping. It is wiped on every Bambuddy restart. For P1S prints (which don't include ams_mapping in MQTT print-start events unlike P2S with developer_mode=true), this mapping is the only source for _track_from_3mf.

After a restart, _track_from_3mf falls through to the final fallback: slot_id - 1 = global_tray_id, which is wrong for multi-colour prints and charges the wrong spools.

Fix — Part A: persist ams_mapping to archive.extra_data at dispatch time (in both _run_reprint_archive and _run_print_library_file, right after register_expected_print):

_ams_mapping = job.options.get("ams_mapping")
if _ams_mapping:
    archive.extra_data = {**(archive.extra_data or {}), "ams_mapping": _ams_mapping}
    await db.commit()

Fix — Part B: add step 3.5 in _track_from_3mf between the queue-item check (step 3) and color-match (step 4):

# 3.5. Try ams_mapping from archive.extra_data (DB-persisted, survives restart)
if not slot_to_tray:
    from backend.app.models.archive import PrintArchive as _PrintArchive
    arch_result = await db.execute(select(_PrintArchive).where(_PrintArchive.id == archive_id))
    arch_rec = arch_result.scalar_one_or_none()
    if arch_rec and arch_rec.extra_data:
        stored_mapping = arch_rec.extra_data.get("ams_mapping")
        if stored_mapping:
            slot_to_tray = stored_mapping
            mapping_source = "extra_data"

Notes

  • Bugs 1 and 3 are triggered by the same event: Bambuddy restart during an active print
  • Bug 2 affects all P1S users printing with AMS backup spools
  • P1S is more affected than P2S because P1S lacks ams_mapping in MQTT print-start events (no developer_mode)
  • All three fixes have been running in production for several hours without issues
Originally created by @rahulrana21 on GitHub (Apr 11, 2026). Original GitHub issue: https://github.com/maziggy/bambuddy/issues/942 Originally assigned to: @maziggy on GitHub. ## Summary Three related bugs found while using Bambuddy exclusively (no BambuStudio) for P1S printing. All three were root-caused from MQTT/code analysis. --- ## Bug 1 — Spurious "Print Started" notifications and phantom archives on Bambuddy restart **File:** `backend/app/services/bambu_mqtt.py` When Bambuddy restarts while a print is in progress, the printer sends a `pushall` response. The `is_new_print` detection fires because `_previous_gcode_state` is reset to `None` on startup, so `None != "RUNNING"` is `True`. This causes: - A duplicate "Print Started" notification sent to all providers - A phantom `PrintArchive` record created in the DB with no filament slot data **Root cause:** ```python is_new_print = ( self.state.state == "RUNNING" and self._previous_gcode_state != "RUNNING" # None != "RUNNING" → True after restart and current_file and not self._was_running # False after restart → True ) ``` **Fix** — mirror the guard already present in `is_file_change`: ```python is_new_print = ( self.state.state == "RUNNING" and self._previous_gcode_state != "RUNNING" and self._previous_gcode_state is not None # ADD: ignore first message after restart and current_file and not self._was_running ) ``` --- ## Bug 2 — AMS auto-switch (backup spool) never enabled **File:** `backend/app/services/bambu_mqtt.py` — `start_print()` BambuStudio sends `{"print": {"command": "print_option", "auto_switch_filament": true}}` when starting a print with AMS. This enables the printer to automatically switch to a backup slot when one slot runs out (requires matching `tray_info_idx` on both slots). Bambuddy never sends this command. The printer either keeps its last BambuStudio setting (unreliable) or defaults to `false`. Result: printer pauses and asks for manual filament reload instead of switching to the backup slot. Bambuddy already has `_set_print_option()` infrastructure for exactly this pattern (used for `auto_recovery_step_loss`). **Fix** — add after `_client.publish()` at the end of `start_print()`: ```python # Enable AMS auto-switch between slots with same filament when one runs out if use_ams: self._set_print_option("auto_switch_filament", True) ``` --- ## Bug 3 — Filament weight tracking fails for P1S after Bambuddy restart **Files:** `backend/app/services/background_dispatch.py`, `backend/app/services/usage_tracker.py` `_print_ams_mappings` in `main.py` is an in-memory dict mapping `archive_id → ams_mapping`. It is wiped on every Bambuddy restart. For P1S prints (which don't include `ams_mapping` in MQTT print-start events unlike P2S with `developer_mode=true`), this mapping is the only source for `_track_from_3mf`. After a restart, `_track_from_3mf` falls through to the final fallback: `slot_id - 1 = global_tray_id`, which is wrong for multi-colour prints and charges the wrong spools. **Fix — Part A:** persist `ams_mapping` to `archive.extra_data` at dispatch time (in both `_run_reprint_archive` and `_run_print_library_file`, right after `register_expected_print`): ```python _ams_mapping = job.options.get("ams_mapping") if _ams_mapping: archive.extra_data = {**(archive.extra_data or {}), "ams_mapping": _ams_mapping} await db.commit() ``` **Fix — Part B:** add step 3.5 in `_track_from_3mf` between the queue-item check (step 3) and color-match (step 4): ```python # 3.5. Try ams_mapping from archive.extra_data (DB-persisted, survives restart) if not slot_to_tray: from backend.app.models.archive import PrintArchive as _PrintArchive arch_result = await db.execute(select(_PrintArchive).where(_PrintArchive.id == archive_id)) arch_rec = arch_result.scalar_one_or_none() if arch_rec and arch_rec.extra_data: stored_mapping = arch_rec.extra_data.get("ams_mapping") if stored_mapping: slot_to_tray = stored_mapping mapping_source = "extra_data" ``` --- ## Notes - Bugs 1 and 3 are triggered by the same event: Bambuddy restart during an active print - Bug 2 affects all P1S users printing with AMS backup spools - P1S is more affected than P2S because P1S lacks `ams_mapping` in MQTT print-start events (no `developer_mode`) - All three fixes have been running in production for several hours without issues
Author
Owner

@maziggy commented on GitHub (Apr 11, 2026):

What version are we talking about?

<!-- gh-comment-id:4228507232 --> @maziggy commented on GitHub (Apr 11, 2026): What version are we talking about?
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/bambuddy#650
No description provided.