bambu-printer-mcp 1.1.2 → 1.1.4
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/README.md +9 -9
- package/dist/index.js +19 -13
- package/dist/printers/bambu.d.ts +2 -1
- package/dist/printers/bambu.js +15 -7
- package/package.json +1 -1
- package/src/index.ts +19 -13
- package/src/printers/bambu.ts +19 -7
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ A Bambu Lab-focused MCP server for controlling Bambu printers, manipulating STL
|
|
|
11
11
|
|
|
12
12
|
This is a stripped-down, Bambu-only fork of [mcp-3D-printer-server](https://github.com/DMontgomery40/mcp-3D-printer-server). All OctoPrint, Klipper, Duet, Repetier, Prusa Connect, and Creality Cloud support has been removed. What remains is a focused, lean implementation for Bambu Lab hardware.
|
|
13
13
|
|
|
14
|
-
Local handoff note: see [REMOTE-DEPLOYMENT.md](./REMOTE-DEPLOYMENT.md) for the custom H2D/H2S patches, per-printer MCP split, and remote deployment plan used in this clone.
|
|
14
|
+
Local handoff note: see [REMOTE-DEPLOYMENT.md](./REMOTE-DEPLOYMENT.md) for the custom H2D/H2S/H2C patches, per-printer MCP split, and remote deployment plan used in this clone.
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
@@ -29,7 +29,7 @@ This fork adds a substantial set of printer control tools beyond the upstream `m
|
|
|
29
29
|
- **Skip objects** (`skip_objects`) — skip specific object IDs during a running multi-object print. IDs from `list_3mf_plate_objects`.
|
|
30
30
|
- **HMS diagnostics** (`printer://{host}/hms` MCP resource) — read-only error summary with automatic settle retry.
|
|
31
31
|
- **Utility controls** — `set_print_speed` (silent/standard/sport/ludicrous), `clear_hms_errors`, `reread_ams_rfid`, `set_airduct_mode` (cooling/heating for H2/P2).
|
|
32
|
-
- **H2
|
|
32
|
+
- **H2-family-safe print path** — correct `project_file` format with `ams_mapping2` parallel array, H2 firmware quirks handled.
|
|
33
33
|
- **BambuStudio CLI auto-flatten** (`BAMBU_CLI_FLATTEN=true`) — works around upstream profile inheritance bugs.
|
|
34
34
|
- **Print collar charm** (`print_collar_charm`) — specialized two-color wrapper with fixed tray policy.
|
|
35
35
|
|
|
@@ -100,8 +100,8 @@ This fork adds a substantial set of printer control tools beyond the upstream `m
|
|
|
100
100
|
- List, upload, and delete files on the printer's SD card via FTPS
|
|
101
101
|
- Capture a JPEG snapshot from the chamber camera. Supports A1, A1 mini, P1S, P1P (TCP-on-6000), and X1, X1C, X1E, P2S, H2, H2S, H2D, H2C, H2D Pro (RTSP via ffmpeg). Requires ffmpeg in PATH for the RTSP path.
|
|
102
102
|
- Upload and print pre-sliced `.gcode.3mf` files with full plate selection and calibration flag control (recommended path — see [docs/SLICING.md](./docs/SLICING.md))
|
|
103
|
-
- Optional single-color auto-slice path via BambuStudio CLI. Set `BAMBU_CLI_FLATTEN=true` to enable a workaround that flattens BBL profile inheritance before invoking the CLI — works around upstream bugs in BambuStudio CLI mode ([#9636](https://github.com/bambulab/BambuStudio/issues/9636), [#9968](https://github.com/bambulab/BambuStudio/issues/9968)). Single-color smoke is verified on H2S/H2D/X1C/P1S. H2D two-color CLI slicing is blocked upstream ([#10408](https://github.com/bambulab/BambuStudio/issues/10408)); use a GUI-sliced `.gcode.3mf` for that workflow. Default off; Path A (GUI-slice) remains the recommended workflow for non-BBL profiles, multi-color
|
|
104
|
-
- Parse AMS mapping from the 3MF's embedded slicer metadata (`Metadata/plate_<n>.json` + gcode filament header) and send it correctly formatted per the OpenBambuAPI spec, with correct H2S/H2D `ams_mapping2` parallel array format
|
|
103
|
+
- Optional single-color auto-slice path via BambuStudio CLI. Set `BAMBU_CLI_FLATTEN=true` to enable a workaround that flattens BBL profile inheritance before invoking the CLI — works around upstream bugs in BambuStudio CLI mode ([#9636](https://github.com/bambulab/BambuStudio/issues/9636), [#9968](https://github.com/bambulab/BambuStudio/issues/9968)). Single-color smoke is verified on H2S/H2D/X1C/P1S; H2C requires Bambu Studio 2.4.0 or newer and should use `BAMBU_MODEL=h2c`, not an H2D fallback. H2D two-color CLI slicing is blocked upstream ([#10408](https://github.com/bambulab/BambuStudio/issues/10408)); use a GUI-sliced `.gcode.3mf` for that workflow. Default off; Path A (GUI-slice) remains the recommended workflow for non-BBL profiles, multi-color H2 jobs, or first-time prints. See [docs/SLICING.md](./docs/SLICING.md).
|
|
104
|
+
- Parse AMS mapping from the 3MF's embedded slicer metadata (`Metadata/plate_<n>.json` + gcode filament header) and send it correctly formatted per the OpenBambuAPI spec, with correct H2S/H2D/H2C `ams_mapping2` parallel array format
|
|
105
105
|
- **Auto-match AMS slots by RFID** (`auto_match_ams` flag on `print_3mf`). Resolves required `tray_info_idx` from the sliced 3MF against live AMS inventory. Handles same-SKU different-color filaments by matching on `(tray_info_idx, tray_color)` and tracking already-claimed slots. Dry-run with `resolve_3mf_ams_slots` before printing.
|
|
106
106
|
- Cancel, pause, and resume in-progress print jobs via MQTT
|
|
107
107
|
- Skip specific objects during a running multi-object print via `skip_objects` (use `list_3mf_plate_objects` to find object IDs first)
|
|
@@ -178,7 +178,7 @@ BAMBU_TOKEN=your_access_token # LAN access token from printer touchscreen
|
|
|
178
178
|
# BAMBU_PRINTER_HOST / BAMBU_PRINTER_SERIAL / BAMBU_PRINTER_ACCESS_TOKEN
|
|
179
179
|
|
|
180
180
|
# --- Printer model (CRITICAL for safe operation) ---
|
|
181
|
-
BAMBU_MODEL=p1s # Your printer model: p1s, p1p, x1c, x1e, a1, a1mini, h2d, h2s
|
|
181
|
+
BAMBU_MODEL=p1s # Your printer model: p1s, p1p, p2s, x1c, x1e, a1, a1mini, h2d, h2s, h2c
|
|
182
182
|
# Alias also accepted: BAMBU_PRINTER_MODEL
|
|
183
183
|
BED_TYPE=textured_plate # Bed plate type: textured_plate, cool_plate, engineering_plate, hot_plate, supertack_plate
|
|
184
184
|
NOZZLE_DIAMETER=0.4 # Nozzle diameter in mm (default: 0.4)
|
|
@@ -215,7 +215,7 @@ BLENDER_MCP_BRIDGE_COMMAND= # Shell command to invoke your Blender MCP bri
|
|
|
215
215
|
| `PRINTER_HOST` | `localhost` | Yes | IP address of the Bambu printer. Alias: `BAMBU_PRINTER_HOST` |
|
|
216
216
|
| `BAMBU_SERIAL` | | Yes | Printer serial number. Alias: `BAMBU_PRINTER_SERIAL` |
|
|
217
217
|
| `BAMBU_TOKEN` | | Yes | LAN access token. Alias: `BAMBU_PRINTER_ACCESS_TOKEN` |
|
|
218
|
-
| `BAMBU_MODEL` | | **Yes** | Printer model: `p1s`, `p1p`, `x1c`, `x1e`, `a1`, `a1mini`, `h2d`, `h2s`. **Required for safe operation** -- determines the correct G-code generation. Alias: `BAMBU_PRINTER_MODEL`. If omitted and the MCP client supports elicitation, the server will ask you interactively. |
|
|
218
|
+
| `BAMBU_MODEL` | | **Yes** | Printer model: `p1s`, `p1p`, `p2s`, `x1c`, `x1e`, `a1`, `a1mini`, `h2d`, `h2s`, `h2c`. **Required for safe operation** -- determines the correct G-code generation. Alias: `BAMBU_PRINTER_MODEL`. If omitted and the MCP client supports elicitation, the server will ask you interactively. Use `h2c` for H2C; do not use `h2d` as a fallback. |
|
|
219
219
|
| `BED_TYPE` | `textured_plate` | No | Bed plate type: `textured_plate`, `cool_plate`, `engineering_plate`, `hot_plate`, `supertack_plate` |
|
|
220
220
|
| `NOZZLE_DIAMETER` | `0.4` | No | Nozzle diameter in mm. Used to select the correct BambuStudio machine preset. |
|
|
221
221
|
| `SLICER_TYPE` | `bambustudio` | No | Slicer to use for slicing operations |
|
|
@@ -230,7 +230,7 @@ BLENDER_MCP_BRIDGE_COMMAND= # Shell command to invoke your Blender MCP bri
|
|
|
230
230
|
| `MCP_HTTP_JSON_RESPONSE` | `true` | No | Return structured JSON alongside text responses |
|
|
231
231
|
| `MCP_HTTP_ALLOWED_ORIGINS` | | No | Comma-separated list of allowed CORS origins |
|
|
232
232
|
| `BLENDER_MCP_BRIDGE_COMMAND` | | No | Command to invoke Blender MCP bridge |
|
|
233
|
-
| `BAMBU_CLI_FLATTEN` | `false` | No | When `true`, the MCP flattens BBL profile inheritance before invoking the BambuStudio CLI. Workaround for upstream issues [#9636](https://github.com/bambulab/BambuStudio/issues/9636) / [#9968](https://github.com/bambulab/BambuStudio/issues/9968). BBL printers only. Single-color smoke verified on H2S/H2D/X1C/P1S; H2D two-color CLI slicing remains blocked by [#10408](https://github.com/bambulab/BambuStudio/issues/10408). See [docs/SLICING.md](./docs/SLICING.md). |
|
|
233
|
+
| `BAMBU_CLI_FLATTEN` | `false` | No | When `true`, the MCP flattens BBL profile inheritance before invoking the BambuStudio CLI. Workaround for upstream issues [#9636](https://github.com/bambulab/BambuStudio/issues/9636) / [#9968](https://github.com/bambulab/BambuStudio/issues/9968). BBL printers only. Single-color smoke verified on H2S/H2D/X1C/P1S; H2C requires Bambu Studio 2.4.0 or newer. H2D two-color CLI slicing remains blocked by [#10408](https://github.com/bambulab/BambuStudio/issues/10408). See [docs/SLICING.md](./docs/SLICING.md). |
|
|
234
234
|
| `BAMBU_PROFILES_ROOT` | derived from `SLICER_PATH` | No | Override path to the BambuStudio `Resources/profiles` directory used by the CLI flattener. Useful for non-standard installs or dev environments. |
|
|
235
235
|
|
|
236
236
|
SuperTack can be passed for pre-sliced print jobs, but BambuStudio CLI slicing currently fails fast for `supertack_plate` because the accepted CLI bed identifier is not verified. Use a pre-sliced 3MF for SuperTack until this is confirmed.
|
|
@@ -513,7 +513,7 @@ This fork sends the `project_file` command directly via `bambu-node` (bypassing
|
|
|
513
513
|
// P1/A1/X1-series: 5-element project lookup table
|
|
514
514
|
ams_mapping = [0, -1, -1, -1, -1];
|
|
515
515
|
|
|
516
|
-
// H2S/H2D: project-length lookup table + parallel ams_mapping2
|
|
516
|
+
// H2S/H2D/H2C: project-length lookup table + parallel ams_mapping2
|
|
517
517
|
ams_mapping = [-1, 1, -1, -1];
|
|
518
518
|
ams_mapping2 = [
|
|
519
519
|
{ ams_id: 255, slot_id: 255 },
|
|
@@ -1026,7 +1026,7 @@ The primary tool for starting a Bambu print. **Recommended input: a pre-sliced `
|
|
|
1026
1026
|
3. Parses the sliced 3MF to extract the correct plate file and compute its MD5 hash.
|
|
1027
1027
|
4. Also parses `Metadata/project_settings.config` to read AMS mapping embedded by Bambu Studio.
|
|
1028
1028
|
5. Uploads the 3MF to the printer's `cache/` directory via FTPS using `basic-ftp` directly (avoiding the bambu-js double-path bug).
|
|
1029
|
-
6. Sends the correct MQTT print command for the target printer family. For H2S/H2D that means `project_file` with project-length `ams_mapping`, parallel `ams_mapping2`, and H2-compatible calibration flags.
|
|
1029
|
+
6. Sends the correct MQTT print command for the target printer family. For H2S/H2D/H2C that means `project_file` with project-length `ams_mapping`, parallel `ams_mapping2`, and H2-compatible calibration flags.
|
|
1030
1030
|
|
|
1031
1031
|
```json
|
|
1032
1032
|
{
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,8 @@ const DEFAULT_BAMBU_MODEL = process.env.BAMBU_PRINTER_MODEL?.trim().toLowerCase(
|
|
|
25
25
|
"";
|
|
26
26
|
const DEFAULT_BED_TYPE = process.env.BED_TYPE?.trim().toLowerCase() || "textured_plate";
|
|
27
27
|
const DEFAULT_NOZZLE_DIAMETER = process.env.NOZZLE_DIAMETER?.trim() || "0.4";
|
|
28
|
-
const VALID_BAMBU_MODELS = ["p1s", "p1p", "p2s", "x1c", "x1e", "a1", "a1mini", "h2d", "h2s"];
|
|
28
|
+
const VALID_BAMBU_MODELS = ["p1s", "p1p", "p2s", "x1c", "x1e", "a1", "a1mini", "h2d", "h2s", "h2c"];
|
|
29
|
+
const H2_BAMBU_MODELS = new Set(["h2d", "h2s", "h2c"]);
|
|
29
30
|
const VALID_BED_TYPES = ["textured_plate", "cool_plate", "engineering_plate", "hot_plate", "supertack_plate"];
|
|
30
31
|
const VALID_BAMBUSTUDIO_CLI_BED_TYPES = ["textured_plate", "cool_plate", "engineering_plate", "hot_plate"];
|
|
31
32
|
// Map model IDs to BambuStudio --load-machine preset names
|
|
@@ -39,6 +40,7 @@ const BAMBU_MODEL_PRESETS = {
|
|
|
39
40
|
a1mini: (n) => `Bambu Lab A1 mini ${n} nozzle`,
|
|
40
41
|
h2d: (n) => `Bambu Lab H2D ${n} nozzle`,
|
|
41
42
|
h2s: (n) => `Bambu Lab H2S ${n} nozzle`,
|
|
43
|
+
h2c: (n) => `Bambu Lab H2C ${n} nozzle`,
|
|
42
44
|
};
|
|
43
45
|
const FILAMENT_PROFILE_DIR = "/Applications/BambuStudio.app/Contents/Resources/profiles/BBL/filament";
|
|
44
46
|
const FILAMENT_MODEL_CODES = {
|
|
@@ -51,6 +53,7 @@ const FILAMENT_MODEL_CODES = {
|
|
|
51
53
|
a1mini: "A1M",
|
|
52
54
|
h2d: "H2D",
|
|
53
55
|
h2s: "H2S",
|
|
56
|
+
h2c: "H2C",
|
|
54
57
|
};
|
|
55
58
|
const COLLAR_CHARM_POLICY = getCollarCharmRolePolicy();
|
|
56
59
|
let filamentProfileIndexCache = null;
|
|
@@ -794,6 +797,7 @@ class BambuPrinterMCPServer {
|
|
|
794
797
|
{ const: "a1mini", title: "A1 Mini" },
|
|
795
798
|
{ const: "h2d", title: "H2D" },
|
|
796
799
|
{ const: "h2s", title: "H2S" },
|
|
800
|
+
{ const: "h2c", title: "H2C" },
|
|
797
801
|
],
|
|
798
802
|
},
|
|
799
803
|
},
|
|
@@ -1311,7 +1315,7 @@ class BambuPrinterMCPServer {
|
|
|
1311
1315
|
},
|
|
1312
1316
|
bambu_model: {
|
|
1313
1317
|
type: "string",
|
|
1314
|
-
enum: [
|
|
1318
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
1315
1319
|
description: "Optional model hint used to resolve Bambu/Orca filament profile JSONs for each tray."
|
|
1316
1320
|
},
|
|
1317
1321
|
nozzle_diameter: {
|
|
@@ -1331,7 +1335,7 @@ class BambuPrinterMCPServer {
|
|
|
1331
1335
|
plate_index: { type: "number", description: "0-based plate index to inspect (default: 0)" },
|
|
1332
1336
|
bambu_model: {
|
|
1333
1337
|
type: "string",
|
|
1334
|
-
enum: [
|
|
1338
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
1335
1339
|
description: "Optional model hint used to resolve Bambu/Orca filament profile JSONs for each tray."
|
|
1336
1340
|
},
|
|
1337
1341
|
nozzle_diameter: { type: "string", description: "Nozzle diameter in mm (default: 0.4)" },
|
|
@@ -1472,7 +1476,7 @@ class BambuPrinterMCPServer {
|
|
|
1472
1476
|
template_dir: { type: "string", description: "Optional template directory override when resolving template_name." },
|
|
1473
1477
|
bambu_model: {
|
|
1474
1478
|
type: "string",
|
|
1475
|
-
enum: [
|
|
1479
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
1476
1480
|
description: "REQUIRED: Bambu Lab printer model. Ask the user if not known. Using the wrong model can damage the printer."
|
|
1477
1481
|
},
|
|
1478
1482
|
slicer_type: {
|
|
@@ -1518,7 +1522,7 @@ class BambuPrinterMCPServer {
|
|
|
1518
1522
|
stl_path: { type: "string", description: "Path to the STL or 3MF file to slice" },
|
|
1519
1523
|
bambu_model: {
|
|
1520
1524
|
type: "string",
|
|
1521
|
-
enum: [
|
|
1525
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
1522
1526
|
description: "REQUIRED: Bambu Lab printer model. Ask the user if not known. Using the wrong model can damage the printer."
|
|
1523
1527
|
},
|
|
1524
1528
|
slicer_type: {
|
|
@@ -1615,7 +1619,7 @@ class BambuPrinterMCPServer {
|
|
|
1615
1619
|
three_mf_path: { type: "string", description: "Path to the 3MF file to print; unsliced 3MFs are auto-sliced before sending." },
|
|
1616
1620
|
bambu_model: {
|
|
1617
1621
|
type: "string",
|
|
1618
|
-
enum: [
|
|
1622
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
1619
1623
|
description: "REQUIRED: Bambu Lab printer model. Ask the user if not known. Using the wrong model can damage the printer."
|
|
1620
1624
|
},
|
|
1621
1625
|
connection_type: { type: "string", enum: ["cloud", "lan"], description: "BambuNetwork connection type to put in FULU PrintParams; cloud uses restored internet printing, lan uses local bridge printing." },
|
|
@@ -1730,7 +1734,7 @@ class BambuPrinterMCPServer {
|
|
|
1730
1734
|
print: { type: "boolean", description: "Start printing after upload (default: false)" },
|
|
1731
1735
|
bambu_model: {
|
|
1732
1736
|
type: "string",
|
|
1733
|
-
enum: [
|
|
1737
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
1734
1738
|
description: "Required when print is true. Bambu Lab printer model used as a safety confirmation before starting the uploaded file."
|
|
1735
1739
|
},
|
|
1736
1740
|
host: { type: "string", description: "Hostname or IP of the printer (default: value from env)" },
|
|
@@ -1749,7 +1753,7 @@ class BambuPrinterMCPServer {
|
|
|
1749
1753
|
filename: { type: "string", description: "Name of the file to print" },
|
|
1750
1754
|
bambu_model: {
|
|
1751
1755
|
type: "string",
|
|
1752
|
-
enum: [
|
|
1756
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
1753
1757
|
description: "REQUIRED: Bambu Lab printer model. Ask the user if not known. Starting G-code for the wrong model can damage the printer."
|
|
1754
1758
|
},
|
|
1755
1759
|
host: { type: "string", description: "Hostname or IP of the printer (default: value from env)" },
|
|
@@ -1768,7 +1772,7 @@ class BambuPrinterMCPServer {
|
|
|
1768
1772
|
filename: { type: "string", description: "Name of the file to print" },
|
|
1769
1773
|
bambu_model: {
|
|
1770
1774
|
type: "string",
|
|
1771
|
-
enum: [
|
|
1775
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
1772
1776
|
description: "REQUIRED: Bambu Lab printer model. Ask the user if not known. Starting G-code for the wrong model can damage the printer."
|
|
1773
1777
|
},
|
|
1774
1778
|
host: { type: "string", description: "Hostname or IP of the printer (default: value from env)" },
|
|
@@ -1981,7 +1985,7 @@ class BambuPrinterMCPServer {
|
|
|
1981
1985
|
three_mf_path: { type: "string", description: "Path to the 3MF file to print" },
|
|
1982
1986
|
bambu_model: {
|
|
1983
1987
|
type: "string",
|
|
1984
|
-
enum: [
|
|
1988
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
1985
1989
|
description: "REQUIRED: Bambu Lab printer model. Ask the user if not known. Using the wrong model can damage the printer."
|
|
1986
1990
|
},
|
|
1987
1991
|
connection_mode: {
|
|
@@ -2051,8 +2055,8 @@ class BambuPrinterMCPServer {
|
|
|
2051
2055
|
template_dir: { type: "string", description: "Optional template directory override when resolving template_name." },
|
|
2052
2056
|
bambu_model: {
|
|
2053
2057
|
type: "string",
|
|
2054
|
-
enum: [
|
|
2055
|
-
description: "REQUIRED: Bambu Lab printer model. H2D and
|
|
2058
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
2059
|
+
description: "REQUIRED: Bambu Lab printer model. H2D, H2S, and H2C are the primary intended paths."
|
|
2056
2060
|
},
|
|
2057
2061
|
host: { type: "string", description: "Hostname or IP of the printer (default: value from env)" },
|
|
2058
2062
|
bambu_serial: { type: "string", description: "Serial number (default: value from env)" },
|
|
@@ -2590,7 +2594,7 @@ class BambuPrinterMCPServer {
|
|
|
2590
2594
|
console.warn("Could not check/slice 3MF, proceeding with original:", sliceCheckErr.message);
|
|
2591
2595
|
}
|
|
2592
2596
|
const parsed3MFData = await parse3MF(threeMFPath);
|
|
2593
|
-
const isH2Print = printModel
|
|
2597
|
+
const isH2Print = H2_BAMBU_MODELS.has(printModel);
|
|
2594
2598
|
let parsedAmsMapping;
|
|
2595
2599
|
if (!isH2Print && parsed3MFData.slicerConfig?.ams_mapping) {
|
|
2596
2600
|
const slots = normalizeAmsMappingObject(parsed3MFData.slicerConfig.ams_mapping);
|
|
@@ -2661,6 +2665,7 @@ class BambuPrinterMCPServer {
|
|
|
2661
2665
|
result = await this.bambu.print3mf(host, bambuSerial, bambuToken, {
|
|
2662
2666
|
projectName,
|
|
2663
2667
|
filePath: threeMFPath,
|
|
2668
|
+
bambuModel: printModel,
|
|
2664
2669
|
plateIndex,
|
|
2665
2670
|
useAMS: useAMS,
|
|
2666
2671
|
amsMapping: finalAmsMapping,
|
|
@@ -2696,6 +2701,7 @@ class BambuPrinterMCPServer {
|
|
|
2696
2701
|
result = await this.bambu.print3mf(host, bambuSerial, bambuToken, {
|
|
2697
2702
|
projectName,
|
|
2698
2703
|
filePath: preparedThreeMFPath,
|
|
2704
|
+
bambuModel: printModel,
|
|
2699
2705
|
plateIndex: collarAnalysis.plateIndex,
|
|
2700
2706
|
useAMS: true,
|
|
2701
2707
|
amsSlots: collarAnalysis.amsSlots,
|
package/dist/printers/bambu.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
interface BambuPrintOptionsInternal {
|
|
2
2
|
projectName: string;
|
|
3
3
|
filePath: string;
|
|
4
|
+
bambuModel?: string;
|
|
4
5
|
useAMS?: boolean;
|
|
5
6
|
plateIndex?: number;
|
|
6
7
|
bedType?: string;
|
|
@@ -94,7 +95,7 @@ export declare class BambuImplementation {
|
|
|
94
95
|
* [16..16+payloadSize] JPEG (FF D8 ... FF D9)
|
|
95
96
|
*
|
|
96
97
|
* Verified models per upstream docs: A1, A1 mini, P1S, P1P. X1/X1C/X1E
|
|
97
|
-
* and P2S use RTSP on port 322 instead
|
|
98
|
+
* and P2S use RTSP on port 322 instead. H2/H2S/H2D/H2C
|
|
98
99
|
* are not documented; we fail fast rather than guess at the protocol.
|
|
99
100
|
*
|
|
100
101
|
* Read-only; no confirm gate. Default 8s timeout for cold-start latency.
|
package/dist/printers/bambu.js
CHANGED
|
@@ -32,6 +32,8 @@ function loadClientCreds() {
|
|
|
32
32
|
const CLIENT_CREDS = loadClientCreds();
|
|
33
33
|
const COMMAND_SETTLE_MS = 300;
|
|
34
34
|
const MODEL_ID_TO_NAME = {
|
|
35
|
+
O1C: "H2C",
|
|
36
|
+
O1C2: "H2C",
|
|
35
37
|
O1D: "H2D",
|
|
36
38
|
O1E: "H2D Pro",
|
|
37
39
|
O1S: "H2S",
|
|
@@ -43,6 +45,10 @@ const MODEL_ID_TO_NAME = {
|
|
|
43
45
|
"BL-P002": "X1",
|
|
44
46
|
C13: "X1E",
|
|
45
47
|
};
|
|
48
|
+
const H2_MODEL_NAMES = new Set(["h2", "h2c", "h2d", "h2dpro", "h2d pro", "h2s"]);
|
|
49
|
+
function isH2ModelName(model) {
|
|
50
|
+
return H2_MODEL_NAMES.has(String(model ?? "").trim().toLowerCase().replace(/\s+/g, " "));
|
|
51
|
+
}
|
|
46
52
|
function sleep(ms) {
|
|
47
53
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
48
54
|
}
|
|
@@ -72,7 +78,7 @@ class TolerantBambuClient extends BambuClient {
|
|
|
72
78
|
await subscribe(`device/${this.config.serialNumber}/report`);
|
|
73
79
|
}
|
|
74
80
|
/**
|
|
75
|
-
*
|
|
81
|
+
* H2-series printers don't respond to get_version with module info.
|
|
76
82
|
* Infer model from serial number prefix so downstream code (Job, status
|
|
77
83
|
* parsing, etc.) has a valid printerModel instead of undefined.
|
|
78
84
|
*/
|
|
@@ -155,7 +161,7 @@ class TolerantBambuClient extends BambuClient {
|
|
|
155
161
|
reject(err);
|
|
156
162
|
});
|
|
157
163
|
});
|
|
158
|
-
//
|
|
164
|
+
// H2-series printers don't respond to get_version with module info.
|
|
159
165
|
// Infer model from serial number prefix so downstream code works.
|
|
160
166
|
if (!this.data.model) {
|
|
161
167
|
const inferred = this.inferModelFromSerial();
|
|
@@ -450,9 +456,11 @@ export class BambuImplementation {
|
|
|
450
456
|
// the container format from the extension.
|
|
451
457
|
let remoteFileName = path.basename(options.filePath);
|
|
452
458
|
remoteFileName = remoteFileName.replace(/\.gcode\.3mf\.gcode\.3mf$/i, ".gcode.3mf");
|
|
453
|
-
//
|
|
459
|
+
// H2-series printers land files at the FTP root and reference them via ftp:///<name>.
|
|
454
460
|
// P1/A1/X1 use /cache/<name> and file:///sdcard/cache/<name>.
|
|
455
|
-
const isH2 = serial.startsWith("093") ||
|
|
461
|
+
const isH2 = serial.startsWith("093") ||
|
|
462
|
+
serial.startsWith("094") ||
|
|
463
|
+
isH2ModelName(options.bambuModel);
|
|
456
464
|
const remoteProjectPath = isH2 ? remoteFileName : `cache/${remoteFileName}`;
|
|
457
465
|
const remoteUploadPath = isH2 ? `/${remoteFileName}` : `/cache/${remoteFileName}`;
|
|
458
466
|
const projectUrl = isH2
|
|
@@ -463,7 +471,7 @@ export class BambuImplementation {
|
|
|
463
471
|
// Pre-sliced .gcode.3mf files: routing depends on firmware generation.
|
|
464
472
|
// P1/A1/X1 series: project_file returns 405004002 for .gcode.3mf (firmware
|
|
465
473
|
// doesn't recognise the container), so use gcode_file instead.
|
|
466
|
-
//
|
|
474
|
+
// H2-series: gcode_file is not supported; project_file works because the
|
|
467
475
|
// firmware can open the zip and find Metadata/plate_<n>.gcode directly.
|
|
468
476
|
if (options.filePath.toLowerCase().endsWith(".gcode.3mf")) {
|
|
469
477
|
if (!isH2) {
|
|
@@ -475,7 +483,7 @@ export class BambuImplementation {
|
|
|
475
483
|
remoteProjectPath,
|
|
476
484
|
};
|
|
477
485
|
}
|
|
478
|
-
//
|
|
486
|
+
// H2-series: fall through to project_file path below
|
|
479
487
|
}
|
|
480
488
|
const projectMetadata = await this.resolveProjectFileMetadata(options.filePath, options.plateIndex);
|
|
481
489
|
// Send project_file command via bambu-node MQTT (bypasses bambu-js
|
|
@@ -970,7 +978,7 @@ export class BambuImplementation {
|
|
|
970
978
|
* [16..16+payloadSize] JPEG (FF D8 ... FF D9)
|
|
971
979
|
*
|
|
972
980
|
* Verified models per upstream docs: A1, A1 mini, P1S, P1P. X1/X1C/X1E
|
|
973
|
-
* and P2S use RTSP on port 322 instead
|
|
981
|
+
* and P2S use RTSP on port 322 instead. H2/H2S/H2D/H2C
|
|
974
982
|
* are not documented; we fail fast rather than guess at the protocol.
|
|
975
983
|
*
|
|
976
984
|
* Read-only; no confirm gate. Default 8s timeout for cold-start latency.
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -46,8 +46,9 @@ const DEFAULT_BAMBU_MODEL =
|
|
|
46
46
|
const DEFAULT_BED_TYPE = process.env.BED_TYPE?.trim().toLowerCase() || "textured_plate";
|
|
47
47
|
const DEFAULT_NOZZLE_DIAMETER = process.env.NOZZLE_DIAMETER?.trim() || "0.4";
|
|
48
48
|
|
|
49
|
-
const VALID_BAMBU_MODELS = ["p1s", "p1p", "p2s", "x1c", "x1e", "a1", "a1mini", "h2d", "h2s"] as const;
|
|
49
|
+
const VALID_BAMBU_MODELS = ["p1s", "p1p", "p2s", "x1c", "x1e", "a1", "a1mini", "h2d", "h2s", "h2c"] as const;
|
|
50
50
|
type BambuModel = typeof VALID_BAMBU_MODELS[number];
|
|
51
|
+
const H2_BAMBU_MODELS = new Set<string>(["h2d", "h2s", "h2c"]);
|
|
51
52
|
|
|
52
53
|
const VALID_BED_TYPES = ["textured_plate", "cool_plate", "engineering_plate", "hot_plate", "supertack_plate"] as const;
|
|
53
54
|
const VALID_BAMBUSTUDIO_CLI_BED_TYPES = ["textured_plate", "cool_plate", "engineering_plate", "hot_plate"] as const;
|
|
@@ -63,6 +64,7 @@ const BAMBU_MODEL_PRESETS: Record<string, (nozzle: string) => string> = {
|
|
|
63
64
|
a1mini: (n) => `Bambu Lab A1 mini ${n} nozzle`,
|
|
64
65
|
h2d: (n) => `Bambu Lab H2D ${n} nozzle`,
|
|
65
66
|
h2s: (n) => `Bambu Lab H2S ${n} nozzle`,
|
|
67
|
+
h2c: (n) => `Bambu Lab H2C ${n} nozzle`,
|
|
66
68
|
};
|
|
67
69
|
|
|
68
70
|
const FILAMENT_PROFILE_DIR =
|
|
@@ -77,6 +79,7 @@ const FILAMENT_MODEL_CODES: Record<string, string> = {
|
|
|
77
79
|
a1mini: "A1M",
|
|
78
80
|
h2d: "H2D",
|
|
79
81
|
h2s: "H2S",
|
|
82
|
+
h2c: "H2C",
|
|
80
83
|
};
|
|
81
84
|
|
|
82
85
|
type FilamentProfileIndex = {
|
|
@@ -1078,6 +1081,7 @@ class BambuPrinterMCPServer {
|
|
|
1078
1081
|
{ const: "a1mini", title: "A1 Mini" },
|
|
1079
1082
|
{ const: "h2d", title: "H2D" },
|
|
1080
1083
|
{ const: "h2s", title: "H2S" },
|
|
1084
|
+
{ const: "h2c", title: "H2C" },
|
|
1081
1085
|
],
|
|
1082
1086
|
},
|
|
1083
1087
|
},
|
|
@@ -1776,7 +1780,7 @@ class BambuPrinterMCPServer {
|
|
|
1776
1780
|
},
|
|
1777
1781
|
bambu_model: {
|
|
1778
1782
|
type: "string",
|
|
1779
|
-
enum: [
|
|
1783
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
1780
1784
|
description: "Optional model hint used to resolve Bambu/Orca filament profile JSONs for each tray."
|
|
1781
1785
|
},
|
|
1782
1786
|
nozzle_diameter: {
|
|
@@ -1796,7 +1800,7 @@ class BambuPrinterMCPServer {
|
|
|
1796
1800
|
plate_index: { type: "number", description: "0-based plate index to inspect (default: 0)" },
|
|
1797
1801
|
bambu_model: {
|
|
1798
1802
|
type: "string",
|
|
1799
|
-
enum: [
|
|
1803
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
1800
1804
|
description: "Optional model hint used to resolve Bambu/Orca filament profile JSONs for each tray."
|
|
1801
1805
|
},
|
|
1802
1806
|
nozzle_diameter: { type: "string", description: "Nozzle diameter in mm (default: 0.4)" },
|
|
@@ -1937,7 +1941,7 @@ class BambuPrinterMCPServer {
|
|
|
1937
1941
|
template_dir: { type: "string", description: "Optional template directory override when resolving template_name." },
|
|
1938
1942
|
bambu_model: {
|
|
1939
1943
|
type: "string",
|
|
1940
|
-
enum: [
|
|
1944
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
1941
1945
|
description: "REQUIRED: Bambu Lab printer model. Ask the user if not known. Using the wrong model can damage the printer."
|
|
1942
1946
|
},
|
|
1943
1947
|
slicer_type: {
|
|
@@ -1983,7 +1987,7 @@ class BambuPrinterMCPServer {
|
|
|
1983
1987
|
stl_path: { type: "string", description: "Path to the STL or 3MF file to slice" },
|
|
1984
1988
|
bambu_model: {
|
|
1985
1989
|
type: "string",
|
|
1986
|
-
enum: [
|
|
1990
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
1987
1991
|
description: "REQUIRED: Bambu Lab printer model. Ask the user if not known. Using the wrong model can damage the printer."
|
|
1988
1992
|
},
|
|
1989
1993
|
slicer_type: {
|
|
@@ -2080,7 +2084,7 @@ class BambuPrinterMCPServer {
|
|
|
2080
2084
|
three_mf_path: { type: "string", description: "Path to the 3MF file to print; unsliced 3MFs are auto-sliced before sending." },
|
|
2081
2085
|
bambu_model: {
|
|
2082
2086
|
type: "string",
|
|
2083
|
-
enum: [
|
|
2087
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
2084
2088
|
description: "REQUIRED: Bambu Lab printer model. Ask the user if not known. Using the wrong model can damage the printer."
|
|
2085
2089
|
},
|
|
2086
2090
|
connection_type: { type: "string", enum: ["cloud", "lan"], description: "BambuNetwork connection type to put in FULU PrintParams; cloud uses restored internet printing, lan uses local bridge printing." },
|
|
@@ -2195,7 +2199,7 @@ class BambuPrinterMCPServer {
|
|
|
2195
2199
|
print: { type: "boolean", description: "Start printing after upload (default: false)" },
|
|
2196
2200
|
bambu_model: {
|
|
2197
2201
|
type: "string",
|
|
2198
|
-
enum: [
|
|
2202
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
2199
2203
|
description: "Required when print is true. Bambu Lab printer model used as a safety confirmation before starting the uploaded file."
|
|
2200
2204
|
},
|
|
2201
2205
|
host: { type: "string", description: "Hostname or IP of the printer (default: value from env)" },
|
|
@@ -2214,7 +2218,7 @@ class BambuPrinterMCPServer {
|
|
|
2214
2218
|
filename: { type: "string", description: "Name of the file to print" },
|
|
2215
2219
|
bambu_model: {
|
|
2216
2220
|
type: "string",
|
|
2217
|
-
enum: [
|
|
2221
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
2218
2222
|
description: "REQUIRED: Bambu Lab printer model. Ask the user if not known. Starting G-code for the wrong model can damage the printer."
|
|
2219
2223
|
},
|
|
2220
2224
|
host: { type: "string", description: "Hostname or IP of the printer (default: value from env)" },
|
|
@@ -2233,7 +2237,7 @@ class BambuPrinterMCPServer {
|
|
|
2233
2237
|
filename: { type: "string", description: "Name of the file to print" },
|
|
2234
2238
|
bambu_model: {
|
|
2235
2239
|
type: "string",
|
|
2236
|
-
enum: [
|
|
2240
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
2237
2241
|
description: "REQUIRED: Bambu Lab printer model. Ask the user if not known. Starting G-code for the wrong model can damage the printer."
|
|
2238
2242
|
},
|
|
2239
2243
|
host: { type: "string", description: "Hostname or IP of the printer (default: value from env)" },
|
|
@@ -2446,7 +2450,7 @@ class BambuPrinterMCPServer {
|
|
|
2446
2450
|
three_mf_path: { type: "string", description: "Path to the 3MF file to print" },
|
|
2447
2451
|
bambu_model: {
|
|
2448
2452
|
type: "string",
|
|
2449
|
-
enum: [
|
|
2453
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
2450
2454
|
description: "REQUIRED: Bambu Lab printer model. Ask the user if not known. Using the wrong model can damage the printer."
|
|
2451
2455
|
},
|
|
2452
2456
|
connection_mode: {
|
|
@@ -2516,8 +2520,8 @@ class BambuPrinterMCPServer {
|
|
|
2516
2520
|
template_dir: { type: "string", description: "Optional template directory override when resolving template_name." },
|
|
2517
2521
|
bambu_model: {
|
|
2518
2522
|
type: "string",
|
|
2519
|
-
enum: [
|
|
2520
|
-
description: "REQUIRED: Bambu Lab printer model. H2D and
|
|
2523
|
+
enum: [...VALID_BAMBU_MODELS],
|
|
2524
|
+
description: "REQUIRED: Bambu Lab printer model. H2D, H2S, and H2C are the primary intended paths."
|
|
2521
2525
|
},
|
|
2522
2526
|
host: { type: "string", description: "Hostname or IP of the printer (default: value from env)" },
|
|
2523
2527
|
bambu_serial: { type: "string", description: "Serial number (default: value from env)" },
|
|
@@ -3201,7 +3205,7 @@ class BambuPrinterMCPServer {
|
|
|
3201
3205
|
}
|
|
3202
3206
|
|
|
3203
3207
|
const parsed3MFData = await parse3MF(threeMFPath);
|
|
3204
|
-
const isH2Print = printModel
|
|
3208
|
+
const isH2Print = H2_BAMBU_MODELS.has(printModel);
|
|
3205
3209
|
let parsedAmsMapping: number[] | undefined;
|
|
3206
3210
|
if (!isH2Print && parsed3MFData.slicerConfig?.ams_mapping) {
|
|
3207
3211
|
const slots = normalizeAmsMappingObject(parsed3MFData.slicerConfig.ams_mapping as Record<string, unknown>);
|
|
@@ -3290,6 +3294,7 @@ class BambuPrinterMCPServer {
|
|
|
3290
3294
|
result = await this.bambu.print3mf(host, bambuSerial, bambuToken, {
|
|
3291
3295
|
projectName,
|
|
3292
3296
|
filePath: threeMFPath,
|
|
3297
|
+
bambuModel: printModel,
|
|
3293
3298
|
plateIndex,
|
|
3294
3299
|
useAMS: useAMS,
|
|
3295
3300
|
amsMapping: finalAmsMapping,
|
|
@@ -3353,6 +3358,7 @@ class BambuPrinterMCPServer {
|
|
|
3353
3358
|
result = await this.bambu.print3mf(host, bambuSerial, bambuToken, {
|
|
3354
3359
|
projectName,
|
|
3355
3360
|
filePath: preparedThreeMFPath,
|
|
3361
|
+
bambuModel: printModel,
|
|
3356
3362
|
plateIndex: collarAnalysis.plateIndex,
|
|
3357
3363
|
useAMS: true,
|
|
3358
3364
|
amsSlots: collarAnalysis.amsSlots,
|
package/src/printers/bambu.ts
CHANGED
|
@@ -42,6 +42,8 @@ const CLIENT_CREDS = loadClientCreds();
|
|
|
42
42
|
const COMMAND_SETTLE_MS = 300;
|
|
43
43
|
|
|
44
44
|
const MODEL_ID_TO_NAME: Record<string, string> = {
|
|
45
|
+
O1C: "H2C",
|
|
46
|
+
O1C2: "H2C",
|
|
45
47
|
O1D: "H2D",
|
|
46
48
|
O1E: "H2D Pro",
|
|
47
49
|
O1S: "H2S",
|
|
@@ -54,9 +56,16 @@ const MODEL_ID_TO_NAME: Record<string, string> = {
|
|
|
54
56
|
C13: "X1E",
|
|
55
57
|
};
|
|
56
58
|
|
|
59
|
+
const H2_MODEL_NAMES = new Set(["h2", "h2c", "h2d", "h2dpro", "h2d pro", "h2s"]);
|
|
60
|
+
|
|
61
|
+
function isH2ModelName(model: unknown): boolean {
|
|
62
|
+
return H2_MODEL_NAMES.has(String(model ?? "").trim().toLowerCase().replace(/\s+/g, " "));
|
|
63
|
+
}
|
|
64
|
+
|
|
57
65
|
interface BambuPrintOptionsInternal {
|
|
58
66
|
projectName: string;
|
|
59
67
|
filePath: string;
|
|
68
|
+
bambuModel?: string;
|
|
60
69
|
useAMS?: boolean;
|
|
61
70
|
plateIndex?: number;
|
|
62
71
|
bedType?: string;
|
|
@@ -128,7 +137,7 @@ class TolerantBambuClient extends BambuClient {
|
|
|
128
137
|
}
|
|
129
138
|
|
|
130
139
|
/**
|
|
131
|
-
*
|
|
140
|
+
* H2-series printers don't respond to get_version with module info.
|
|
132
141
|
* Infer model from serial number prefix so downstream code (Job, status
|
|
133
142
|
* parsing, etc.) has a valid printerModel instead of undefined.
|
|
134
143
|
*/
|
|
@@ -205,7 +214,7 @@ class TolerantBambuClient extends BambuClient {
|
|
|
205
214
|
reject(err);
|
|
206
215
|
});
|
|
207
216
|
});
|
|
208
|
-
//
|
|
217
|
+
// H2-series printers don't respond to get_version with module info.
|
|
209
218
|
// Infer model from serial number prefix so downstream code works.
|
|
210
219
|
if (!this.data.model) {
|
|
211
220
|
const inferred = this.inferModelFromSerial();
|
|
@@ -562,9 +571,12 @@ export class BambuImplementation {
|
|
|
562
571
|
let remoteFileName = path.basename(options.filePath);
|
|
563
572
|
remoteFileName = remoteFileName.replace(/\.gcode\.3mf\.gcode\.3mf$/i, ".gcode.3mf");
|
|
564
573
|
|
|
565
|
-
//
|
|
574
|
+
// H2-series printers land files at the FTP root and reference them via ftp:///<name>.
|
|
566
575
|
// P1/A1/X1 use /cache/<name> and file:///sdcard/cache/<name>.
|
|
567
|
-
const isH2 =
|
|
576
|
+
const isH2 =
|
|
577
|
+
serial.startsWith("093") ||
|
|
578
|
+
serial.startsWith("094") ||
|
|
579
|
+
isH2ModelName(options.bambuModel);
|
|
568
580
|
const remoteProjectPath = isH2 ? remoteFileName : `cache/${remoteFileName}`;
|
|
569
581
|
const remoteUploadPath = isH2 ? `/${remoteFileName}` : `/cache/${remoteFileName}`;
|
|
570
582
|
const projectUrl = isH2
|
|
@@ -577,7 +589,7 @@ export class BambuImplementation {
|
|
|
577
589
|
// Pre-sliced .gcode.3mf files: routing depends on firmware generation.
|
|
578
590
|
// P1/A1/X1 series: project_file returns 405004002 for .gcode.3mf (firmware
|
|
579
591
|
// doesn't recognise the container), so use gcode_file instead.
|
|
580
|
-
//
|
|
592
|
+
// H2-series: gcode_file is not supported; project_file works because the
|
|
581
593
|
// firmware can open the zip and find Metadata/plate_<n>.gcode directly.
|
|
582
594
|
if (options.filePath.toLowerCase().endsWith(".gcode.3mf")) {
|
|
583
595
|
if (!isH2) {
|
|
@@ -589,7 +601,7 @@ export class BambuImplementation {
|
|
|
589
601
|
remoteProjectPath,
|
|
590
602
|
};
|
|
591
603
|
}
|
|
592
|
-
//
|
|
604
|
+
// H2-series: fall through to project_file path below
|
|
593
605
|
}
|
|
594
606
|
|
|
595
607
|
const projectMetadata = await this.resolveProjectFileMetadata(
|
|
@@ -1210,7 +1222,7 @@ export class BambuImplementation {
|
|
|
1210
1222
|
* [16..16+payloadSize] JPEG (FF D8 ... FF D9)
|
|
1211
1223
|
*
|
|
1212
1224
|
* Verified models per upstream docs: A1, A1 mini, P1S, P1P. X1/X1C/X1E
|
|
1213
|
-
* and P2S use RTSP on port 322 instead
|
|
1225
|
+
* and P2S use RTSP on port 322 instead. H2/H2S/H2D/H2C
|
|
1214
1226
|
* are not documented; we fail fast rather than guess at the protocol.
|
|
1215
1227
|
*
|
|
1216
1228
|
* Read-only; no confirm gate. Default 8s timeout for cold-start latency.
|