Spoolman leads CC2 Control's copies; new spools from the bridge
CI / test (push) Successful in 2m35s
CI / image (push) Successful in 42s

- Master data of CC2 Control's copies follows Spoolman (name, brand,
  colour, diameter, density, net, tare, price; not the material, which was
  fitted to the tray).
- A loaded spool's rest in CC2 Control is set to Spoolman's via
  /api/spools/adjust once everything is booked (old copy after the roll
  printed in the other printer, weigh-in in Spoolman); the resulting
  correction is not booked back.
- Copies of spools archived or deleted in Spoolman are deleted from CC2
  Control when no tray holds them (library limit 128); an outage never
  counts as deleted.
- A roll that ran out is archived in Spoolman (setting, default on); a
  scan of an archived spool maps nothing.
- A roll scanned again with unchanged tag data and put back into its old
  slot (after printing in the other printer) is recognised.
- Tag generator: "Neue Spule" creates spools in Spoolman from an existing
  or a new filament (and vendor), labelled vendor + id, then opens the tag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014GcEk5tkfFSYD6NTF66NkC
This commit is contained in:
Jonas MenzelandClaude Opus 5.5 committed 2026-10-25 21:26:49 +01:00
1 parent d03668e3c5
commit b37cd64909
13 files changed
+873 -27

No files matched your search

+34 -1
View File
@@ -17,7 +17,7 @@ from fastapi.responses import HTMLResponse, JSONResponse, Response
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from . import materials, tagcodec
from . import materials, newspool, tagcodec
from .bridge import Bridge
from .sshsource import CanvasRecordReader, HostKeyMismatch, KeyStore, SSHError, fingerprint
from .spoolman import SpoolmanError, summary
@@ -276,6 +276,39 @@ def create_app(data_dir: Path | None = None, *, bridge: Bridge | None = None, st
out.sort(key=lambda x: x["id"])
return {"spools": out, "id_offset": s.id_offset, "max_id": tagcodec.MAX_WEIGHT - s.id_offset}
@app.get("/api/spoolman/catalog")
def spoolman_catalog():
client = bridge.spoolman_factory(settings.get())
try:
return newspool.catalog(client)
except SpoolmanError as e:
raise HTTPException(502, str(e)) from None
finally:
client.close()
@app.post("/api/spoolman/create")
async def spoolman_create(request: Request):
body = await _json(request)
s = settings.get()
try:
p = newspool.plan(body)
except (newspool.NewSpoolError, TypeError, ValueError) as e:
raise HTTPException(400, str(e)) from None
if s.dry_run:
bridge.log.add("dry", f"würde in Spoolman {p['count']} neue Spule(n) anlegen")
raise HTTPException(409, "Dry-Run aktiv: in Spoolman wird nichts angelegt")
client = bridge.spoolman_factory(s)
try:
spools, what = newspool.create(client, p, s.location_storage)
except newspool.NewSpoolError as e:
raise HTTPException(400, str(e)) from None
except SpoolmanError as e:
raise HTTPException(502, str(e)) from None
finally:
client.close()
bridge.log.add("info", f"erledigt: in Spoolman angelegt: {what}")
return {"spools": spools}
@app.post("/api/tag")
async def tag(request: Request):
body = await _json(request)