mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-12 11:37:42 +00:00
v3.0: content-addressed mint tooling, succession runtime, W1 hardening
Implements phase v3.0 of filament_id_plan_v3.md - tooling and client
prerequisites. No filament_id values change in this commit.
Tooling (scripts/assign_filament_ids.py; 106 unit tests):
- The mint key becomes "filament_product/<filament_vendor>/<filament_type>/
<family_name>", resolved loader-faithfully from the declarer's flattened
config - bundle-independent and content-addressed; identity fixes re-id
by design and are made safe by the succession ledger. --mint now takes
the triple.
- The snapshot gains "triples" and "triple_exceptions" sections, folded
into the equality gate: any vendor/type/name change surfaces as a
reviewable snapshot diff. Check 3 rewritten to triple-mint conformance
with (id, triple) grandfathering; check 5 generalized from OFL generics
to every OFL-riding vendor preset; new check 8 (triple integrity) and
check 9 (succession integrity).
- The retired ledger moves to resources/profiles/retired_filament_ids.json
so it ships with the app; schema {claims, successor} plus cross-island
"hints". The 14 v1 entries are migrated with mode-rule successors.
Vanished ids in a foreign island's space (GF*/QD_*) are RELEASED with a
hint instead of retired: the island catalog owns them and may
legitimately (re)ship them, which check 4 must never block.
- New maintenance modes: --remint VENDOR, --drop-redundant-ids VENDOR,
--add-hint "OLD=NEW", and --update-snapshot --forget-never-shipped FILE
(never-shipped ids drop from lineage; chains splice through them).
Runtime (C++):
- Succession helpers in libslic3r/Preset (pure chain-follow + lazy ledger
load from resources), consulted only on resolution miss in
get_filament_by_filament_id, both AMS sync predicates,
add_ams_filaments, setting_id_to_type, and the calibration-history
lookup; behavior is byte-identical while the ledger has no matching
entry. Catch2 coverage in tests/libslic3r.
- W1 hardening: check_ams_filament_valid no longer remote-wipes trays or
rewrites temps for P-shaped ids that a system preset carries (ten such
system ids ship today); the size==8 && [0]=='P' assert is relaxed; the
unguarded filament_list find deref in the temp-equation check returns
non-destructively on a miss.
- MoonrakerPrinterAgent: the 23 hardcoded OFL generic ids are replaced by
a runtime lookup of "Generic <family> @System" (id-equivalent on
today's shipped profiles, follows future re-mints automatically);
scripts/test_moonraker_lane_data.py derives its expectations from the
shipped profiles and gains --check-ofl-map.
Profile data (W3 - type is now a key component, so type bugs are fixed
before any re-mint):
- 17 same-name-different-type groups corrected across 50 files (OFL
Generic PETG-CF/PE-CF/PP-CF; Flashforge ASA Basic/ASA-CF/ABS-CF/HIPS/
PAHT-CF/PLA Silk; FusRock PAHT; Creality Generic PA6-CF; InfiMech PETG;
Anycubic TPU 95A / TPU for ACE; Prusa Generic PA-CF/PLA-CF) - every
value validated against MaterialType::all(); 3 Snapmaker U1 roots gain
their missing filament_vendor. Flattened-config equivalence vs the
previous commit: exactly the 54 intended diffs, zero BBL.
- doc/developer-reference/filament_id.md rewritten for the v3 rule.
Ambiguous type divergences (Prusa Generic TPU/TPU HF FLEX-vs-TPU, FusRock
S-Multi/S-PAHT) and all same-type vendor-tag divergences are deferred to
the v3.2 vendor worksheets, catalogued with analysis.
This commit is contained in:
@@ -69,9 +69,12 @@ the `Generic X` base name, write no id key).
|
|||||||
`Generic X @System`, keeps the `Generic X` base name (that alias is what hides the library
|
`Generic X @System`, keeps the `Generic X` base name (that alias is what hides the library
|
||||||
preset on your printers), sets a non-empty `compatible_printers`, and writes no id key.
|
preset on your printers), sets a non-empty `compatible_printers`, and writes no id key.
|
||||||
A vendor-*branded* filament never rides a generic family id.
|
A vendor-*branded* filament never rides a generic family id.
|
||||||
5. **Ids are immutable once shipped.** Renaming a family does not change its id — use
|
5. **Ids follow the product identity.** The id is a pure function of the product triple
|
||||||
`renamed_from`. A shipped id is never recycled for a different material: old ids live on in
|
`(filament_vendor, filament_type, family name)` — correcting any of them re-mints the id
|
||||||
user presets and 3mf files and a recycled id would silently match the wrong material.
|
**by design**, and `--update-snapshot` records the old id in the shipped succession ledger
|
||||||
|
with its successor so device trays, calibration records, and user presets keep resolving
|
||||||
|
(`renamed_from` still gates preset-*name* compatibility as before). A shipped id is never
|
||||||
|
recycled for a different material: retired ids are blocked forever.
|
||||||
|
|
||||||
## Minting — nobody invents ids
|
## Minting — nobody invents ids
|
||||||
|
|
||||||
@@ -81,15 +84,20 @@ New ids are deterministic, computed exactly like the `setting_id` precedent
|
|||||||
```text
|
```text
|
||||||
FILAMENT_ID_NAMESPACE = uuid5(setting-id NAMESPACE, "filament_id")
|
FILAMENT_ID_NAMESPACE = uuid5(setting-id NAMESPACE, "filament_id")
|
||||||
= c4d3ff49-4c32-5534-a3e3-00894157ab97
|
= c4d3ff49-4c32-5534-a3e3-00894157ab97
|
||||||
filament_id = "OF" + base62_6( uuid5(FILAMENT_ID_NAMESPACE, "filament_family/<vendor>/<family>") )
|
filament_id = "OF" + base62_6( uuid5(FILAMENT_ID_NAMESPACE,
|
||||||
|
"filament_product/<filament_vendor>/<filament_type>/<family_name>") )
|
||||||
```
|
```
|
||||||
|
|
||||||
`base62_6` is the low 6 base62 digits (alphabet `0-9A-Za-z`) of the UUID taken as a big-endian
|
`base62_6` is the low 6 base62 digits (alphabet `0-9A-Za-z`) of the UUID taken as a big-endian
|
||||||
integer, most-significant digit first — 8 chars total, within the AMS length limit. `<vendor>`
|
integer, most-significant digit first — 8 chars total, within the AMS length limit. The triple
|
||||||
is the vendor bundle name (the stem of the vendor index json, e.g. `Qidi`,
|
comes from the family root's *flattened* config: `<filament_vendor>` is the filament
|
||||||
`OrcaFilamentLibrary`); `<family>` is the family base name. On the rare collision with any
|
**manufacturer** (`"Polymaker"`, or `"Generic"` for generics — never the printer brand),
|
||||||
existing or retired id, the minter salts the input (`…/1`, `…/2`, …) until free and the result
|
`<filament_type>` the material type, `<family_name>` the root's base name; the two config
|
||||||
is frozen in the file. Example: family `MyBrand PLA` in vendor `Orca 3D` mints `OFvCEY5V`.
|
values are inheritable list options and the first element counts. The key contains no bundle
|
||||||
|
name, so the same product mints the same id in every bundle — hoisting a family into
|
||||||
|
OrcaFilamentLibrary never changes its id. On the rare collision with any existing or retired
|
||||||
|
id, the minter salts the input (`…/1`, `…/2`, …) until free and the result is frozen in the
|
||||||
|
file. Example: `Polymaker/PLA/PolyLite PLA` mints `OF5CgdDq`.
|
||||||
|
|
||||||
Workflow for a new family:
|
Workflow for a new family:
|
||||||
|
|
||||||
@@ -101,8 +109,12 @@ python scripts/assign_filament_ids.py --check # 4. verify — the sam
|
|||||||
# 5. Commit the profile edits together with scripts/filament_id_snapshot.json.
|
# 5. Commit the profile edits together with scripts/filament_id_snapshot.json.
|
||||||
```
|
```
|
||||||
|
|
||||||
`--mint "Vendor/Family"` prints the id for one family without touching anything. The default
|
`--mint "filament_vendor/filament_type/family_name"` prints the id a triple would mint without
|
||||||
run is idempotent and never rewrites a valid existing id.
|
touching anything. The default run is idempotent and never rewrites a valid existing id.
|
||||||
|
Maintenance modes (normally only used by id migrations): `--remint VENDOR` re-derives a
|
||||||
|
vendor's declared ids from their triples, `--drop-redundant-ids VENDOR` deletes declarations
|
||||||
|
that merely re-declare an inherited OFL id, and `--add-hint "OLD=NEW"` records a cross-island
|
||||||
|
succession hint.
|
||||||
|
|
||||||
If you skip the tooling, CI fails and prints the remedy: the expected id for your family, and
|
If you skip the tooling, CI fails and prints the remedy: the expected id for your family, and
|
||||||
the instruction to run `python scripts/assign_filament_ids.py --update-snapshot` and commit
|
the instruction to run `python scripts/assign_filament_ids.py --update-snapshot` and commit
|
||||||
@@ -116,7 +128,20 @@ the resulting diff.
|
|||||||
| `QD_*` | Qidi device protocol | frozen device contract; Qidi vendor only |
|
| `QD_*` | Qidi device protocol | frozen device contract; Qidi vendor only |
|
||||||
| `P` + 7 hex chars (case-insensitive), `"null"` | user-created custom filaments (`CreatePresetsDialog.cpp`) | never appears in system profiles |
|
| `P` + 7 hex chars (case-insensitive), `"null"` | user-created custom filaments (`CreatePresetsDialog.cpp`) | never appears in system profiles |
|
||||||
| every already-shipped id | grandfather snapshot | frozen as-is; new claims need maintainer sign-off |
|
| every already-shipped id | grandfather snapshot | frozen as-is; new claims need maintainer sign-off |
|
||||||
| every retired id | `scripts/retired_filament_ids.json` | never used again, for anything |
|
| every retired id | `resources/profiles/retired_filament_ids.json` | never used again, for anything |
|
||||||
|
|
||||||
|
## The succession ledger
|
||||||
|
|
||||||
|
`resources/profiles/retired_filament_ids.json` ships with the app. Each retired id maps to
|
||||||
|
`{"claims": [...], "successor": <id|null>}` — successor chains are followed to the live end —
|
||||||
|
and a `hints` map carries the same forwarding for ids Orca cannot retire because another
|
||||||
|
island owns them (e.g. a `GF*` id whose material also exists as an OFL family). The client
|
||||||
|
consults the ledger **only on resolution miss** (AMS tray sync, tray-id type lookup,
|
||||||
|
calibration history, filament-id preset lookup): a live preset always wins first, so BBL
|
||||||
|
installs resolve `GF*` natively and behavior is unchanged wherever the raw id still exists.
|
||||||
|
This is what makes identity-driven re-mints (structure rule 5) safe: the old id keeps
|
||||||
|
resolving to the family's current preset instead of degrading to a `Generic <type>` fallback.
|
||||||
|
The file is append-only and maintained exclusively by `--update-snapshot` / `--add-hint`.
|
||||||
|
|
||||||
## How CI enforces this
|
## How CI enforces this
|
||||||
|
|
||||||
@@ -131,14 +156,22 @@ deterministically (running it twice changes nothing).
|
|||||||
The checks, in brief:
|
The checks, in brief:
|
||||||
|
|
||||||
- **Format** — every id is either in the snapshot, `OF` + 6 base62 chars, BBL's, or Qidi `QD_*`.
|
- **Format** — every id is either in the snapshot, `OF` + 6 base62 chars, BBL's, or Qidi `QD_*`.
|
||||||
- **Snapshot equality** — tree claims == snapshot claims, both directions.
|
- **Snapshot equality** — tree claims == snapshot claims **and** tree triples == snapshot
|
||||||
- **Mint conformance** — a non-grandfathered `OF*` claim must equal the mint (or a salt
|
triples, both directions: any `filament_vendor`/`filament_type`/family-name change surfaces
|
||||||
iteration) of its `(vendor, family)`; the error prints the expected id.
|
as a snapshot diff.
|
||||||
- **Retired reuse** — any tree id present in `scripts/retired_filament_ids.json` is an error.
|
- **Mint conformance** — a non-grandfathered `OF*` id must equal the mint (or a salt
|
||||||
|
iteration) of its declarer's product triple; the error prints the expected id.
|
||||||
|
- **Retired reuse** — any tree id present in `resources/profiles/retired_filament_ids.json` is an error.
|
||||||
Ids that fully vanish from the tree are appended there by `--update-snapshot`; the file is
|
Ids that fully vanish from the tree are appended there by `--update-snapshot`; the file is
|
||||||
**append-only**.
|
**append-only**.
|
||||||
- **Alias hygiene** — a tuned generic must keep the library preset's base name and a non-empty
|
- **Alias hygiene** — any vendor preset riding an OFL family id must keep the library
|
||||||
`compatible_printers` (structure rule 4); the error names the rename as the cause.
|
preset's base name, a non-empty `compatible_printers`, and no own id key (structure rule 4);
|
||||||
|
the error names the rename as the cause.
|
||||||
|
- **Triple integrity** — every declarer outside the BBL/`QD_*` islands must resolve a
|
||||||
|
non-empty `filament_vendor` and `filament_type` (generics use `"Generic"`), and all
|
||||||
|
declarers of one family within a bundle must agree on the triple.
|
||||||
|
- **Succession integrity** — retired successor chains terminate at a live id (or null) with
|
||||||
|
no cycles; `hints` keys are live, island-owned ids.
|
||||||
- **Reserved namespaces** — `GF*` outside BBL, `QD_*` outside Qidi, `P<7-hex>` or `null`
|
- **Reserved namespaces** — `GF*` outside BBL, `QD_*` outside Qidi, `P<7-hex>` or `null`
|
||||||
anywhere, unless that exact claim is grandfathered in the snapshot.
|
anywhere, unless that exact claim is grandfathered in the snapshot.
|
||||||
- **Structure** — no `filament_id` key on instantiated presets; no declared-vs-inherited id
|
- **Structure** — no `filament_id` key on instantiated presets; no declared-vs-inherited id
|
||||||
@@ -161,7 +194,10 @@ check instead.
|
|||||||
inherit the family's root, write no id key.
|
inherit the family's root, write no id key.
|
||||||
- **A tuned generic ("our profile for Generic PLA")?** Inherit `Generic PLA @System`, keep the
|
- **A tuned generic ("our profile for Generic PLA")?** Inherit `Generic PLA @System`, keep the
|
||||||
`Generic PLA` base name, set `compatible_printers`, write no id key.
|
`Generic PLA` base name, set `compatible_printers`, write no id key.
|
||||||
- **I need to rename a family.** Keep the id, add `renamed_from`. Ids never change.
|
- **I need to rename a family (or fix its `filament_vendor`/`filament_type`).** Add
|
||||||
|
`renamed_from` for the name, run `--remint <Vendor>` then `--update-snapshot`: the id
|
||||||
|
re-derives from the corrected identity and the old id lands in the succession ledger
|
||||||
|
pointing at the new one. Commit the profile, snapshot, and ledger diffs together.
|
||||||
- **CI says my family needs an id.** Run `python scripts/assign_filament_ids.py`, then
|
- **CI says my family needs an id.** Run `python scripts/assign_filament_ids.py`, then
|
||||||
`--update-snapshot`, and commit both diffs. Do not type an id by hand.
|
`--update-snapshot`, and commit both diffs. Do not type an id by hand.
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,12 @@ holding OFL-only materials, on-device PA-calibration records, user-root preset c
|
|||||||
followed to the live end). A retired id may never be minted again (check 4 unchanged).
|
followed to the live end). A retired id may never be minted again (check 4 unchanged).
|
||||||
Cross-island *hint* entries are permitted for ids Orca cannot retire because another
|
Cross-island *hint* entries are permitted for ids Orca cannot retire because another
|
||||||
island owns them (e.g. `GFL99 → <OFL Generic PLA id>`): consulted only when no live
|
island owns them (e.g. `GFL99 → <OFL Generic PLA id>`): consulted only when no live
|
||||||
preset matches, so BBL installs still resolve `GFL99` natively first.
|
preset matches, so BBL installs still resolve `GFL99` natively first. By the same
|
||||||
|
principle, an id in a foreign island's space (`GF*`/`QD_*`) that vanishes from the tree
|
||||||
|
is **released with a hint, never retired** — the island's catalog owns it and may
|
||||||
|
legitimately (re)ship it later, which check 4 must never block. (Implementation
|
||||||
|
amendment, v3.0: `--update-snapshot` routes such ids to `hints` automatically; hint
|
||||||
|
keys may be absent from the tree.)
|
||||||
- **Shipped and consulted at runtime.** The ledger ships in `resources/`; a small helper
|
- **Shipped and consulted at runtime.** The ledger ships in `resources/`; a small helper
|
||||||
(`resolve_filament_id_succession(id)`) follows the chain and is consulted **only on
|
(`resolve_filament_id_succession(id)`) follows the chain and is consulted **only on
|
||||||
resolution miss**, before the `Generic <type>` name fallback, in:
|
resolution miss**, before the `Generic <type>` name fallback, in:
|
||||||
@@ -134,8 +139,9 @@ those families twice.
|
|||||||
|
|
||||||
**v3.1 — OFL re-mint.** Every OFL-declared id re-derives from its triple (mirrors like
|
**v3.1 — OFL re-mint.** Every OFL-declared id re-derives from its triple (mirrors like
|
||||||
`OGFA00`, generics like `OGFL99`, blocks like `OEPLAB00` — all of it); each old shipped id
|
`OGFA00`, generics like `OGFL99`, blocks like `OEPLAB00` — all of it); each old shipped id
|
||||||
gains a succession entry pointing at its replacement; the 26 BBL×OFL byte-shared ids
|
gains a succession entry pointing at its replacement; the 26 GF-shaped ids OFL declares
|
||||||
dissolve (BBL keeps its id; the OFL family gets its own — two-island purity). Snapshot
|
(measured at v3.0: only one of them, `GFOT001`, is also declared by BBL) are released to
|
||||||
|
the BBL island space with hints at the re-minted families — two-island purity. Snapshot
|
||||||
regenerated; full gate battery + fixture overlays (this phase touches preset-visibility
|
regenerated; full gate battery + fixture overlays (this phase touches preset-visibility
|
||||||
machinery only via ids, but the fixtures are cheap insurance).
|
machinery only via ids, but the fixtures are cheap insurance).
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"Anycubic"
|
"Anycubic"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PEBA"
|
"TPU"
|
||||||
],
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Anycubic Kobra S1 Max 0.6 nozzle"
|
"Anycubic Kobra S1 Max 0.6 nozzle"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"Anycubic"
|
"Anycubic"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"TPU for ACE"
|
"TPU"
|
||||||
],
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Anycubic Kobra S1 Max 0.4 nozzle"
|
"Anycubic Kobra S1 Max 0.4 nozzle"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"Anycubic"
|
"Anycubic"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PEBA"
|
"TPU"
|
||||||
],
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Anycubic Kobra S1 Max 0.6 nozzle"
|
"Anycubic Kobra S1 Max 0.6 nozzle"
|
||||||
|
|||||||
@@ -87,7 +87,7 @@
|
|||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PA-CF"
|
"PA6-CF"
|
||||||
],
|
],
|
||||||
"filament_vendor": [
|
"filament_vendor": [
|
||||||
"Generic"
|
"Generic"
|
||||||
|
|||||||
@@ -87,7 +87,7 @@
|
|||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PA-CF"
|
"PA6-CF"
|
||||||
],
|
],
|
||||||
"filament_vendor": [
|
"filament_vendor": [
|
||||||
"Generic"
|
"Generic"
|
||||||
|
|||||||
@@ -87,7 +87,7 @@
|
|||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PA-CF"
|
"PA6-CF"
|
||||||
],
|
],
|
||||||
"filament_vendor": [
|
"filament_vendor": [
|
||||||
"Generic"
|
"Generic"
|
||||||
|
|||||||
@@ -87,7 +87,7 @@
|
|||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PA-CF"
|
"PA6-CF"
|
||||||
],
|
],
|
||||||
"filament_vendor": [
|
"filament_vendor": [
|
||||||
"Generic"
|
"Generic"
|
||||||
|
|||||||
@@ -84,7 +84,7 @@
|
|||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PA-CF"
|
"PA6-CF"
|
||||||
],
|
],
|
||||||
"filament_vendor": [
|
"filament_vendor": [
|
||||||
"Generic"
|
"Generic"
|
||||||
|
|||||||
@@ -84,7 +84,7 @@
|
|||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PA-CF"
|
"PA6-CF"
|
||||||
],
|
],
|
||||||
"filament_vendor": [
|
"filament_vendor": [
|
||||||
"Generic"
|
"Generic"
|
||||||
|
|||||||
@@ -39,6 +39,9 @@
|
|||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n;right_extruder_material: ABS-CF\n"
|
"; filament start gcode\n;right_extruder_material: ABS-CF\n"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"ABS-CF"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 0.4 nozzle"
|
"Flashforge Guider4 0.4 nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -39,6 +39,9 @@
|
|||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n;right_extruder_material: ABS-CF\n"
|
"; filament start gcode\n;right_extruder_material: ABS-CF\n"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"ABS-CF"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 Pro 0.4 nozzle"
|
"Flashforge Guider4 Pro 0.4 nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -27,6 +27,9 @@
|
|||||||
"filament_settings_id": [
|
"filament_settings_id": [
|
||||||
"Flashforge ASA Basic @FF AD5X 0.6 nozzle"
|
"Flashforge ASA Basic @FF AD5X 0.6 nozzle"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"ASA"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge AD5X 0.6 nozzle"
|
"Flashforge AD5X 0.6 nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -27,6 +27,9 @@
|
|||||||
"filament_settings_id": [
|
"filament_settings_id": [
|
||||||
"Flashforge ASA Basic @FF AD5X 0.8 nozzle"
|
"Flashforge ASA Basic @FF AD5X 0.8 nozzle"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"ASA"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge AD5X 0.8 nozzle"
|
"Flashforge AD5X 0.8 nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -27,6 +27,9 @@
|
|||||||
"filament_settings_id": [
|
"filament_settings_id": [
|
||||||
"Flashforge ASA Basic @FF AD5X"
|
"Flashforge ASA Basic @FF AD5X"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"ASA"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge AD5X 0.4 nozzle"
|
"Flashforge AD5X 0.4 nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
"; filament start gcode\n;right_extruder_material: ASA-CF\n"
|
"; filament start gcode\n;right_extruder_material: ASA-CF\n"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"ASA"
|
"ASA-CF"
|
||||||
],
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 0.4 nozzle"
|
"Flashforge Guider4 0.4 nozzle"
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
"; filament start gcode\n;right_extruder_material: ASA-CF\n"
|
"; filament start gcode\n;right_extruder_material: ASA-CF\n"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"ASA"
|
"ASA-CF"
|
||||||
],
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 Pro 0.4 nozzle"
|
"Flashforge Guider4 Pro 0.4 nozzle"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"Flashforge ASA-CF"
|
"Flashforge ASA-CF"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"ASA"
|
"ASA-CF"
|
||||||
],
|
],
|
||||||
"hot_plate_temp": [
|
"hot_plate_temp": [
|
||||||
"100"
|
"100"
|
||||||
|
|||||||
@@ -63,6 +63,9 @@
|
|||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n;right_extruder_material:HIPS"
|
"; filament start gcode\n;right_extruder_material:HIPS"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"HIPS"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 0.6 HF nozzle"
|
"Flashforge Guider4 0.6 HF nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -63,6 +63,9 @@
|
|||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n;right_extruder_material:HIPS"
|
"; filament start gcode\n;right_extruder_material:HIPS"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"HIPS"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 0.6 nozzle"
|
"Flashforge Guider4 0.6 nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -63,6 +63,9 @@
|
|||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n;right_extruder_material:HIPS"
|
"; filament start gcode\n;right_extruder_material:HIPS"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"HIPS"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 0.8 HF nozzle"
|
"Flashforge Guider4 0.8 HF nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -63,6 +63,9 @@
|
|||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n;right_extruder_material:HIPS"
|
"; filament start gcode\n;right_extruder_material:HIPS"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"HIPS"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 Pro 0.6 HF nozzle"
|
"Flashforge Guider4 Pro 0.6 HF nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -63,6 +63,9 @@
|
|||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n;right_extruder_material:HIPS"
|
"; filament start gcode\n;right_extruder_material:HIPS"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"HIPS"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 Pro 0.6 nozzle"
|
"Flashforge Guider4 Pro 0.6 nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -63,6 +63,9 @@
|
|||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n;right_extruder_material:HIPS"
|
"; filament start gcode\n;right_extruder_material:HIPS"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"HIPS"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 Pro 0.8 HF nozzle"
|
"Flashforge Guider4 Pro 0.8 HF nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
"; filament start gcode\n;right_extruder_material:PA-CF\n"
|
"; filament start gcode\n;right_extruder_material:PA-CF\n"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PA-CF"
|
"PAHT-CF"
|
||||||
],
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 0.4 nozzle"
|
"Flashforge Guider4 0.4 nozzle"
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
"; filament start gcode\n;right_extruder_material:PA-CF\n"
|
"; filament start gcode\n;right_extruder_material:PA-CF\n"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PA-CF"
|
"PAHT-CF"
|
||||||
],
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 Pro 0.4 nozzle"
|
"Flashforge Guider4 Pro 0.4 nozzle"
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
"Flashforge PLA Silk @FF AD5X 0.25 nozzle"
|
"Flashforge PLA Silk @FF AD5X 0.25 nozzle"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"SILK"
|
"PLA"
|
||||||
],
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge AD5X 0.25 nozzle"
|
"Flashforge AD5X 0.25 nozzle"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
"Flashforge PLA Silk @FF AD5X 0.6 nozzle"
|
"Flashforge PLA Silk @FF AD5X 0.6 nozzle"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"SILK"
|
"PLA"
|
||||||
],
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge AD5X 0.6 nozzle"
|
"Flashforge AD5X 0.6 nozzle"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
"Flashforge PLA Silk @FF AD5X 0.8 nozzle"
|
"Flashforge PLA Silk @FF AD5X 0.8 nozzle"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"SILK"
|
"PLA"
|
||||||
],
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge AD5X 0.8 nozzle"
|
"Flashforge AD5X 0.8 nozzle"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
"Flashforge PLA Silk @FF AD5X"
|
"Flashforge PLA Silk @FF AD5X"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"SILK"
|
"PLA"
|
||||||
],
|
],
|
||||||
"hot_plate_temp": [
|
"hot_plate_temp": [
|
||||||
"60"
|
"60"
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
"; filament start gcode"
|
"; filament start gcode"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"SILK"
|
"PLA"
|
||||||
],
|
],
|
||||||
"hot_plate_temp": [
|
"hot_plate_temp": [
|
||||||
"65"
|
"65"
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
"; filament start gcode"
|
"; filament start gcode"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"SILK"
|
"PLA"
|
||||||
],
|
],
|
||||||
"nozzle_temperature": [
|
"nozzle_temperature": [
|
||||||
"230"
|
"230"
|
||||||
|
|||||||
@@ -36,6 +36,9 @@
|
|||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n;right_extruder_material:PA"
|
"; filament start gcode\n;right_extruder_material:PA"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"PAHT"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 0.6 HF nozzle"
|
"Flashforge Guider4 0.6 HF nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -36,6 +36,9 @@
|
|||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n;right_extruder_material:PA"
|
"; filament start gcode\n;right_extruder_material:PA"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"PAHT"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 0.8 HF nozzle"
|
"Flashforge Guider4 0.8 HF nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -36,6 +36,9 @@
|
|||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n;right_extruder_material:PA"
|
"; filament start gcode\n;right_extruder_material:PA"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"PAHT"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 Pro 0.6 HF nozzle"
|
"Flashforge Guider4 Pro 0.6 HF nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -36,6 +36,9 @@
|
|||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n;right_extruder_material:PA"
|
"; filament start gcode\n;right_extruder_material:PA"
|
||||||
],
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"PAHT"
|
||||||
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 Pro 0.8 HF nozzle"
|
"Flashforge Guider4 Pro 0.8 HF nozzle"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
"; filament start gcode\n;right_extruder_material:PA-CF\n"
|
"; filament start gcode\n;right_extruder_material:PA-CF\n"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PA-CF"
|
"PAHT-CF"
|
||||||
],
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 0.4 nozzle"
|
"Flashforge Guider4 0.4 nozzle"
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
"; filament start gcode\n;right_extruder_material:PA-CF\n"
|
"; filament start gcode\n;right_extruder_material:PA-CF\n"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PA-CF"
|
"PAHT-CF"
|
||||||
],
|
],
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Flashforge Guider4 Pro 0.4 nozzle"
|
"Flashforge Guider4 Pro 0.4 nozzle"
|
||||||
|
|||||||
@@ -168,7 +168,7 @@
|
|||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PA-CF"
|
"PAHT-CF"
|
||||||
],
|
],
|
||||||
"filament_unload_time": [
|
"filament_unload_time": [
|
||||||
"0"
|
"0"
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
"; filament start gcode"
|
"; filament start gcode"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"SILK"
|
"PLA"
|
||||||
],
|
],
|
||||||
"hot_plate_temp": [
|
"hot_plate_temp": [
|
||||||
"65"
|
"65"
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
"; filament start gcode"
|
"; filament start gcode"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"SILK"
|
"PLA"
|
||||||
],
|
],
|
||||||
"nozzle_temperature": [
|
"nozzle_temperature": [
|
||||||
"230"
|
"230"
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
"12"
|
"12"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PETG Basic"
|
"PETG"
|
||||||
],
|
],
|
||||||
"filament_density": [
|
"filament_density": [
|
||||||
"1.27"
|
"1.27"
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
"12"
|
"12"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PETG Basic"
|
"PETG"
|
||||||
],
|
],
|
||||||
"filament_density": [
|
"filament_density": [
|
||||||
"1.27"
|
"1.27"
|
||||||
|
|||||||
@@ -4,5 +4,8 @@
|
|||||||
"inherits": "fdm_filament_pe",
|
"inherits": "fdm_filament_pe",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "OFJfx0Cl",
|
"filament_id": "OFJfx0Cl",
|
||||||
"instantiation": "false"
|
"instantiation": "false",
|
||||||
|
"filament_type": [
|
||||||
|
"PE-CF"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,5 +4,8 @@
|
|||||||
"inherits": "fdm_filament_pet",
|
"inherits": "fdm_filament_pet",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "OFDCk0cz",
|
"filament_id": "OFDCk0cz",
|
||||||
"instantiation": "false"
|
"instantiation": "false",
|
||||||
|
"filament_type": [
|
||||||
|
"PETG-CF"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,5 +4,8 @@
|
|||||||
"inherits": "fdm_filament_pp",
|
"inherits": "fdm_filament_pp",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "OFRS2Ggt",
|
"filament_id": "OFRS2Ggt",
|
||||||
"instantiation": "false"
|
"instantiation": "false",
|
||||||
|
"filament_type": [
|
||||||
|
"PP-CF"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,5 +4,8 @@
|
|||||||
"inherits": "fdm_filament_pa",
|
"inherits": "fdm_filament_pa",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "OFXfgh61",
|
"filament_id": "OFXfgh61",
|
||||||
"instantiation": "false"
|
"instantiation": "false",
|
||||||
|
"filament_type": [
|
||||||
|
"PA-CF"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,5 +4,8 @@
|
|||||||
"inherits": "fdm_filament_pla",
|
"inherits": "fdm_filament_pla",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "OFv8SRZh",
|
"filament_id": "OFv8SRZh",
|
||||||
"instantiation": "false"
|
"instantiation": "false",
|
||||||
|
"filament_type": [
|
||||||
|
"PLA-CF"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,9 @@
|
|||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PLA"
|
"PLA"
|
||||||
],
|
],
|
||||||
|
"filament_vendor": [
|
||||||
|
"Snapmaker"
|
||||||
|
],
|
||||||
"filament_density": [
|
"filament_density": [
|
||||||
"1.24"
|
"1.24"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -46,6 +46,9 @@
|
|||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PLA"
|
"PLA"
|
||||||
],
|
],
|
||||||
|
"filament_vendor": [
|
||||||
|
"Snapmaker"
|
||||||
|
],
|
||||||
"filament_density": [
|
"filament_density": [
|
||||||
"1.24"
|
"1.24"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -46,6 +46,9 @@
|
|||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PLA"
|
"PLA"
|
||||||
],
|
],
|
||||||
|
"filament_vendor": [
|
||||||
|
"Snapmaker"
|
||||||
|
],
|
||||||
"filament_density": [
|
"filament_density": [
|
||||||
"1.24"
|
"1.24"
|
||||||
],
|
],
|
||||||
|
|||||||
90
resources/profiles/retired_filament_ids.json
Normal file
90
resources/profiles/retired_filament_ids.json
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
{
|
||||||
|
"hints": {},
|
||||||
|
"retired": {
|
||||||
|
"GFABS": {
|
||||||
|
"claims": [
|
||||||
|
"Anycubic/Anycubic ABS"
|
||||||
|
],
|
||||||
|
"successor": "OFf2b9wu"
|
||||||
|
},
|
||||||
|
"GFL92": {
|
||||||
|
"claims": [
|
||||||
|
"Anycubic/Anycubic PLA"
|
||||||
|
],
|
||||||
|
"successor": "OFgK2Xvv"
|
||||||
|
},
|
||||||
|
"GFL93": {
|
||||||
|
"claims": [
|
||||||
|
"Anycubic/Anycubic PLA+"
|
||||||
|
],
|
||||||
|
"successor": "OFgrGfPy"
|
||||||
|
},
|
||||||
|
"GFPLA": {
|
||||||
|
"claims": [
|
||||||
|
"Anycubic/Anycubic PLA"
|
||||||
|
],
|
||||||
|
"successor": "OFgK2Xvv"
|
||||||
|
},
|
||||||
|
"GFPLA High Speed": {
|
||||||
|
"claims": [
|
||||||
|
"Anycubic/Anycubic PLA High Speed"
|
||||||
|
],
|
||||||
|
"successor": "OFgSK1hL"
|
||||||
|
},
|
||||||
|
"GFPLA Matte": {
|
||||||
|
"claims": [
|
||||||
|
"Anycubic/Anycubic PLA Matte"
|
||||||
|
],
|
||||||
|
"successor": "OFvYfHPB"
|
||||||
|
},
|
||||||
|
"GFPLA Silk": {
|
||||||
|
"claims": [
|
||||||
|
"Anycubic/Anycubic PLA Silk"
|
||||||
|
],
|
||||||
|
"successor": "OFjdTQd6"
|
||||||
|
},
|
||||||
|
"GFPLA+": {
|
||||||
|
"claims": [
|
||||||
|
"Anycubic/Anycubic PLA+"
|
||||||
|
],
|
||||||
|
"successor": "OFgrGfPy"
|
||||||
|
},
|
||||||
|
"P11851ba": {
|
||||||
|
"claims": [
|
||||||
|
"Artillery/Artillery PET"
|
||||||
|
],
|
||||||
|
"successor": "OFw0qp7w"
|
||||||
|
},
|
||||||
|
"P284941e": {
|
||||||
|
"claims": [
|
||||||
|
"Artillery/Artillery PETG",
|
||||||
|
"Artillery/Artillery PETG Basic"
|
||||||
|
],
|
||||||
|
"successor": "OFEYKrjb"
|
||||||
|
},
|
||||||
|
"P2fbf0c0": {
|
||||||
|
"claims": [
|
||||||
|
"Artillery/Artillery TPU"
|
||||||
|
],
|
||||||
|
"successor": "OFTbsWVg"
|
||||||
|
},
|
||||||
|
"P39db358": {
|
||||||
|
"claims": [
|
||||||
|
"Artillery/Artillery ABS"
|
||||||
|
],
|
||||||
|
"successor": "OFw1S8lL"
|
||||||
|
},
|
||||||
|
"P8163162": {
|
||||||
|
"claims": [
|
||||||
|
"Artillery/Artillery PVA"
|
||||||
|
],
|
||||||
|
"successor": "OFc2SnEp"
|
||||||
|
},
|
||||||
|
"P87436f6": {
|
||||||
|
"claims": [
|
||||||
|
"Artillery/Artillery ASA"
|
||||||
|
],
|
||||||
|
"successor": "OFtmT4Nd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,47 +0,0 @@
|
|||||||
{
|
|
||||||
"retired": {
|
|
||||||
"GFABS": [
|
|
||||||
"Anycubic/Anycubic ABS"
|
|
||||||
],
|
|
||||||
"GFL92": [
|
|
||||||
"Anycubic/Anycubic PLA"
|
|
||||||
],
|
|
||||||
"GFL93": [
|
|
||||||
"Anycubic/Anycubic PLA+"
|
|
||||||
],
|
|
||||||
"GFPLA": [
|
|
||||||
"Anycubic/Anycubic PLA"
|
|
||||||
],
|
|
||||||
"GFPLA High Speed": [
|
|
||||||
"Anycubic/Anycubic PLA High Speed"
|
|
||||||
],
|
|
||||||
"GFPLA Matte": [
|
|
||||||
"Anycubic/Anycubic PLA Matte"
|
|
||||||
],
|
|
||||||
"GFPLA Silk": [
|
|
||||||
"Anycubic/Anycubic PLA Silk"
|
|
||||||
],
|
|
||||||
"GFPLA+": [
|
|
||||||
"Anycubic/Anycubic PLA+"
|
|
||||||
],
|
|
||||||
"P11851ba": [
|
|
||||||
"Artillery/Artillery PET"
|
|
||||||
],
|
|
||||||
"P284941e": [
|
|
||||||
"Artillery/Artillery PETG",
|
|
||||||
"Artillery/Artillery PETG Basic"
|
|
||||||
],
|
|
||||||
"P2fbf0c0": [
|
|
||||||
"Artillery/Artillery TPU"
|
|
||||||
],
|
|
||||||
"P39db358": [
|
|
||||||
"Artillery/Artillery ABS"
|
|
||||||
],
|
|
||||||
"P8163162": [
|
|
||||||
"Artillery/Artillery PVA"
|
|
||||||
],
|
|
||||||
"P87436f6": [
|
|
||||||
"Artillery/Artillery ASA"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,10 +5,15 @@ Inserts/deletes/modifies random lane data in Moonraker database,
|
|||||||
then reads back and displays with colored output.
|
then reads back and displays with colored output.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import requests
|
try:
|
||||||
|
import requests
|
||||||
|
except ImportError:
|
||||||
|
requests = None # only needed for live-printer operations, not --check-ofl-map
|
||||||
import random
|
import random
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
import time
|
import time
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@@ -16,6 +21,11 @@ import sys
|
|||||||
DEFAULT_HOST = "192.168.88.9"
|
DEFAULT_HOST = "192.168.88.9"
|
||||||
DEFAULT_PORT = 7125
|
DEFAULT_PORT = 7125
|
||||||
NAMESPACE = "lane_data"
|
NAMESPACE = "lane_data"
|
||||||
|
|
||||||
|
# Repo-relative paths for the offline generic-map check
|
||||||
|
REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
MOONRAKER_AGENT_CPP = os.path.join(REPO_ROOT, "src", "slic3r", "Utils", "MoonrakerPrinterAgent.cpp")
|
||||||
|
OFL_FILAMENT_DIR = os.path.join(REPO_ROOT, "resources", "profiles", "OrcaFilamentLibrary", "filament")
|
||||||
LANE_KEYS = [f"lane{i}" for i in range(1, 9)] # lane1-lane8
|
LANE_KEYS = [f"lane{i}" for i in range(1, 9)] # lane1-lane8
|
||||||
MATERIALS = ["PLA", "ABS", "PETG", "ASA", "ASA Sparkle", "TPU", ""]
|
MATERIALS = ["PLA", "ABS", "PETG", "ASA", "ASA Sparkle", "TPU", ""]
|
||||||
|
|
||||||
@@ -30,6 +40,95 @@ MATERIAL_TEMPS = {
|
|||||||
"": {"nozzle": None, "bed": None},
|
"": {"nozzle": None, "bed": None},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def parse_cpp_type_map():
|
||||||
|
"""Extract the normalized-type -> OFL generic family table from MoonrakerPrinterAgent.cpp.
|
||||||
|
|
||||||
|
Reads MoonrakerPrinterAgent::map_filament_type_to_generic_id's type_to_ofl_family
|
||||||
|
initializer so the check tracks the C++ normalization without a duplicated list.
|
||||||
|
"""
|
||||||
|
with open(MOONRAKER_AGENT_CPP, encoding="utf-8") as f:
|
||||||
|
src = f.read()
|
||||||
|
m = re.search(r"type_to_ofl_family\s*=\s*\{(.*?)\n\s*\};", src, re.DOTALL)
|
||||||
|
if not m:
|
||||||
|
raise RuntimeError(f"type_to_ofl_family table not found in {MOONRAKER_AGENT_CPP}")
|
||||||
|
pairs = re.findall(r'\{\s*"([^"]+)"\s*,\s*"([^"]+)"\s*\}', m.group(1))
|
||||||
|
if not pairs:
|
||||||
|
raise RuntimeError("type_to_ofl_family table parsed empty")
|
||||||
|
return dict(pairs)
|
||||||
|
|
||||||
|
def load_ofl_presets():
|
||||||
|
"""Map preset name -> parsed JSON for every OrcaFilamentLibrary filament profile."""
|
||||||
|
presets = {}
|
||||||
|
for root, _dirs, files in os.walk(OFL_FILAMENT_DIR):
|
||||||
|
for fn in files:
|
||||||
|
if not fn.endswith(".json"):
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
with open(os.path.join(root, fn), encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
except (OSError, ValueError):
|
||||||
|
continue
|
||||||
|
name = data.get("name")
|
||||||
|
if isinstance(name, str) and name:
|
||||||
|
presets[name] = data
|
||||||
|
return presets
|
||||||
|
|
||||||
|
def resolve_ofl_filament_id(presets, name):
|
||||||
|
"""Follow the inherits chain (within OFL) until a filament_id is declared."""
|
||||||
|
seen = set()
|
||||||
|
while name and name not in seen:
|
||||||
|
seen.add(name)
|
||||||
|
preset = presets.get(name)
|
||||||
|
if preset is None:
|
||||||
|
return None
|
||||||
|
fid = preset.get("filament_id")
|
||||||
|
if fid:
|
||||||
|
return fid
|
||||||
|
name = preset.get("inherits")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def check_ofl_generic_map():
|
||||||
|
"""Assert every material type the C++ normalization handles resolves to a shipped
|
||||||
|
OrcaFilamentLibrary generic preset carrying a filament_id.
|
||||||
|
|
||||||
|
Expectations are derived from the shipped profiles, not pinned id literals, so the
|
||||||
|
check stays valid across filament_id re-mints.
|
||||||
|
"""
|
||||||
|
print("Checking C++ generic-type map against shipped OrcaFilamentLibrary presets...")
|
||||||
|
try:
|
||||||
|
type_map = parse_cpp_type_map()
|
||||||
|
except (OSError, RuntimeError) as e:
|
||||||
|
print(f" FAIL: {e}")
|
||||||
|
return False
|
||||||
|
presets = load_ofl_presets()
|
||||||
|
if not presets:
|
||||||
|
print(f" FAIL: no OFL filament profiles found under {OFL_FILAMENT_DIR}")
|
||||||
|
return False
|
||||||
|
errors = []
|
||||||
|
for family in sorted(set(type_map.values())):
|
||||||
|
preset_name = f"Generic {family} @System"
|
||||||
|
if preset_name not in presets:
|
||||||
|
errors.append(f"{preset_name}: no such OFL preset")
|
||||||
|
continue
|
||||||
|
if str(presets[preset_name].get("instantiation", "")).lower() != "true":
|
||||||
|
errors.append(f"{preset_name}: not instantiated — the C++ runtime lookup "
|
||||||
|
f"only sees presets loaded into the PresetBundle")
|
||||||
|
continue
|
||||||
|
fid = resolve_ofl_filament_id(presets, preset_name)
|
||||||
|
if not fid:
|
||||||
|
errors.append(f"{preset_name}: no filament_id resolvable through inherits")
|
||||||
|
continue
|
||||||
|
aliases = ", ".join(sorted(t for t, fam in type_map.items() if fam == family))
|
||||||
|
print(f" {fid:10s} {preset_name:32s} <- {aliases}")
|
||||||
|
if errors:
|
||||||
|
for e in errors:
|
||||||
|
print(f" FAIL: {e}")
|
||||||
|
print(f"OFL generic map check FAILED ({len(errors)} error(s))")
|
||||||
|
return False
|
||||||
|
print(f"OFL generic map check passed: {len(type_map)} type aliases, "
|
||||||
|
f"{len(set(type_map.values()))} OFL generic presets\n")
|
||||||
|
return True
|
||||||
|
|
||||||
def test_connection(host, port, api_key=None, verbose=False):
|
def test_connection(host, port, api_key=None, verbose=False):
|
||||||
"""Test basic connectivity to Moonraker."""
|
"""Test basic connectivity to Moonraker."""
|
||||||
url = f"http://{host}:{port}/server/info"
|
url = f"http://{host}:{port}/server/info"
|
||||||
@@ -404,11 +503,25 @@ def main():
|
|||||||
help="Only read and display current lane data")
|
help="Only read and display current lane data")
|
||||||
parser.add_argument("--load", metavar="FILE",
|
parser.add_argument("--load", metavar="FILE",
|
||||||
help="Load lane data from JSON file and overwrite printer lanes")
|
help="Load lane data from JSON file and overwrite printer lanes")
|
||||||
|
parser.add_argument("--check-ofl-map", action="store_true",
|
||||||
|
help="Only run the offline check that the C++ generic-type map "
|
||||||
|
"resolves against shipped OrcaFilamentLibrary presets")
|
||||||
parser.add_argument("--verbose", "-v", action="store_true",
|
parser.add_argument("--verbose", "-v", action="store_true",
|
||||||
help="Verbose output for debugging")
|
help="Verbose output for debugging")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Offline check first: the C++ type normalization must resolve against shipped
|
||||||
|
# OFL presets (no printer needed).
|
||||||
|
if not check_ofl_generic_map():
|
||||||
|
return 1
|
||||||
|
if args.check_ofl_map:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if requests is None:
|
||||||
|
print("The 'requests' module is required for live printer operations (pip install requests).")
|
||||||
|
return 1
|
||||||
|
|
||||||
print(f"\nConnecting to Moonraker at {args.host}:{args.port}...")
|
print(f"\nConnecting to Moonraker at {args.host}:{args.port}...")
|
||||||
|
|
||||||
# First test basic connectivity
|
# First test basic connectivity
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -555,6 +555,60 @@ std::string generate_preset_setting_id(const std::string& vendor, const std::str
|
|||||||
return std::string(out, 16);
|
return std::string(out, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string follow_filament_id_succession(const std::string& id, const std::map<std::string, std::string>& forwards)
|
||||||
|
{
|
||||||
|
auto it = forwards.find(id);
|
||||||
|
if (it == forwards.end())
|
||||||
|
return std::string();
|
||||||
|
std::set<std::string> visited { id };
|
||||||
|
std::string current = id;
|
||||||
|
while (it != forwards.end() && visited.insert(it->second).second) {
|
||||||
|
current = it->second;
|
||||||
|
it = forwards.find(current);
|
||||||
|
}
|
||||||
|
// it == end(): current is the live end of the chain; otherwise the ledger is
|
||||||
|
// cyclic and current is the last id reached before a repeat.
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::map<std::string, std::string>& filament_id_succession_map()
|
||||||
|
{
|
||||||
|
// Loaded once; C++11 magic-static initialization makes this thread-safe.
|
||||||
|
// Succession is a best-effort miss-path fallback, so a missing or corrupt
|
||||||
|
// ledger is not an error for the client - it just yields an empty map.
|
||||||
|
static const std::map<std::string, std::string> forwards = []() {
|
||||||
|
std::map<std::string, std::string> map;
|
||||||
|
const std::string path = Slic3r::resources_dir() + "/profiles/retired_filament_ids.json";
|
||||||
|
boost::nowide::ifstream file(path.c_str());
|
||||||
|
if (!file.is_open()) {
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": cannot open " << path;
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
nlohmann::json ledger;
|
||||||
|
file >> ledger;
|
||||||
|
if (ledger.contains("retired") && ledger["retired"].is_object())
|
||||||
|
for (auto& [old_id, entry] : ledger["retired"].items())
|
||||||
|
if (entry.is_object() && entry.contains("successor") && entry["successor"].is_string())
|
||||||
|
map[old_id] = entry["successor"].get<std::string>();
|
||||||
|
if (ledger.contains("hints") && ledger["hints"].is_object())
|
||||||
|
for (auto& [old_id, target] : ledger["hints"].items())
|
||||||
|
if (target.is_string())
|
||||||
|
map[old_id] = target.get<std::string>();
|
||||||
|
} catch (...) {
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": failed to parse " << path;
|
||||||
|
map.clear();
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}();
|
||||||
|
return forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string resolve_filament_id_succession(const std::string& id)
|
||||||
|
{
|
||||||
|
return follow_filament_id_succession(id, filament_id_succession_map());
|
||||||
|
}
|
||||||
|
|
||||||
std::string Preset::get_iot_type_string(Preset::Type type)
|
std::string Preset::get_iot_type_string(Preset::Type type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|||||||
@@ -100,6 +100,23 @@ std::string generate_preset_setting_id(const std::string& vendor,
|
|||||||
const std::string& type,
|
const std::string& type,
|
||||||
const std::string& name);
|
const std::string& name);
|
||||||
|
|
||||||
|
// Succession forwarding for retired/renamed filament_ids, backed by the shipped
|
||||||
|
// ledger resources/profiles/retired_filament_ids.json. Consulted on a filament_id
|
||||||
|
// resolution miss only, so live ids always resolve natively first.
|
||||||
|
//
|
||||||
|
// Pure chain walk over `forwards` (old id -> successor). Returns the final id of the
|
||||||
|
// chain, or an empty string when `id` has no entry. Cycle-guarded: on a malformed
|
||||||
|
// cyclic ledger it stops at the last id reached before any repeat (a self-loop
|
||||||
|
// returns `id` itself).
|
||||||
|
std::string follow_filament_id_succession(const std::string& id,
|
||||||
|
const std::map<std::string, std::string>& forwards);
|
||||||
|
// Forwarding map loaded once (thread-safe) from the ledger, merging
|
||||||
|
// "retired" {id -> non-null successor} and "hints" {island-owned id -> live id}.
|
||||||
|
// A missing or corrupt file yields an empty map.
|
||||||
|
const std::map<std::string, std::string>& filament_id_succession_map();
|
||||||
|
// Convenience: follow_filament_id_succession(id, filament_id_succession_map()).
|
||||||
|
std::string resolve_filament_id_succession(const std::string& id);
|
||||||
|
|
||||||
enum ConfigFileType
|
enum ConfigFileType
|
||||||
{
|
{
|
||||||
CONFIG_FILE_TYPE_UNKNOWN,
|
CONFIG_FILE_TYPE_UNKNOWN,
|
||||||
|
|||||||
@@ -729,6 +729,12 @@ std::optional<FilamentBaseInfo> PresetBundle::get_filament_by_filament_id(const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Miss: a retired/renamed id may forward to a live successor through the shipped
|
||||||
|
// succession ledger. resolve() returns a chain-final id, so the retry below cannot
|
||||||
|
// recurse further (a malformed cyclic ledger yields a non-final id, rejected here).
|
||||||
|
const std::string successor = resolve_filament_id_succession(filament_id);
|
||||||
|
if (!successor.empty() && resolve_filament_id_succession(successor).empty())
|
||||||
|
return get_filament_by_filament_id(successor, printer_name);
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3150,6 +3156,15 @@ void PresetBundle::get_ams_cobox_infos(AMSComboInfo& combox_info)
|
|||||||
auto iter = std::find_if(filaments.begin(), filaments.end(),
|
auto iter = std::find_if(filaments.begin(), filaments.end(),
|
||||||
[this, &filament_id](auto &f) { return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == filament_id; });
|
[this, &filament_id](auto &f) { return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == filament_id; });
|
||||||
warn_ambiguous_filament_id_match(filaments, iter, filament_id);
|
warn_ambiguous_filament_id_match(filaments, iter, filament_id);
|
||||||
|
if (iter == filaments.end()) {
|
||||||
|
// Retired/renamed ids forward to a live successor through the shipped succession ledger.
|
||||||
|
const std::string successor = resolve_filament_id_succession(filament_id);
|
||||||
|
if (!successor.empty()) {
|
||||||
|
iter = std::find_if(filaments.begin(), filaments.end(),
|
||||||
|
[this, &successor](auto &f) { return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == successor; });
|
||||||
|
warn_ambiguous_filament_id_match(filaments, iter, successor);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (iter == filaments.end()) {
|
if (iter == filaments.end()) {
|
||||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id;
|
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id;
|
||||||
auto filament_type = ams.opt_string("filament_type", 0u);
|
auto filament_type = ams.opt_string("filament_type", 0u);
|
||||||
@@ -3253,6 +3268,16 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||||||
has_type |= f.config.opt_string("filament_type", 0u) == filament_type;
|
has_type |= f.config.opt_string("filament_type", 0u) == filament_type;
|
||||||
return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == filament_id; });
|
return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == filament_id; });
|
||||||
warn_ambiguous_filament_id_match(filaments, iter, filament_id);
|
warn_ambiguous_filament_id_match(filaments, iter, filament_id);
|
||||||
|
if (iter == filaments.end()) {
|
||||||
|
// Retired/renamed ids forward to a live successor through the shipped succession
|
||||||
|
// ledger (has_type is already complete: the miss above scanned every preset).
|
||||||
|
const std::string successor = resolve_filament_id_succession(filament_id);
|
||||||
|
if (!successor.empty()) {
|
||||||
|
iter = std::find_if(filaments.begin(), filaments.end(), [this, &successor](auto &f) {
|
||||||
|
return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == successor; });
|
||||||
|
warn_ambiguous_filament_id_match(filaments, iter, successor);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (iter == filaments.end()) {
|
if (iter == filaments.end()) {
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id;
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id;
|
||||||
if (!filament_type.empty()) {
|
if (!filament_type.empty()) {
|
||||||
@@ -3714,7 +3739,11 @@ bool PresetBundle::check_filament_temp_equation_by_printer_type_and_nozzle_for_m
|
|||||||
std::map<std::string, std::vector<Preset const *>> filament_list = filaments.get_filament_presets();
|
std::map<std::string, std::vector<Preset const *>> filament_list = filaments.get_filament_presets();
|
||||||
std::set<std::string> printer_names = get_printer_names_by_printer_type_and_nozzle(printer_type, nozzle_diameter_str);
|
std::set<std::string> printer_names = get_printer_names_by_printer_type_and_nozzle(printer_type, nozzle_diameter_str);
|
||||||
|
|
||||||
for (const Preset *preset : filament_list.find(setting_id)->second) {
|
auto filament_iter = filament_list.find(setting_id);
|
||||||
|
if (filament_iter == filament_list.end())
|
||||||
|
return is_equation;
|
||||||
|
|
||||||
|
for (const Preset *preset : filament_iter->second) {
|
||||||
if (tag_uid == "0" || (tag_uid.size() == 16 && tag_uid.substr(12, 2) == "01")) continue;
|
if (tag_uid == "0" || (tag_uid.size() == 16 && tag_uid.substr(12, 2) == "01")) continue;
|
||||||
if (preset && !preset->is_user()) continue;
|
if (preset && !preset->is_user()) continue;
|
||||||
ConfigOption * printer_opt = const_cast<Preset *>(preset)->config.option("compatible_printers");
|
ConfigOption * printer_opt = const_cast<Preset *>(preset)->config.option("compatible_printers");
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ int get_colume_idx(CaliColumnType type, MachineObject* obj)
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
static wxString get_preset_name_by_filament_id(std::string filament_id)
|
static wxString get_preset_name_by_filament_id(std::string filament_id, bool follow_succession = true)
|
||||||
{
|
{
|
||||||
auto preset_bundle = wxGetApp().preset_bundle;
|
auto preset_bundle = wxGetApp().preset_bundle;
|
||||||
auto collection = &preset_bundle->filaments;
|
auto collection = &preset_bundle->filaments;
|
||||||
@@ -93,6 +93,12 @@ static wxString get_preset_name_by_filament_id(std::string filament_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (preset_name.empty() && follow_succession) {
|
||||||
|
// Retired/renamed ids forward to a live successor through the shipped succession ledger.
|
||||||
|
const std::string successor = resolve_filament_id_succession(filament_id);
|
||||||
|
if (!successor.empty())
|
||||||
|
preset_name = get_preset_name_by_filament_id(successor, false);
|
||||||
|
}
|
||||||
return preset_name;
|
return preset_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2540,14 +2540,22 @@ std::string MachineObject::setting_id_to_type(std::string setting_id, std::strin
|
|||||||
std::string type;
|
std::string type;
|
||||||
PresetBundle* preset_bundle = GUI::wxGetApp().preset_bundle;
|
PresetBundle* preset_bundle = GUI::wxGetApp().preset_bundle;
|
||||||
if (preset_bundle) {
|
if (preset_bundle) {
|
||||||
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) {
|
auto lookup_system_type = [preset_bundle](const std::string &id) {
|
||||||
|
std::string display_filament_type;
|
||||||
if (it->filament_id.compare(setting_id) == 0 && it->is_system) {
|
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) {
|
||||||
std::string display_filament_type;
|
if (it->filament_id.compare(id) == 0 && it->is_system) {
|
||||||
it->config.get_filament_type(display_filament_type);
|
it->config.get_filament_type(display_filament_type);
|
||||||
type = display_filament_type;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
|
return display_filament_type;
|
||||||
|
};
|
||||||
|
type = lookup_system_type(setting_id);
|
||||||
|
if (type.empty()) {
|
||||||
|
// Retired/renamed ids forward to a live successor through the shipped succession ledger.
|
||||||
|
const std::string successor = resolve_filament_id_succession(setting_id);
|
||||||
|
if (!successor.empty())
|
||||||
|
type = lookup_system_type(successor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5249,7 +5257,10 @@ void MachineObject::update_filament_list()
|
|||||||
|
|
||||||
for (auto it = filament_list.begin(); it != filament_list.end(); it++) {
|
for (auto it = filament_list.begin(); it != filament_list.end(); it++) {
|
||||||
if (m_filament_list.find(it->first) != m_filament_list.end()) {
|
if (m_filament_list.find(it->first) != m_filament_list.end()) {
|
||||||
assert(it->first.size() == 8 && it->first[0] == 'P');
|
// User roots may legitimately carry adopted system-shaped ids (GF*/OF*/P-hex
|
||||||
|
// system), so a non-'P' id here is expected, not an invariant violation.
|
||||||
|
if (it->first.size() != 8 || it->first[0] != 'P')
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": user-root filament_id is not user-shaped: " << it->first;
|
||||||
|
|
||||||
if (it->second.first != m_filament_list[it->first].first) {
|
if (it->second.first != m_filament_list[it->first].first) {
|
||||||
BOOST_LOG_TRIVIAL(info) << "old min temp is not equal to new min temp and filament id: " << it->first;
|
BOOST_LOG_TRIVIAL(info) << "old min temp is not equal to new min temp and filament id: " << it->first;
|
||||||
@@ -5311,6 +5322,17 @@ void MachineObject::update_printer_preset_name()
|
|||||||
void MachineObject::check_ams_filament_valid()
|
void MachineObject::check_ams_filament_valid()
|
||||||
{
|
{
|
||||||
PresetBundle * preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle;
|
PresetBundle * preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle;
|
||||||
|
// A tray id carried by ANY system filament preset is not a dangling user-preset id
|
||||||
|
// (ten shipped P-hex system ids pass the 'P' shape gates below), so the destructive
|
||||||
|
// tray-wipe / temp-rewrite handling must never fire for it.
|
||||||
|
auto is_system_filament_id = [preset_bundle](const std::string &id) {
|
||||||
|
if (!preset_bundle)
|
||||||
|
return false;
|
||||||
|
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++)
|
||||||
|
if (it->is_system && it->filament_id == id)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
auto printer_model = DevPrinterConfigUtil::get_printer_display_name(this->printer_type);
|
auto printer_model = DevPrinterConfigUtil::get_printer_display_name(this->printer_type);
|
||||||
std::map<std::string, std::set<std::string>> need_checked_filament_id;
|
std::map<std::string, std::set<std::string>> need_checked_filament_id;
|
||||||
for (auto &ams_pair : m_fila_system->GetAmsList()) {
|
for (auto &ams_pair : m_fila_system->GetAmsList()) {
|
||||||
@@ -5332,6 +5354,8 @@ void MachineObject::check_ams_filament_valid()
|
|||||||
auto &checked_filament = data.checked_filament;
|
auto &checked_filament = data.checked_filament;
|
||||||
for (const auto &[slot_id, curr_tray] : ams->GetTrays()) {
|
for (const auto &[slot_id, curr_tray] : ams->GetTrays()) {
|
||||||
|
|
||||||
|
if (curr_tray->setting_id.size() == 8 && curr_tray->setting_id[0] == 'P' && is_system_filament_id(curr_tray->setting_id))
|
||||||
|
continue;
|
||||||
if (curr_tray->setting_id.size() == 8 && curr_tray->setting_id[0] == 'P' && filament_list.find(curr_tray->setting_id) == filament_list.end()) {
|
if (curr_tray->setting_id.size() == 8 && curr_tray->setting_id[0] == 'P' && filament_list.find(curr_tray->setting_id) == filament_list.end()) {
|
||||||
if (checked_filament.find(curr_tray->setting_id) != checked_filament.end()) {
|
if (checked_filament.find(curr_tray->setting_id) != checked_filament.end()) {
|
||||||
need_checked_filament_id[nozzle_diameter_str].insert(curr_tray->setting_id);
|
need_checked_filament_id[nozzle_diameter_str].insert(curr_tray->setting_id);
|
||||||
@@ -5392,6 +5416,8 @@ void MachineObject::check_ams_filament_valid()
|
|||||||
auto &data = m_nozzle_filament_data[nozzle_diameter_str];
|
auto &data = m_nozzle_filament_data[nozzle_diameter_str];
|
||||||
auto &checked_filament = data.checked_filament;
|
auto &checked_filament = data.checked_filament;
|
||||||
auto &filament_list = data.filament_list;
|
auto &filament_list = data.filament_list;
|
||||||
|
if (vt_tray.setting_id.size() == 8 && vt_tray.setting_id[0] == 'P' && is_system_filament_id(vt_tray.setting_id))
|
||||||
|
continue;
|
||||||
if (vt_tray.setting_id.size() == 8 && vt_tray.setting_id[0] == 'P' && filament_list.find(vt_tray.setting_id) == filament_list.end()) {
|
if (vt_tray.setting_id.size() == 8 && vt_tray.setting_id[0] == 'P' && filament_list.find(vt_tray.setting_id) == filament_list.end()) {
|
||||||
if (checked_filament.find(vt_tray.setting_id) != checked_filament.end()) {
|
if (checked_filament.find(vt_tray.setting_id) != checked_filament.end()) {
|
||||||
need_checked_filament_id[nozzle_diameter_str].insert(vt_tray.setting_id);
|
need_checked_filament_id[nozzle_diameter_str].insert(vt_tray.setting_id);
|
||||||
|
|||||||
@@ -537,6 +537,13 @@ bool PresetComboBox::add_ams_filaments(std::string selected, bool alias_name)
|
|||||||
}
|
}
|
||||||
auto iter = std::find_if(filaments.begin(), filaments.end(),
|
auto iter = std::find_if(filaments.begin(), filaments.end(),
|
||||||
[&filament_id, this](auto &f) { return f.is_compatible && m_collection->get_preset_base(f) == &f && f.filament_id == filament_id; });
|
[&filament_id, this](auto &f) { return f.is_compatible && m_collection->get_preset_base(f) == &f && f.filament_id == filament_id; });
|
||||||
|
if (iter == filaments.end()) {
|
||||||
|
// Retired/renamed ids forward to a live successor through the shipped succession ledger.
|
||||||
|
const std::string successor = resolve_filament_id_succession(filament_id);
|
||||||
|
if (!successor.empty())
|
||||||
|
iter = std::find_if(filaments.begin(), filaments.end(),
|
||||||
|
[&successor, this](auto &f) { return f.is_compatible && m_collection->get_preset_base(f) == &f && f.filament_id == successor; });
|
||||||
|
}
|
||||||
if (iter == filaments.end()) {
|
if (iter == filaments.end()) {
|
||||||
auto filament_type = tray.opt_string("filament_type", 0u);
|
auto filament_type = tray.opt_string("filament_type", 0u);
|
||||||
if (!filament_type.empty()) {
|
if (!filament_type.empty()) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
#include <map>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -609,51 +610,70 @@ std::string MoonrakerPrinterAgent::map_filament_type_to_generic_id(const std::st
|
|||||||
{
|
{
|
||||||
const std::string upper = trim_and_upper(filament_type);
|
const std::string upper = trim_and_upper(filament_type);
|
||||||
|
|
||||||
// Map to OrcaFilamentLibrary preset IDs (compatible with all printers)
|
// Normalize reported material names (trimmed, uppercased) to an OrcaFilamentLibrary
|
||||||
// Source: resources/profiles/OrcaFilamentLibrary/filament/
|
// generic family. The family's filament_id is resolved from the loaded system presets
|
||||||
|
// below rather than hardcoded, so profile id re-mints never require touching this table.
|
||||||
|
// scripts/test_moonraker_lane_data.py parses this initializer; keep the {"A", "B"} format.
|
||||||
|
static const std::map<std::string, std::string> type_to_ofl_family = {
|
||||||
|
// PLA variants
|
||||||
|
{"PLA", "PLA"},
|
||||||
|
{"PLA-CF", "PLA-CF"},
|
||||||
|
{"PLA SILK", "PLA Silk"},
|
||||||
|
{"PLA-SILK", "PLA Silk"},
|
||||||
|
{"PLA HIGH SPEED", "PLA High Speed"},
|
||||||
|
{"PLA-HS", "PLA High Speed"},
|
||||||
|
{"PLA HS", "PLA High Speed"},
|
||||||
|
|
||||||
// PLA variants
|
// ABS/ASA variants
|
||||||
if (upper == "PLA") return "OGFL99";
|
{"ABS", "ABS"},
|
||||||
if (upper == "PLA-CF") return "OGFL98";
|
{"ASA", "ASA"},
|
||||||
if (upper == "PLA SILK" || upper == "PLA-SILK") return "OGFL96";
|
|
||||||
if (upper == "PLA HIGH SPEED" || upper == "PLA-HS" || upper == "PLA HS") return "OGFL95";
|
|
||||||
|
|
||||||
// ABS/ASA variants
|
// PETG/PET variants
|
||||||
if (upper == "ABS") return "OGFB99";
|
{"PETG", "PETG"},
|
||||||
if (upper == "ASA") return "OGFB98";
|
{"PET", "PETG"},
|
||||||
|
{"PCTG", "PCTG"},
|
||||||
|
|
||||||
// PETG/PET variants
|
// PA/Nylon variants
|
||||||
if (upper == "PETG" || upper == "PET") return "OGFG99";
|
{"PA", "PA"},
|
||||||
if (upper == "PCTG") return "OGFG97";
|
{"NYLON", "PA"},
|
||||||
|
{"PA-CF", "PA-CF"},
|
||||||
|
{"PPA", "PPA-CF"},
|
||||||
|
{"PPA-CF", "PPA-CF"},
|
||||||
|
{"PPA-GF", "PPA-GF"},
|
||||||
|
|
||||||
// PA/Nylon variants
|
// PC variants
|
||||||
if (upper == "PA" || upper == "NYLON") return "OGFN99";
|
{"PC", "PC"},
|
||||||
if (upper == "PA-CF") return "OGFN98";
|
|
||||||
if (upper == "PPA" || upper == "PPA-CF") return "OGFN97";
|
|
||||||
if (upper == "PPA-GF") return "OGFN96";
|
|
||||||
|
|
||||||
// PC variants
|
// PP/PE variants
|
||||||
if (upper == "PC") return "OGFC99";
|
{"PE", "PE"},
|
||||||
|
{"PP", "PP"},
|
||||||
|
|
||||||
// PP/PE variants
|
// Support materials
|
||||||
if (upper == "PE") return "OGFP99";
|
{"PVA", "PVA"},
|
||||||
if (upper == "PP") return "OGFP97";
|
{"HIPS", "HIPS"},
|
||||||
|
{"BVOH", "BVOH"},
|
||||||
|
|
||||||
// Support materials
|
// TPU variants
|
||||||
if (upper == "PVA") return "OGFS99";
|
{"TPU", "TPU"},
|
||||||
if (upper == "HIPS") return "OGFS98";
|
|
||||||
if (upper == "BVOH") return "OGFS97";
|
|
||||||
|
|
||||||
// TPU variants
|
// Other materials
|
||||||
if (upper == "TPU") return "OGFU99";
|
{"EVA", "EVA"},
|
||||||
|
{"PHA", "PHA"},
|
||||||
|
{"COPE", "CoPE"},
|
||||||
|
{"SBS", "SBS"},
|
||||||
|
};
|
||||||
|
|
||||||
// Other materials
|
auto it = type_to_ofl_family.find(upper);
|
||||||
if (upper == "EVA") return "OGFR99";
|
if (it == type_to_ofl_family.end())
|
||||||
if (upper == "PHA") return "OGFR98";
|
return UNKNOWN_FILAMENT_ID;
|
||||||
if (upper == "COPE") return "OGFLC99";
|
|
||||||
if (upper == "SBS") return "OFLSBS99";
|
|
||||||
|
|
||||||
// Unknown material
|
if (auto* bundle = GUI::wxGetApp().preset_bundle) {
|
||||||
|
const Preset* preset = bundle->filaments.find_preset("Generic " + it->second + " @System");
|
||||||
|
if (preset != nullptr && preset->is_system && !preset->filament_id.empty())
|
||||||
|
return preset->filament_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown material, or no loaded preset data to resolve against
|
||||||
return UNKNOWN_FILAMENT_ID;
|
return UNKNOWN_FILAMENT_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ add_executable(${_TEST_NAME}_tests
|
|||||||
test_config.cpp
|
test_config.cpp
|
||||||
test_preset_bundle_loading.cpp
|
test_preset_bundle_loading.cpp
|
||||||
test_preset_setting_id.cpp
|
test_preset_setting_id.cpp
|
||||||
|
test_filament_id_succession.cpp
|
||||||
test_elephant_foot_compensation.cpp
|
test_elephant_foot_compensation.cpp
|
||||||
test_geometry.cpp
|
test_geometry.cpp
|
||||||
test_placeholder_parser.cpp
|
test_placeholder_parser.cpp
|
||||||
|
|||||||
61
tests/libslic3r/test_filament_id_succession.cpp
Normal file
61
tests/libslic3r/test_filament_id_succession.cpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#include <catch2/catch_all.hpp>
|
||||||
|
|
||||||
|
#include "libslic3r/Preset.hpp"
|
||||||
|
|
||||||
|
using namespace Slic3r;
|
||||||
|
|
||||||
|
// Pure-function coverage of the succession chain walk (follow_filament_id_succession).
|
||||||
|
// The ledger-file loader (filament_id_succession_map) is deliberately untested here so
|
||||||
|
// the test carries no resources-dir dependency.
|
||||||
|
TEST_CASE("filament_id succession follows forwarding chains", "[Preset][filament_id]") {
|
||||||
|
SECTION("empty map returns empty") {
|
||||||
|
const std::map<std::string, std::string> empty;
|
||||||
|
CHECK(follow_filament_id_succession("OFabc123", empty).empty());
|
||||||
|
CHECK(follow_filament_id_succession("", empty).empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::map<std::string, std::string> forwards = {
|
||||||
|
{"OFold001", "OFnew001"},
|
||||||
|
{"OFchainA", "OFchainB"},
|
||||||
|
{"OFchainB", "OFchainC"},
|
||||||
|
{"OFchainC", "OFlive00"},
|
||||||
|
};
|
||||||
|
|
||||||
|
SECTION("absent id returns empty") {
|
||||||
|
CHECK(follow_filament_id_succession("GFL99", forwards).empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("single hop resolves to the successor") {
|
||||||
|
CHECK(follow_filament_id_succession("OFold001", forwards) == "OFnew001");
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("multi-hop chain resolves to the live end") {
|
||||||
|
CHECK(follow_filament_id_succession("OFchainA", forwards) == "OFlive00");
|
||||||
|
CHECK(follow_filament_id_succession("OFchainB", forwards) == "OFlive00");
|
||||||
|
CHECK(follow_filament_id_succession("OFchainC", forwards) == "OFlive00");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cycles are a ledger-validation error (script check 9) and never ship, but the client
|
||||||
|
// walk must still terminate on corrupt data: it stops at the last id reached before any
|
||||||
|
// id would repeat.
|
||||||
|
TEST_CASE("filament_id succession terminates on malformed cycles", "[Preset][filament_id]") {
|
||||||
|
SECTION("two-node cycle returns the last id before revisiting") {
|
||||||
|
const std::map<std::string, std::string> cycle = {{"A", "B"}, {"B", "A"}};
|
||||||
|
CHECK(follow_filament_id_succession("A", cycle) == "B");
|
||||||
|
CHECK(follow_filament_id_succession("B", cycle) == "A");
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("cycle entered through a tail stops before re-entering it") {
|
||||||
|
// T -> A -> B -> C -> A: stops at C, the last id reached before repeating A.
|
||||||
|
const std::map<std::string, std::string> cycle = {
|
||||||
|
{"T", "A"}, {"A", "B"}, {"B", "C"}, {"C", "A"}};
|
||||||
|
CHECK(follow_filament_id_succession("T", cycle) == "C");
|
||||||
|
CHECK(follow_filament_id_succession("A", cycle) == "C");
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("self-loop returns the id itself") {
|
||||||
|
const std::map<std::string, std::string> loop = {{"A", "A"}};
|
||||||
|
CHECK(follow_filament_id_succession("A", loop) == "A");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user