mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 19:21:33 +02:00
Everything the completion path needs to split a print's filament across the trays it fed from lived only in memory: the dispatched plate and slot-to-tray mapping, the spool-assignment snapshot, and the tray-change log. A print that outlived a restart lost all of it and fell back to what the printer reports at completion -- which, with AMS Filament Backup on, is the substitute tray. The whole print was charged to the spool that only finished it while the spool that ran dry was charged nothing. Persist that context in a new active_print_sessions row, append tray changes as they happen, and restore both the session and the printer's tray-change log at restart recovery. Seed the log from the current tray when there is nothing to restore, since last_loaded_tray advances even when no change is logged. Rank the queue item's stored ams_mapping above the printer's live mapping field, which is what backup rewrites. Recover plate_id from the archive or queue item, and give extract_layer_filament_usage_from_3mf a plate_id instead of taking the first .gcode member -- a Bambu Studio export stores plate 2 first, so per-layer figures were measured against the wrong plate for both inventory backends. Stop auto-unlinking a spool assignment when its slot reports empty during a running print. At a runout the spool is still in the AMS, and dropping the link leaves the completion path nothing to charge. Capture the print-start context for both inventory backends. Spoolman's own durable row (#1820) carries its plate-scoped figures and dispatched mapping but not the tray-change log, and its slot assignments -- the way. Registration in _active_sessions stays gated, since on_ams_change reads it to decide whether to skip the remain%-based weight sync (#880).
58 lines
2.6 KiB
Python
58 lines
2.6 KiB
Python
"""Durable copy of the filament-attribution context for an in-flight print."""
|
|
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import JSON, DateTime, ForeignKey
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from backend.app.core.database import Base
|
|
|
|
|
|
class ActivePrintSession(Base):
|
|
"""Print-start context the completion path needs, persisted per printer.
|
|
|
|
``usage_tracker._active_sessions`` holds the same data in memory, and the
|
|
tray-change log lives on ``PrinterState``. Both are lost when Bambuddy
|
|
restarts mid-print, which on a long print silently destroys filament
|
|
attribution: without the plate the 3MF parser sums every plate, without the
|
|
assignment snapshot a spool unlinked at runout can't be resolved, and
|
|
without the tray-change log an AMS-backup switch charges the whole print to
|
|
whichever tray happened to finish it.
|
|
|
|
One row per printer — a printer runs one print at a time. Written at print
|
|
start, appended to on every tray change, deleted at completion. A leaked
|
|
row (completion missed entirely) is harmless: print start overwrites it,
|
|
and the completion path ignores a row whose ``started_at`` doesn't line up
|
|
with the print it is closing.
|
|
|
|
The Spoolman writer has had an equivalent durable row since #1820
|
|
(``active_print_spoolman``); this is the internal-inventory counterpart.
|
|
"""
|
|
|
|
__tablename__ = "active_print_sessions"
|
|
|
|
printer_id: Mapped[int] = mapped_column(ForeignKey("printers.id", ondelete="CASCADE"), primary_key=True)
|
|
|
|
print_name: Mapped[str] = mapped_column(default="")
|
|
started_at: Mapped[datetime] = mapped_column(DateTime)
|
|
|
|
# tray_now at print start — reliable, unlike at completion where the
|
|
# printer has usually retracted and reports 255.
|
|
tray_now_at_start: Mapped[int] = mapped_column(default=-1)
|
|
|
|
# Queue item's plate for multi-plate 3MFs dispatched one plate at a time.
|
|
plate_id: Mapped[int | None] = mapped_column(nullable=True)
|
|
|
|
# Slicer slot -> global tray, as dispatched: [2]
|
|
ams_mapping: Mapped[list | None] = mapped_column(JSON, nullable=True)
|
|
|
|
# {"<ams_id>-<tray_id>": spool_id} — the assignment map as it stood before
|
|
# the print could disturb it.
|
|
spool_assignments: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
|
|
# {"<ams_id>-<tray_id>": remain%} for the remain-delta fallback path.
|
|
tray_remain_start: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
|
|
# [[global_tray_id, layer_num], ...] mirroring PrinterState.tray_change_log.
|
|
tray_change_log: Mapped[list | None] = mapped_column(JSON, nullable=True)
|