bambu-printer-mcp 1.1.27 → 1.1.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTORS.md +7 -1
- package/README.md +29 -10
- package/dist/ams-mapping.d.ts +18 -2
- package/dist/ams-mapping.js +36 -5
- package/dist/bambu-native.d.ts +55 -0
- package/dist/bambu-native.js +212 -13
- package/dist/index.js +154 -71
- package/dist/printers/bambu.d.ts +29 -2
- package/dist/printers/bambu.js +59 -28
- package/dist/safety/hidden-hms.d.ts +32 -0
- package/dist/safety/hidden-hms.js +405 -0
- package/dist/safety/limits.d.ts +6 -0
- package/dist/safety/limits.js +9 -0
- package/dist/safety/print-file.d.ts +2 -0
- package/dist/safety/print-file.js +83 -7
- package/dist/safety/printer-state.d.ts +11 -0
- package/dist/safety/printer-state.js +115 -22
- package/dist/slicer/profile-flatten.js +25 -0
- package/dist/slicer/remote-slicer.d.ts +12 -0
- package/dist/slicer/remote-slicer.js +240 -0
- package/dist/stl/stl-manipulator.d.ts +2 -1
- package/dist/stl/stl-manipulator.js +71 -42
- package/native/bambu-native-print.cpp +100 -26
- package/package.json +7 -5
- package/scripts/build-bambu-native.sh +53 -0
- package/scripts/setup-bambu-native.mjs +372 -0
- package/src/ams-mapping.ts +38 -5
- package/src/bambu-native.ts +229 -14
- package/src/index.ts +156 -67
- package/src/printers/bambu.ts +65 -25
- package/src/safety/hidden-hms.ts +406 -0
- package/src/safety/limits.ts +9 -0
- package/src/safety/print-file.ts +71 -7
- package/src/safety/printer-state.ts +117 -22
- package/src/slicer/profile-flatten.ts +32 -0
- package/src/slicer/remote-slicer.ts +216 -0
- package/src/stl/stl-manipulator.ts +70 -43
- package/scripts/build-bambu-native.zsh +0 -33
package/dist/printers/bambu.js
CHANGED
|
@@ -7,8 +7,9 @@ import os from "node:os";
|
|
|
7
7
|
import { Readable } from "node:stream";
|
|
8
8
|
import { readSafe3mfArchive } from "../safety/archive.js";
|
|
9
9
|
import { inspectPrintFile } from "../safety/print-file.js";
|
|
10
|
-
import { normalizeModel, validateTemperature } from "../safety/limits.js";
|
|
11
|
-
import {
|
|
10
|
+
import { isDualNozzleModel, normalizeModel, validateTemperature } from "../safety/limits.js";
|
|
11
|
+
import { bridgeAmsMapping2Entry, bridgeAmsMappingValue, externalTrayForNozzle, describeAmsTrayRange } from "../ams-mapping.js";
|
|
12
|
+
import { describeHmsKey, hiddenHmsKeys, hiddenHmsNotices, reportedHmsKey, validatePrinterState, manualHeatingRequirements } from "../safety/printer-state.js";
|
|
12
13
|
import { withPrinterOperation, withPrintSnapshot, uniquePrintName, normalizedRemotePath, cancelPendingPrinterOperations } from "../safety/artifact.js";
|
|
13
14
|
import { Client as FTPClient } from "basic-ftp";
|
|
14
15
|
import { BambuPrinter } from "bambu-js";
|
|
@@ -69,7 +70,7 @@ const MODEL_ID_TO_NAME = {
|
|
|
69
70
|
const H2_MODEL_NAMES = new Set(["h2", "h2c", "h2d", "h2dpro", "h2d pro", "h2s", "x2d"]);
|
|
70
71
|
export function assertDirectPrintSupported(model, serial) {
|
|
71
72
|
if (model?.trim().toLowerCase() === "x2d" || serial?.trim().toUpperCase().startsWith("20P")) {
|
|
72
|
-
throw new Error("X2D direct printing is not supported through legacy MQTT/FTPS. Use the
|
|
73
|
+
throw new Error("X2D direct printing is not supported through legacy MQTT/FTPS. Use the native eMMC route via print_3mf (macOS, or Linux with the native helper installed). " +
|
|
73
74
|
"X2D status and slicing remain available on all supported platforms.");
|
|
74
75
|
}
|
|
75
76
|
}
|
|
@@ -392,21 +393,37 @@ export class BambuImplementation {
|
|
|
392
393
|
finishedJobIdentity(status) {
|
|
393
394
|
return status.raw.gcode_state === "FINISH" ? JSON.stringify([status.raw.gcode_file, status.raw.subtask_name, status.raw.task_id, status.raw.subtask_id]) : undefined;
|
|
394
395
|
}
|
|
396
|
+
/**
|
|
397
|
+
* The human print confirmation. Its result goes to assertBedClearance at
|
|
398
|
+
* every later state check of the same print, which stops the print if the
|
|
399
|
+
* situation the human confirmed has changed.
|
|
400
|
+
*/
|
|
395
401
|
async confirmPrintPreflight(serial, status, inspection) {
|
|
396
402
|
const finishedJob = this.finishedJobIdentity(status);
|
|
397
403
|
const cleared = this.clearedErrors.get(serial);
|
|
404
|
+
const notices = hiddenHmsNotices(status?.raw, serial, inspection.model);
|
|
398
405
|
await this.confirmHardwareAction(`Start a checked print on ${inspection.model.toUpperCase()} (${serial})? Nozzles: ${inspection.nozzleDiameters.join(", ")} mm. ` +
|
|
399
406
|
`Materials: ${inspection.materials.join(", ")}. Peak targets: nozzle ${inspection.maxNozzleTemperature}°C, bed ${inspection.maxBedTemperature}°C, chamber ${inspection.maxChamberTemperature}°C. ` +
|
|
400
407
|
`File SHA-256: ${inspection.sha256}. Confirm the physical spool labels and that the build plate is clear.` +
|
|
401
408
|
(finishedJob !== undefined ? " The printer reports FINISH: remove the previous part and debris before confirming." : "") +
|
|
402
|
-
(cleared ? ` Previously cleared hardware codes: ${cleared.join(", ")}. Confirm their physical causes have been resolved.` : "")
|
|
403
|
-
|
|
409
|
+
(cleared ? ` Previously cleared hardware codes: ${cleared.map(describeHmsKey).join(", ")}. Confirm their physical causes have been resolved.` : "") +
|
|
410
|
+
(notices.length ? ` The printer also reports ${notices.join(", ")}, which Bambu lists for this model without text and never shows as a fault; ` +
|
|
411
|
+
`${notices.length === 1 ? "it does" : "they do"} not block printing.` : ""), finishedJob !== undefined || !!cleared);
|
|
412
|
+
return { finishedJob, serial, model: inspection.model, notices };
|
|
404
413
|
}
|
|
405
|
-
|
|
414
|
+
/** Stop a print whose confirmed situation changed: a newly finished job, or a hidden HMS notice the preflight did not name. */
|
|
415
|
+
assertBedClearance(status, preflight) {
|
|
406
416
|
const current = this.finishedJobIdentity(status);
|
|
407
|
-
if (current !== undefined && current !==
|
|
417
|
+
if (current !== undefined && current !== preflight.finishedJob) {
|
|
408
418
|
throw new Error("Printer reports a newly finished job. Confirm that its part and debris have been removed before retrying the print.");
|
|
409
419
|
}
|
|
420
|
+
// An X2D raises its hidden camera notice about 15 seconds after boot, so it
|
|
421
|
+
// can appear after the human confirmed. Never pass a notice nobody was told about.
|
|
422
|
+
const unnamed = hiddenHmsNotices(status?.raw, preflight.serial, preflight.model).filter(notice => !preflight.notices.includes(notice));
|
|
423
|
+
if (unnamed.length) {
|
|
424
|
+
throw new Error(`Printer reported ${unnamed.join(", ")} after the print confirmation. ` +
|
|
425
|
+
"Bambu hides it and it does not block printing, but it was not named when you confirmed; start the print again to review it.");
|
|
426
|
+
}
|
|
410
427
|
}
|
|
411
428
|
async getPrinter(host, serial, token) {
|
|
412
429
|
return this.printerStore.getPrinter(host, serial, token);
|
|
@@ -604,12 +621,17 @@ export class BambuImplementation {
|
|
|
604
621
|
// `plate_N.json.filament_ids` -- and expand to a full project-level
|
|
605
622
|
// array here. `amsMapping` is the raw escape hatch (takes precedence
|
|
606
623
|
// when both are supplied).
|
|
624
|
+
// Dual-nozzle printers address two external spools: 254 feeds the left/deputy
|
|
625
|
+
// nozzle and 255 the right/main nozzle (Bambu Studio VIRTUAL_TRAY_DEPUTY_ID /
|
|
626
|
+
// VIRTUAL_TRAY_MAIN_ID). Single-nozzle printers keep 254 as the only external tray.
|
|
627
|
+
const dualNozzle = isDualNozzleModel(model);
|
|
628
|
+
const externalTrays = dualNozzle ? [254, 255] : [254];
|
|
607
629
|
const validateTrayValue = (v, label) => {
|
|
608
630
|
if (!Number.isInteger(v) ||
|
|
609
631
|
v < -1 ||
|
|
610
632
|
(v > 15 && v < 128) ||
|
|
611
|
-
v > 254) {
|
|
612
|
-
throw new Error(`${label} values must be integers in
|
|
633
|
+
v > (dualNozzle ? 255 : 254)) {
|
|
634
|
+
throw new Error(`${label} values must be integers in ${describeAmsTrayRange({ dualNozzle })}; got ${v}`);
|
|
613
635
|
}
|
|
614
636
|
};
|
|
615
637
|
let baseMapping;
|
|
@@ -639,7 +661,7 @@ export class BambuImplementation {
|
|
|
639
661
|
const projectLen = Math.max(projectMetadata.projectFilamentCount, ...positions.map((p) => p + 1), 1);
|
|
640
662
|
baseMapping = Array(projectLen).fill(-1);
|
|
641
663
|
positions.forEach((pos, i) => {
|
|
642
|
-
baseMapping[pos] = options.useAMS === false ?
|
|
664
|
+
baseMapping[pos] = options.useAMS === false ? externalTrayForNozzle(inspection.filamentNozzleIndices?.[pos], dualNozzle) : i;
|
|
643
665
|
});
|
|
644
666
|
}
|
|
645
667
|
let amsMapping;
|
|
@@ -647,15 +669,7 @@ export class BambuImplementation {
|
|
|
647
669
|
if (usesH2ProjectFile) {
|
|
648
670
|
const projLen = Math.max(projectMetadata.projectFilamentCount, baseMapping.length, 1);
|
|
649
671
|
amsMapping = Array.from({ length: projLen }, (_, i) => i < baseMapping.length ? baseMapping[i] : -1);
|
|
650
|
-
amsMapping2 = amsMapping.map((v) =>
|
|
651
|
-
if (v < 0 || v === 255)
|
|
652
|
-
return { ams_id: 255, slot_id: 255 };
|
|
653
|
-
if (v === 254)
|
|
654
|
-
return { ams_id: 254, slot_id: 254 };
|
|
655
|
-
if (v >= 128)
|
|
656
|
-
return { ams_id: 128, slot_id: v - 128 };
|
|
657
|
-
return { ams_id: Math.floor(v / 4), slot_id: v % 4 };
|
|
658
|
-
});
|
|
672
|
+
amsMapping2 = amsMapping.map((v) => bridgeAmsMapping2Entry(v, dualNozzle));
|
|
659
673
|
}
|
|
660
674
|
else {
|
|
661
675
|
amsMapping = Array.from({ length: Math.max(5, baseMapping.length, projectMetadata.projectFilamentCount) }, (_, i) => i < baseMapping.length ? baseMapping[i] : -1);
|
|
@@ -665,8 +679,8 @@ export class BambuImplementation {
|
|
|
665
679
|
if (baseMapping[position] === undefined || baseMapping[position] < 0) {
|
|
666
680
|
throw new Error(`Missing physical filament mapping for project filament ${position}.`);
|
|
667
681
|
}
|
|
668
|
-
if (options.useAMS === false && baseMapping[position]
|
|
669
|
-
throw new Error(
|
|
682
|
+
if (options.useAMS === false && !externalTrays.includes(baseMapping[position])) {
|
|
683
|
+
throw new Error(`External-spool printing requires external spool mapping (${externalTrays.join(" or ")}).`);
|
|
670
684
|
}
|
|
671
685
|
}
|
|
672
686
|
const legacyContainer = options.filePath.toLowerCase().endsWith(".gcode.3mf") && !usesH2ProjectFile && !isA1;
|
|
@@ -752,7 +766,7 @@ export class BambuImplementation {
|
|
|
752
766
|
project_id: submissionId,
|
|
753
767
|
subtask_id: submissionId,
|
|
754
768
|
task_id: submissionId,
|
|
755
|
-
ams_mapping: amsMapping,
|
|
769
|
+
ams_mapping: amsMapping.map(value => bridgeAmsMappingValue(value, dualNozzle)),
|
|
756
770
|
ams_mapping2: amsMapping2,
|
|
757
771
|
},
|
|
758
772
|
};
|
|
@@ -822,6 +836,19 @@ export class BambuImplementation {
|
|
|
822
836
|
throw new Error(`Failed to cancel print: ${error.message}`);
|
|
823
837
|
}
|
|
824
838
|
}
|
|
839
|
+
/** Raw MQTT stop for routes that already ran the shared cancellation steps. */
|
|
840
|
+
async sendStopOverMqtt(host, serial, token) {
|
|
841
|
+
const printer = await this.getPrinter(host, serial, token);
|
|
842
|
+
await invokeWithoutAck(printer, new UpdateStateCommand({ state: "stop" }));
|
|
843
|
+
return { status: "success", message: "Cancel command sent over MQTT." };
|
|
844
|
+
}
|
|
845
|
+
/** Raw MQTT heater-off; switching off needs no material or model declaration. */
|
|
846
|
+
async sendHeaterOffOverMqtt(host, serial, token, heater) {
|
|
847
|
+
const printer = await this.getPrinter(host, serial, token);
|
|
848
|
+
const gcode = `${heater === "bed" ? "M140" : "M104"} S0`;
|
|
849
|
+
await invokeWithoutAck(printer, new GCodeLineCommand({ gcodes: [gcode] }));
|
|
850
|
+
return { status: "success", message: `Heater-off sent over MQTT for ${heater}.`, command: gcode };
|
|
851
|
+
}
|
|
825
852
|
async pauseJob(host, serial, token, dispatch) {
|
|
826
853
|
const printer = dispatch ? undefined : await this.getPrinter(host, serial, token);
|
|
827
854
|
try {
|
|
@@ -867,10 +894,12 @@ export class BambuImplementation {
|
|
|
867
894
|
const codesFor = (status) => {
|
|
868
895
|
if (!Array.isArray(status.raw?.hms) || status.raw?.print_error === undefined)
|
|
869
896
|
throw new Error("Fresh error codes are required before clearing hardware errors.");
|
|
870
|
-
|
|
897
|
+
// Hidden notices never block and survive clean_print_error, so they are not errors to clear or re-acknowledge.
|
|
898
|
+
const hidden = new Set(hiddenHmsKeys(status.raw, serial, String(status.model ?? "")));
|
|
899
|
+
return [`print_error:${status.raw.print_error}`, ...status.raw.hms.map(reportedHmsKey).filter((key) => !hidden.has(key))].sort();
|
|
871
900
|
};
|
|
872
901
|
const codes = codesFor(await this.getSafetyStatus(host, serial, token));
|
|
873
|
-
await this.confirmHardwareAction(`Clear reported hardware errors on ${serial}: ${codes.join(", ")}? Inspect the printer and resolve the physical cause first. Confirm only after removing obstructions and correcting the fault.`, true);
|
|
902
|
+
await this.confirmHardwareAction(`Clear reported hardware errors on ${serial}: ${codes.map(describeHmsKey).join(", ")}? Inspect the printer and resolve the physical cause first. Confirm only after removing obstructions and correcting the fault.`, true);
|
|
874
903
|
const beforeDispatch = async () => {
|
|
875
904
|
assertActive();
|
|
876
905
|
const current = codesFor(await this.getSafetyStatus(host, serial, token));
|
|
@@ -1001,11 +1030,13 @@ export class BambuImplementation {
|
|
|
1001
1030
|
}
|
|
1002
1031
|
const printer = dispatch ? undefined : await this.getPrinter(host, serial, token);
|
|
1003
1032
|
assertActive();
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
else
|
|
1033
|
+
const dispatched = dispatch ? await dispatch(heater, targetTemperature, assertActive, beforeDispatch) : undefined;
|
|
1034
|
+
if (!dispatch)
|
|
1007
1035
|
await invokeWithoutAck(printer, new GCodeLineCommand({ gcodes: [gcode] }));
|
|
1008
|
-
|
|
1036
|
+
// Keep route details from a dual-route Linux heater-off.
|
|
1037
|
+
const routeDetails = dispatched && typeof dispatched === "object" && "routes" in dispatched
|
|
1038
|
+
? { routes: dispatched.routes, native_error: dispatched.native_error, mqtt_error: dispatched.mqtt_error } : {};
|
|
1039
|
+
return { status: "success", message: `Temperature command sent for ${normalizedComponent}.`, command: gcode, ...routeDetails };
|
|
1009
1040
|
};
|
|
1010
1041
|
if (targetTemperature === 0) {
|
|
1011
1042
|
cancelPendingPrinterOperations(host, serial);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare const HIDDEN_HMS_SOURCE: {
|
|
2
|
+
readonly studioTag: "v02.08.02.61";
|
|
3
|
+
readonly studioCommit: "926a7192574bcb9b3a732e1ec59a46d79cb45466";
|
|
4
|
+
/** Per table: Bambu's device_hms version and the SHA-256 of the English file used. */
|
|
5
|
+
readonly tables: {
|
|
6
|
+
readonly "093": {
|
|
7
|
+
readonly version: 202508191204;
|
|
8
|
+
readonly sha256: "7801fd6c355854b62ecb62ee32727b4e5dcca908841dbcfd5e5de45b3dfd1c25";
|
|
9
|
+
};
|
|
10
|
+
readonly "094": {
|
|
11
|
+
readonly version: 202503231214;
|
|
12
|
+
readonly sha256: "047c15e2140738ec08258b74536e6cb996cddf0c586c5c39e2318e54125a9e76";
|
|
13
|
+
};
|
|
14
|
+
readonly "20P": {
|
|
15
|
+
readonly version: 202511162200;
|
|
16
|
+
readonly sha256: "e4f067d027b9bcbb9bbf6cb90f41f11130cf4d83dffd3dee101db7826dc808c3";
|
|
17
|
+
};
|
|
18
|
+
readonly "22E": {
|
|
19
|
+
readonly version: 202510142200;
|
|
20
|
+
readonly sha256: "87426021aea2bd4e8d721e46e1c86808fd7c6fc06f52baf6d952ead9e8d14d1e";
|
|
21
|
+
};
|
|
22
|
+
readonly "239": {
|
|
23
|
+
readonly version: 202506171403;
|
|
24
|
+
readonly sha256: "c1d23d5302756d57df5cb9bc795d95fc54ef1db7565dca1f04b69a024886426a";
|
|
25
|
+
};
|
|
26
|
+
readonly "31B": {
|
|
27
|
+
readonly version: 202511162200;
|
|
28
|
+
readonly sha256: "dcf63657bff5451f0715ea3c032efe482279bc8cbc28cb9b8ae51c7354826574";
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
export declare const HIDDEN_HMS: Readonly<Record<string, readonly string[]>>;
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
// GENERATED by scripts/generate-hidden-hms.mjs from Bambu Studio v02.08.02.61
|
|
2
|
+
// (commit 926a7192574bcb9b3a732e1ec59a46d79cb45466, resources/hms/hms_en_<serial prefix>.json).
|
|
3
|
+
// Codes Bambu lists for a serial prefix with empty text in every entry. Do not edit by hand.
|
|
4
|
+
export const HIDDEN_HMS_SOURCE = {
|
|
5
|
+
studioTag: "v02.08.02.61",
|
|
6
|
+
studioCommit: "926a7192574bcb9b3a732e1ec59a46d79cb45466",
|
|
7
|
+
/** Per table: Bambu's device_hms version and the SHA-256 of the English file used. */
|
|
8
|
+
tables: {
|
|
9
|
+
"093": { version: 202508191204, sha256: "7801fd6c355854b62ecb62ee32727b4e5dcca908841dbcfd5e5de45b3dfd1c25" },
|
|
10
|
+
"094": { version: 202503231214, sha256: "047c15e2140738ec08258b74536e6cb996cddf0c586c5c39e2318e54125a9e76" },
|
|
11
|
+
"20P": { version: 202511162200, sha256: "e4f067d027b9bcbb9bbf6cb90f41f11130cf4d83dffd3dee101db7826dc808c3" },
|
|
12
|
+
"22E": { version: 202510142200, sha256: "87426021aea2bd4e8d721e46e1c86808fd7c6fc06f52baf6d952ead9e8d14d1e" },
|
|
13
|
+
"239": { version: 202506171403, sha256: "c1d23d5302756d57df5cb9bc795d95fc54ef1db7565dca1f04b69a024886426a" },
|
|
14
|
+
"31B": { version: 202511162200, sha256: "dcf63657bff5451f0715ea3c032efe482279bc8cbc28cb9b8ae51c7354826574" },
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
export const HIDDEN_HMS = {
|
|
18
|
+
"093": [
|
|
19
|
+
"0300180000000000",
|
|
20
|
+
"050001000001000A",
|
|
21
|
+
"0500010000020003",
|
|
22
|
+
"0500010000020008",
|
|
23
|
+
"0500010000020009",
|
|
24
|
+
"0500010000030009",
|
|
25
|
+
"0500030000010053",
|
|
26
|
+
"0500030000020010",
|
|
27
|
+
"0500030000020011",
|
|
28
|
+
"0500030000020012",
|
|
29
|
+
"0500030000020013",
|
|
30
|
+
"0500030000020014",
|
|
31
|
+
"0500030000020015",
|
|
32
|
+
"0500030000020016",
|
|
33
|
+
"0500030000020017",
|
|
34
|
+
"0500030000020018",
|
|
35
|
+
"0500030000030007",
|
|
36
|
+
"0500040000020020",
|
|
37
|
+
"0500050000010008",
|
|
38
|
+
"0500050000010009",
|
|
39
|
+
"050005000001000A",
|
|
40
|
+
"050005000001000B",
|
|
41
|
+
"050005000001000C",
|
|
42
|
+
"0500050000020030",
|
|
43
|
+
"0500060000020005",
|
|
44
|
+
"0500060000020007",
|
|
45
|
+
"0500060000020008",
|
|
46
|
+
"0500060000020011",
|
|
47
|
+
"0500060000020012",
|
|
48
|
+
"0500060000020013",
|
|
49
|
+
"0500060000020014",
|
|
50
|
+
"0500060000020021",
|
|
51
|
+
"0500060000020022",
|
|
52
|
+
"0500060000020023",
|
|
53
|
+
"0500060000020024",
|
|
54
|
+
"0500060000020041",
|
|
55
|
+
"0500060000020043",
|
|
56
|
+
"0500060000020044",
|
|
57
|
+
"0500060000020051",
|
|
58
|
+
"0500060000020053",
|
|
59
|
+
"0500060000020054",
|
|
60
|
+
"0500060000020061",
|
|
61
|
+
"0500060000020062",
|
|
62
|
+
"05000600000200A0",
|
|
63
|
+
"05000600000200A1",
|
|
64
|
+
"0C00010000010018",
|
|
65
|
+
"0C0001000002000E",
|
|
66
|
+
"0C00010000020015",
|
|
67
|
+
"0C00010000020016",
|
|
68
|
+
"0C00010000020019",
|
|
69
|
+
"0C0001000002001A",
|
|
70
|
+
"0C0001000002001B",
|
|
71
|
+
"0C00040000020006",
|
|
72
|
+
],
|
|
73
|
+
"094": [
|
|
74
|
+
"0300180000000000",
|
|
75
|
+
"0300260000000000",
|
|
76
|
+
"050001000001000A",
|
|
77
|
+
"0500010000020003",
|
|
78
|
+
"0500010000020008",
|
|
79
|
+
"0500010000020009",
|
|
80
|
+
"0500010000030009",
|
|
81
|
+
"0500030000020010",
|
|
82
|
+
"0500030000020011",
|
|
83
|
+
"0500030000020012",
|
|
84
|
+
"0500030000020013",
|
|
85
|
+
"0500030000020014",
|
|
86
|
+
"0500030000020015",
|
|
87
|
+
"0500030000020016",
|
|
88
|
+
"0500030000020017",
|
|
89
|
+
"0500030000020018",
|
|
90
|
+
"0500030000030007",
|
|
91
|
+
"0500040000020020",
|
|
92
|
+
"0500050000010008",
|
|
93
|
+
"0500050000010009",
|
|
94
|
+
"050005000001000A",
|
|
95
|
+
"050005000001000B",
|
|
96
|
+
"050005000001000C",
|
|
97
|
+
"0500060000020001",
|
|
98
|
+
"0500060000020002",
|
|
99
|
+
"0500060000020003",
|
|
100
|
+
"0500060000020005",
|
|
101
|
+
"0500060000020006",
|
|
102
|
+
"0500060000020007",
|
|
103
|
+
"0500060000020008",
|
|
104
|
+
"0500060000020011",
|
|
105
|
+
"0500060000020012",
|
|
106
|
+
"0500060000020013",
|
|
107
|
+
"0500060000020014",
|
|
108
|
+
"0500060000020021",
|
|
109
|
+
"0500060000020022",
|
|
110
|
+
"0500060000020023",
|
|
111
|
+
"0500060000020024",
|
|
112
|
+
"0500060000020041",
|
|
113
|
+
"0500060000020042",
|
|
114
|
+
"0500060000020043",
|
|
115
|
+
"0500060000020044",
|
|
116
|
+
"0500060000020051",
|
|
117
|
+
"0500060000020052",
|
|
118
|
+
"0500060000020053",
|
|
119
|
+
"0500060000020054",
|
|
120
|
+
"0500060000020061",
|
|
121
|
+
"0500060000020062",
|
|
122
|
+
"05000600000200A0",
|
|
123
|
+
"05000600000200A1",
|
|
124
|
+
"0C00010000020015",
|
|
125
|
+
"0C00010000020016",
|
|
126
|
+
"0C00010000020019",
|
|
127
|
+
"0C0001000002001A",
|
|
128
|
+
"0C0001000002001B",
|
|
129
|
+
"0C00040000020006",
|
|
130
|
+
],
|
|
131
|
+
"20P": [
|
|
132
|
+
"0300180000000000",
|
|
133
|
+
"0300260000000000",
|
|
134
|
+
"050001000001000A",
|
|
135
|
+
"0500010000020003",
|
|
136
|
+
"0500010000020008",
|
|
137
|
+
"0500010000020009",
|
|
138
|
+
"050001000002000B",
|
|
139
|
+
"050001000002000F",
|
|
140
|
+
"0500010000020010",
|
|
141
|
+
"0500010000020011",
|
|
142
|
+
"0500010000030009",
|
|
143
|
+
"0500020000030009",
|
|
144
|
+
"050002000003000A",
|
|
145
|
+
"050002000003000B",
|
|
146
|
+
"050002000003000C",
|
|
147
|
+
"0500030000010053",
|
|
148
|
+
"0500030000020010",
|
|
149
|
+
"0500030000020011",
|
|
150
|
+
"0500030000020012",
|
|
151
|
+
"0500030000020013",
|
|
152
|
+
"0500030000020014",
|
|
153
|
+
"0500030000020015",
|
|
154
|
+
"0500030000020016",
|
|
155
|
+
"0500030000020017",
|
|
156
|
+
"0500030000020018",
|
|
157
|
+
"0500030000020019",
|
|
158
|
+
"0500030000020050",
|
|
159
|
+
"0500030000020051",
|
|
160
|
+
"0500030000020052",
|
|
161
|
+
"0500030000020053",
|
|
162
|
+
"0500030000020054",
|
|
163
|
+
"0500030000030007",
|
|
164
|
+
"0500040000010056",
|
|
165
|
+
"0500040000010060",
|
|
166
|
+
"0500040000010061",
|
|
167
|
+
"0500040000020020",
|
|
168
|
+
"0500050000010008",
|
|
169
|
+
"0500050000010009",
|
|
170
|
+
"050005000001000A",
|
|
171
|
+
"050005000001000B",
|
|
172
|
+
"050005000001000C",
|
|
173
|
+
"0500050000020023",
|
|
174
|
+
"0500050000020030",
|
|
175
|
+
"0500060000020005",
|
|
176
|
+
"0500060000020006",
|
|
177
|
+
"0500060000020007",
|
|
178
|
+
"0500060000020008",
|
|
179
|
+
"0500060000020009",
|
|
180
|
+
"0500060000020011",
|
|
181
|
+
"0500060000020012",
|
|
182
|
+
"0500060000020013",
|
|
183
|
+
"0500060000020014",
|
|
184
|
+
"0500060000020015",
|
|
185
|
+
"0500060000020021",
|
|
186
|
+
"0500060000020022",
|
|
187
|
+
"0500060000020023",
|
|
188
|
+
"0500060000020024",
|
|
189
|
+
"0500060000020025",
|
|
190
|
+
"0500060000020035",
|
|
191
|
+
"0500060000020041",
|
|
192
|
+
"0500060000020042",
|
|
193
|
+
"0500060000020044",
|
|
194
|
+
"0500060000020045",
|
|
195
|
+
"0500060000020051",
|
|
196
|
+
"0500060000020052",
|
|
197
|
+
"0500060000020054",
|
|
198
|
+
"0500060000020061",
|
|
199
|
+
"0500060000020062",
|
|
200
|
+
"0500060000020070",
|
|
201
|
+
"0500060000020071",
|
|
202
|
+
"05000600000200A0",
|
|
203
|
+
"05000600000200A1",
|
|
204
|
+
"0500070000020001",
|
|
205
|
+
"0500070000020002",
|
|
206
|
+
"0500070000020003",
|
|
207
|
+
"0500070000020101",
|
|
208
|
+
"0500070000020201",
|
|
209
|
+
"0503000000030027",
|
|
210
|
+
"0503000000030028",
|
|
211
|
+
"0503000000030029",
|
|
212
|
+
"0C00010000010018",
|
|
213
|
+
"0C0001000002000E",
|
|
214
|
+
"0C00010000020015",
|
|
215
|
+
"0C00010000020016",
|
|
216
|
+
"0C00010000020019",
|
|
217
|
+
"0C0001000002001A",
|
|
218
|
+
"0C0001000002001B",
|
|
219
|
+
"0C0003000003001A",
|
|
220
|
+
"0C00040000020006",
|
|
221
|
+
],
|
|
222
|
+
"22E": [
|
|
223
|
+
"0300180000000000",
|
|
224
|
+
"050001000001000A",
|
|
225
|
+
"0500010000020003",
|
|
226
|
+
"0500010000020008",
|
|
227
|
+
"0500010000020009",
|
|
228
|
+
"0500010000030009",
|
|
229
|
+
"0500030000010053",
|
|
230
|
+
"0500030000020010",
|
|
231
|
+
"0500030000020011",
|
|
232
|
+
"0500030000020012",
|
|
233
|
+
"0500030000020013",
|
|
234
|
+
"0500030000020014",
|
|
235
|
+
"0500030000020015",
|
|
236
|
+
"0500030000020016",
|
|
237
|
+
"0500030000020017",
|
|
238
|
+
"0500030000020018",
|
|
239
|
+
"0500030000030007",
|
|
240
|
+
"0500040000010056",
|
|
241
|
+
"0500040000020020",
|
|
242
|
+
"0500050000010008",
|
|
243
|
+
"0500050000010009",
|
|
244
|
+
"050005000001000A",
|
|
245
|
+
"050005000001000B",
|
|
246
|
+
"050005000001000C",
|
|
247
|
+
"0500050000020030",
|
|
248
|
+
"0500060000020005",
|
|
249
|
+
"0500060000020007",
|
|
250
|
+
"0500060000020008",
|
|
251
|
+
"0500060000020011",
|
|
252
|
+
"0500060000020012",
|
|
253
|
+
"0500060000020013",
|
|
254
|
+
"0500060000020014",
|
|
255
|
+
"0500060000020021",
|
|
256
|
+
"0500060000020022",
|
|
257
|
+
"0500060000020023",
|
|
258
|
+
"0500060000020024",
|
|
259
|
+
"0500060000020044",
|
|
260
|
+
"0500060000020054",
|
|
261
|
+
"0500060000020061",
|
|
262
|
+
"0500060000020062",
|
|
263
|
+
"05000600000200A0",
|
|
264
|
+
"05000600000200A1",
|
|
265
|
+
"0500070000020001",
|
|
266
|
+
"0500070000020002",
|
|
267
|
+
"0500070000020003",
|
|
268
|
+
"0500070000020101",
|
|
269
|
+
"0500070000020201",
|
|
270
|
+
"0503000000030027",
|
|
271
|
+
"0503000000030028",
|
|
272
|
+
"0503000000030029",
|
|
273
|
+
"0C00010000010018",
|
|
274
|
+
"0C0001000002000E",
|
|
275
|
+
"0C00010000020015",
|
|
276
|
+
"0C00010000020016",
|
|
277
|
+
"0C00010000020019",
|
|
278
|
+
"0C0001000002001A",
|
|
279
|
+
"0C0001000002001B",
|
|
280
|
+
"0C00040000020006",
|
|
281
|
+
],
|
|
282
|
+
"239": [
|
|
283
|
+
"0300180000000000",
|
|
284
|
+
"0300260000000000",
|
|
285
|
+
"0500010000020003",
|
|
286
|
+
"0500010000020008",
|
|
287
|
+
"0500010000020009",
|
|
288
|
+
"0500010000030009",
|
|
289
|
+
"0500030000020010",
|
|
290
|
+
"0500030000020011",
|
|
291
|
+
"0500030000020012",
|
|
292
|
+
"0500030000020013",
|
|
293
|
+
"0500030000020014",
|
|
294
|
+
"0500030000020015",
|
|
295
|
+
"0500030000020016",
|
|
296
|
+
"0500030000020017",
|
|
297
|
+
"0500030000020018",
|
|
298
|
+
"0500030000030007",
|
|
299
|
+
"0500040000020020",
|
|
300
|
+
"0500050000010008",
|
|
301
|
+
"0500050000010009",
|
|
302
|
+
"050005000001000A",
|
|
303
|
+
"050005000001000B",
|
|
304
|
+
"050005000001000C",
|
|
305
|
+
"0500060000020005",
|
|
306
|
+
"0500060000020006",
|
|
307
|
+
"0500060000020007",
|
|
308
|
+
"0500060000020008",
|
|
309
|
+
"0500060000020011",
|
|
310
|
+
"0500060000020012",
|
|
311
|
+
"0500060000020013",
|
|
312
|
+
"0500060000020014",
|
|
313
|
+
"0500060000020021",
|
|
314
|
+
"0500060000020022",
|
|
315
|
+
"0500060000020023",
|
|
316
|
+
"0500060000020024",
|
|
317
|
+
"0500060000020041",
|
|
318
|
+
"0500060000020042",
|
|
319
|
+
"0500060000020043",
|
|
320
|
+
"0500060000020044",
|
|
321
|
+
"0500060000020051",
|
|
322
|
+
"0500060000020052",
|
|
323
|
+
"0500060000020053",
|
|
324
|
+
"0500060000020054",
|
|
325
|
+
"0500060000020061",
|
|
326
|
+
"0500060000020062",
|
|
327
|
+
"05000600000200A0",
|
|
328
|
+
"05000600000200A1",
|
|
329
|
+
"0C00010000020015",
|
|
330
|
+
"0C00010000020016",
|
|
331
|
+
"0C00010000020019",
|
|
332
|
+
"0C0001000002001A",
|
|
333
|
+
"0C0001000002001B",
|
|
334
|
+
"0C00040000020006",
|
|
335
|
+
],
|
|
336
|
+
"31B": [
|
|
337
|
+
"0300180000000000",
|
|
338
|
+
"0300260000000000",
|
|
339
|
+
"050001000001000A",
|
|
340
|
+
"0500010000020003",
|
|
341
|
+
"0500010000020008",
|
|
342
|
+
"0500010000020009",
|
|
343
|
+
"0500010000030009",
|
|
344
|
+
"0500030000010053",
|
|
345
|
+
"0500030000020010",
|
|
346
|
+
"0500030000020011",
|
|
347
|
+
"0500030000020012",
|
|
348
|
+
"0500030000020013",
|
|
349
|
+
"0500030000020014",
|
|
350
|
+
"0500030000020015",
|
|
351
|
+
"0500030000020016",
|
|
352
|
+
"0500030000020017",
|
|
353
|
+
"0500030000020018",
|
|
354
|
+
"0500030000030007",
|
|
355
|
+
"0500040000010056",
|
|
356
|
+
"0500040000020020",
|
|
357
|
+
"0500050000010008",
|
|
358
|
+
"0500050000010009",
|
|
359
|
+
"050005000001000A",
|
|
360
|
+
"050005000001000B",
|
|
361
|
+
"050005000001000C",
|
|
362
|
+
"0500050000020030",
|
|
363
|
+
"0500060000020005",
|
|
364
|
+
"0500060000020006",
|
|
365
|
+
"0500060000020007",
|
|
366
|
+
"0500060000020008",
|
|
367
|
+
"0500060000020011",
|
|
368
|
+
"0500060000020012",
|
|
369
|
+
"0500060000020013",
|
|
370
|
+
"0500060000020014",
|
|
371
|
+
"0500060000020021",
|
|
372
|
+
"0500060000020022",
|
|
373
|
+
"0500060000020023",
|
|
374
|
+
"0500060000020024",
|
|
375
|
+
"0500060000020041",
|
|
376
|
+
"0500060000020042",
|
|
377
|
+
"0500060000020043",
|
|
378
|
+
"0500060000020044",
|
|
379
|
+
"0500060000020051",
|
|
380
|
+
"0500060000020052",
|
|
381
|
+
"0500060000020053",
|
|
382
|
+
"0500060000020054",
|
|
383
|
+
"0500060000020061",
|
|
384
|
+
"0500060000020062",
|
|
385
|
+
"05000600000200A0",
|
|
386
|
+
"05000600000200A1",
|
|
387
|
+
"0500070000020001",
|
|
388
|
+
"0500070000020002",
|
|
389
|
+
"0500070000020003",
|
|
390
|
+
"0500070000020101",
|
|
391
|
+
"0500070000020201",
|
|
392
|
+
"0503000000030027",
|
|
393
|
+
"0503000000030028",
|
|
394
|
+
"0503000000030029",
|
|
395
|
+
"0C00010000010018",
|
|
396
|
+
"0C0001000002000E",
|
|
397
|
+
"0C00010000020015",
|
|
398
|
+
"0C00010000020016",
|
|
399
|
+
"0C00010000020019",
|
|
400
|
+
"0C0001000002001A",
|
|
401
|
+
"0C0001000002001B",
|
|
402
|
+
"0C0003000003001A",
|
|
403
|
+
"0C00040000020006",
|
|
404
|
+
],
|
|
405
|
+
};
|
package/dist/safety/limits.d.ts
CHANGED
|
@@ -21,6 +21,12 @@ export declare const MACHINE_LIMITS: Readonly<Record<string, {
|
|
|
21
21
|
chamber: number;
|
|
22
22
|
volume: readonly number[];
|
|
23
23
|
}>>;
|
|
24
|
+
/** Printers with two physical nozzles. Bambu Studio numbers the right/main nozzle 0
|
|
25
|
+
* (MAIN_EXTRUDER_ID) and the left/deputy nozzle 1 (DEPUTY_EXTRUDER_ID), and reports one
|
|
26
|
+
* virtual external-spool slot per nozzle: 255 (VIRTUAL_TRAY_MAIN_ID) and 254
|
|
27
|
+
* (VIRTUAL_TRAY_DEPUTY_ID). The single-nozzle H2S is deliberately absent. */
|
|
28
|
+
export declare const DUAL_NOZZLE_MODELS: ReadonlySet<string>;
|
|
29
|
+
export declare function isDualNozzleModel(model: unknown): boolean;
|
|
24
30
|
export declare function normalizeModel(value: unknown): string | undefined;
|
|
25
31
|
export declare function normalizeMaterial(value: unknown): string | undefined;
|
|
26
32
|
export declare function validateTemperature(component: 'nozzle' | 'bed' | 'chamber', value: unknown, model: string, materials?: string[]): number;
|
package/dist/safety/limits.js
CHANGED
|
@@ -30,6 +30,15 @@ export const MACHINE_LIMITS = {
|
|
|
30
30
|
h2s: { nozzle: 350, bed: 120, chamber: 65, volume: [340, 320, 340] },
|
|
31
31
|
x2d: { nozzle: 300, bed: 120, chamber: 65, volume: [256, 256, 260] },
|
|
32
32
|
};
|
|
33
|
+
/** Printers with two physical nozzles. Bambu Studio numbers the right/main nozzle 0
|
|
34
|
+
* (MAIN_EXTRUDER_ID) and the left/deputy nozzle 1 (DEPUTY_EXTRUDER_ID), and reports one
|
|
35
|
+
* virtual external-spool slot per nozzle: 255 (VIRTUAL_TRAY_MAIN_ID) and 254
|
|
36
|
+
* (VIRTUAL_TRAY_DEPUTY_ID). The single-nozzle H2S is deliberately absent. */
|
|
37
|
+
export const DUAL_NOZZLE_MODELS = new Set(['h2d', 'h2dpro', 'h2c', 'x2d']);
|
|
38
|
+
export function isDualNozzleModel(model) {
|
|
39
|
+
const normalized = normalizeModel(model);
|
|
40
|
+
return normalized !== undefined && DUAL_NOZZLE_MODELS.has(normalized);
|
|
41
|
+
}
|
|
33
42
|
export function normalizeModel(value) {
|
|
34
43
|
if (typeof value !== 'string')
|
|
35
44
|
return undefined;
|
|
@@ -12,6 +12,8 @@ export interface PrintFileInspection {
|
|
|
12
12
|
selectsAms: boolean;
|
|
13
13
|
nozzleTypes?: string[];
|
|
14
14
|
nozzleFlows?: string[];
|
|
15
|
+
/** Physical nozzle index for each declared filament, composed from the selected plate headers. */
|
|
16
|
+
filamentNozzleIndices?: number[];
|
|
15
17
|
}
|
|
16
18
|
/** Inspect the exact selected plate. This does not simulate firmware or arbitrary motion:
|
|
17
19
|
* only declared object bounds are checked, never purge/homing/wipe travel coordinates.
|