diff --git a/NIGHTLY_CHANGELOG.md b/NIGHTLY_CHANGELOG.md index 492b142..9055ef9 100644 --- a/NIGHTLY_CHANGELOG.md +++ b/NIGHTLY_CHANGELOG.md @@ -1,4 +1,7 @@ ## Changes in this build -- Fix: wrong filament slot used in multicolor prints when T0 is unused — AMS box mapping now includes placeholder entries for all paint indices so the printer correctly matches T1/T2/T3 tool changes to the right slots (Issue #78) -- Fix: Spoolman spool-slot assignment now persisted to config.ini and restored on bridge restart +- Fix: Spoolman spool-slot assignment persistence was silently broken (NameError on config_loader swallowed by bare except) — now uses correct module reference and logs failures; per-printer isolation added so multi-printer setups no longer overwrite each other (Issue #80, PR #83 by @walterioo) +- Fix: spool dropdown in print dialog showed "[object Object]" instead of vendor name (PR #83) +- Fix: gate_spool_id in MMU object now populated from per-printer slot map instead of hardcoded -1 (PR #83) +- Fix: PLA variants (PLA+, PLA Silk, PLA Matte) now recognized as their material family — correct tray_info_idx sent to printer, correct Generic profile synced to OrcaSlicer, and vendor profiles for the variant shown in slot editor dropdown (Issue #82) +- UI: PLA+, PLA Silk and PLA Matte buttons added to slot material selector diff --git a/kobrax_moonraker_bridge.py b/kobrax_moonraker_bridge.py index 2deb518..c08fe00 100644 --- a/kobrax_moonraker_bridge.py +++ b/kobrax_moonraker_bridge.py @@ -1855,23 +1855,55 @@ class KobraXBridge: # `compatible_printers: []` (= mit allen Druckern kompatibel). _TRAY_INFO_IDX = { # Anycubic-eigene Kobra-X-Profile - "PLA": "GFPLA", - "PLA+": "GFPLA+", - "PLA SILK": "GFPLA Silk", - "PETG": "GFPETG", - "ABS": "GFABS", - "ASA": "GFASA", - "TPU": "GFTPU 95A", - "PVA": "GFPVA", + "PLA": "GFPLA", + "PLA+": "GFPLA+", + "PLA SILK": "GFPLA Silk", + "PLA-SILK": "GFPLA Silk", + "PLASILK": "GFPLA Silk", + "SILK PLA": "GFPLA Silk", + "PLA MATTE": "GFPLA", + "PLA-MATTE": "GFPLA", + "PLA MARBLE": "GFPLA", + "PLA WOOD": "GFPLA", + "PETG": "GFPETG", + "PETG+": "GFPETG", + "ABS": "GFABS", + "ASA": "GFASA", + "TPU": "GFTPU 95A", + "TPE": "GFTPU 95A", + "PVA": "GFPVA", # Kein Anycubic-Kobra-X-Profil → Library-Fallback - "PLA-CF": "OGFL98", - "PETG-CF": "OGFG98", - "PA": "OGFN99", - "PA-CF": "OGFN98", - "PC": "OGFC99", - "HIPS": "OGFS98", + "PLA-CF": "OGFL98", + "PLA CF": "OGFL98", + "PETG-CF": "OGFG98", + "PETG CF": "OGFG98", + "PA": "OGFN99", + "PA-CF": "OGFN98", + "PA CF": "OGFN98", + "PC": "OGFC99", + "HIPS": "OGFS98", } + # Normalisiert Material-Typ-Strings auf den kanonischen Key für _TRAY_INFO_IDX + # und _default_filament_name. PLA-Varianten die nicht exakt matchen fallen + # auf ihre Basisfamilie zurück (PLA+ → PLA+, PLA Matte → PLA, etc.). + @staticmethod + def _normalize_material(mat: str) -> str: + m = mat.upper().strip().replace("-", " ").replace("_", " ") + # Bekannte Varianten normalisieren + _ALIASES = { + "PLAPLUS": "PLA+", "PLA PLUS": "PLA+", + "SILK PLA": "PLA SILK", "PLASILK": "PLA SILK", + "PLA MATTE": "PLA MATTE", "PLA MARBLE": "PLA MARBLE", + "PLA WOOD": "PLA WOOD", + "TPE": "TPU", + "PETG PLUS": "PETG+", + "PA6": "PA", "PA12": "PA", "PA66": "PA", + } + if m in _ALIASES: + return _ALIASES[m] + return m + def _build_lane_data(self) -> dict: """Baut BBL-AMS-JSON für OrcaSlicer DevFilaSystemParser::ParseV1_0. @@ -1910,7 +1942,7 @@ class KobraXBridge: color_hex = color_raw[:6].upper() + "FF" else: color_hex = "FFFFFFFF" - material = slot.get("type", "PLA").upper() + material = self._normalize_material(slot.get("type", "PLA")) # User-Override aus config.ini [filament_profiles].slot_N_id # bekommt Vorrang vor dem Default-Mapping nach material-Type. # Vendor wird mitgesendet (tray_sub_brands + filament_vendor), @@ -2086,7 +2118,7 @@ class KobraXBridge: for _global_index, slot in slots: occupied = slot.get("status") == 5 gate_status.append(1 if occupied else 0) - material = (slot.get("type") or "PLA").upper() if occupied else "" + material = self._normalize_material(slot.get("type") or "PLA") if occupied else "" gate_material.append(material) c = slot.get("color", [0, 0, 0]) if occupied else [0, 0, 0] # Happy Hare erwartet gate_color als RRGGBB OHNE '#' (Klipper-Limitation). @@ -2136,8 +2168,22 @@ class KobraXBridge: kann pro Slot eine konkrete Marke setzen wenn er das will.""" if not material: return "" - mat = material.upper().strip() + mat = self._normalize_material(material) profs = self._load_orca_filaments() + # Varianten-Mapping: Drucker meldet z.B. "PLA SILK", OrcaSlicer speichert + # alle Varianten unter type=PLA mit dem Variant-Namen im name-Feld. + _VARIANT_NAME = { + "PLA SILK": "Generic PLA Silk", + "PLA MATTE": "Generic PLA Matte", + "PLA+": "Generic PLA", + "PLA-CF": "Generic PLA-CF", + "PETG-CF": "Generic PETG-CF", + } + if mat in _VARIANT_NAME: + target = _VARIANT_NAME[mat] + for p in profs: + if p.get("vendor") == "Generic" and p.get("name") == target: + return p["name"] def _match_type(p: dict) -> bool: pt = (p.get("type") or "").upper() return pt == mat or pt.startswith(mat + "-") or pt.startswith(mat + " ") diff --git a/web/themes/default/app.js b/web/themes/default/app.js index 6f80ba4..696c1bc 100644 --- a/web/themes/default/app.js +++ b/web/themes/default/app.js @@ -1413,7 +1413,14 @@ function doProfileImportUpload(files){ // ── AMS Slot Edit ── var _slotEditIndex=-1; var _slotEditLoaded=false; -var _MAT_PRESETS=['PLA','PETG','ABS','ASA','TPU','PA','PC','HIPS']; +var _MAT_PRESETS=['PLA','PLA+','PLA SILK','PLA MATTE','PETG','ABS','ASA','TPU','PA','PC','HIPS']; +function _normalizeMat(m){ + var s=m.toUpperCase().trim().replace(/-/g,' ').replace(/_/g,' '); + var aliases={'PLAPLUS':'PLA+','PLA PLUS':'PLA+','SILK PLA':'PLA SILK','PLASILK':'PLA SILK', + 'PLA MATTE':'PLA','PLA MARBLE':'PLA','PLA WOOD':'PLA','TPE':'TPU', + 'PETG PLUS':'PETG+','PA6':'PA','PA12':'PA','PA66':'PA'}; + return aliases[s]||s; +} var _BASE_MATERIAL_TYPES=['PLA','PETG','ABS','ASA','TPU','TPE','PA','PC','HIPS','PEI','PEEK']; function updateSlotEditFeedButton(){ var btn=document.getElementById('btn-slot-edit-feed'); @@ -1454,10 +1461,21 @@ function _fillSlotProfileDropdown(material, currentVendor, currentName){ _loadOrcaFilaments(function(profiles){ // Type-Filter: nur Profile vom passenden material zeigen (z.B. PLA → alle PLA-Varianten) var matU=(material||'').toUpperCase().trim(); + // PLA-Varianten: Drucker meldet "PLA SILK"/"PLA+"/"PLA MATTE", OrcaSlicer + // speichert alle unter type=PLA — Namens-Keyword als Zusatzfilter. + var _PLA_VARIANT_KW={'PLA SILK':'silk','PLA+':'pla+','PLA MATTE':'matte', + 'PLA MARBLE':'marble','PLA WOOD':'wood'}; + var variantKw=_PLA_VARIANT_KW[matU]||null; + var baseMat=variantKw?'PLA':matU; var matched=profiles.filter(function(p){ var pt=(p.type||'').toUpperCase(); - // PLA-CF, PLA-SILK etc. zählen auch zu PLA - return matU==='' || pt===matU || pt.startsWith(matU+'-') || pt.startsWith(matU+' '); + var nameL=(p.name||'').toLowerCase(); + // Basis-Typ muss passen + var typeOk=baseMat===''||pt===baseMat||pt.startsWith(baseMat+'-')||pt.startsWith(baseMat+' '); + if(!typeOk) return false; + // Bei Variante: Name muss Keyword enthalten (z.B. "silk", "matte", "pla+") + if(variantKw) return nameL.indexOf(variantKw)!==-1; + return true; }); sel.innerHTML=''; // User-Profile (is_user) zuerst — eigene Optgroup '★ Eigene' an erster Stelle. @@ -1619,11 +1637,14 @@ function openSlotEdit(i){ _renderCopyFromSlot(globalIdx); var mat=(slot.type||'PLA').toUpperCase(); document.getElementById('slot-edit-mat').value=mat; + // Normalisieren für Button-Highlighting: PLA-Varianten auf nächsten Preset mappen + var matNorm=_normalizeMat(mat); var btns=document.getElementById('slot-mat-btns'); btns.innerHTML=_MAT_PRESETS.map(function(m){ + var active=m===mat||m===matNorm; return ''; + +(active?'background:var(--accent);color:#fff':'background:var(--raised);color:var(--txt2)')+'">'+m+''; }).join(''); // OrcaSlicer-Profil-Dropdown: aktuellen User-Override für diesen Slot // aus /kx/filament/slots holen (enthält vendor+name+id).