The plate-clear gate added in #961 was raised only when a print ended
with status completed or failed. Aborted prints (printer self-abort
or a user stopping the print from the printer's own touchscreen) and
cancelled prints (user stopping via the Bambuddy queue UI) did NOT
raise the flag, so the queue scheduler dispatched the next pending
item ~2 seconds later onto a fouled bed.
The reporter saw two prints (P1P + P1S) auto-start onto fouled beds
within seconds of touchscreen-aborts, and explicitly flagged the
risk of damage to the printer. A third printer behaved correctly
because its previous print had ended "completed" — the asymmetry he
noticed was the gate working for one terminal status and not the
other three.
Touchscreen-aborts are particularly important to gate. Bambuddy's
existing "user stopped via UI" override (which translates aborted
to cancelled when _user_stopped_printers is populated) only fires
for stops through the Bambuddy queue UI; a touchscreen stop reports
aborted straight through.
The original code comment claimed user-cancelled prints don't need a
plate-clear ack because "nothing printed on the bed". That only
holds if you cancel right at layer 1; a cancel at hour 11 of a
12-hour print leaves a fully fouled bed.
The gate is user-clearable on the Printers page, so worst case a
user who cancels at layer 1 clicks "Clear Plate" once — that's a
non-issue compared to auto-dispatching onto material.
Regression coverage in test_print_lifecycle.py::TestPlateClearGate:
parametrised across all 4 terminal statuses asserting
set_awaiting_plate_clear(printer_id, True) is called for each, plus
a defence-in-depth test that an unrecognised future status string
never silently raises the gate.
The previous fix only filtered status codes (< 0x4000) from the
print_error field. Firmware can also send the same false positive
through the hms array in MQTT, which had no such filter. Apply the
same < 0x4000 check to the HMS parser so status/phase indicators
are skipped regardless of which MQTT field carries them.
The MQTT completion handler stored "aborted" as the queue item status
when a print was cancelled mid-print, but the response schema only
allows "cancelled". Pydantic validation failed on the invalid status
when listing all queue items, returning 500. Filtering by specific
status excluded the bad row so those still worked.
Normalise "aborted" → "cancelled" before storing. A startup fixup
also converts any existing "aborted" rows in the database.
- Remove 28 unused imports across 22 test files
- Prefix 4 unused local variables with _ in app code
(archives, bambu_mqtt, main) and remove 1 dead store
- Consolidate import/import-from in test_plate_detection.py
- Fix unreachable statement in test_archive_service.py
- Simplify redundant comparison in timelapse_processor.py
Resolves ~50 CodeQL py/unused-import, py/unused-local-variable,
py/import-and-import-from, py/unreachable-statement, and
py/redundant-comparison findings.
- H2D sends timelapse status in ipcam.timelapse field, not xcam.timelapse
- Added parsing for timelapse from ipcam data
- Added test to prevent regression
2. Systemd service updated - /etc/systemd/system/bambuddy.service
- Now runs as claude user instead of root
- Added ExecStartPre commands with + prefix (runs as root) to:
- Create logs and archive directories if missing
- Fix ownership to claude:claude before service starts
The service restarted successfully with the permission fixes running at startup. On the next print with timelapse enabled, both the snapshot and timelapse should be captured automatically.
1. bambu_mqtt.py: Added hms_errors to the completion callback data, which includes the HMS error codes when a print fails
2. archive.py: Updated update_archive_status() to accept an optional failure_reason parameter
3. main.py: Added auto-detection of failure reasons:
- status == "aborted" → failure_reason = "User cancelled"
- status == "failed" with HMS errors → maps module codes to reasons:
- Module 0x07 (Filament) → "Filament runout"
- Module 0x0C (Motion Controller) → "Layer shift"
- Module 0x05 (Nozzle) → "Clogged nozzle"
Frontend changes:
1. ArchivesPage.tsx:
- Badge now shows "cancelled" for aborted prints, "failed" for failed prints
- "Failed Prints" collection and "Hide Failed" filter now include both failed and aborted statuses
2. EditArchiveModal.tsx: Failure reason field now shows for both failed and aborted prints
New tests added:
- test_hms_errors_included_in_failed_completion_callback
- test_aborted_status_when_cancelled
The HMS error module mapping is basic and can be expanded as you observe more failure types. The actual Bambu HMS error codes are documented in their wiki - we can add
more mappings as needed.