bambu-printer-mcp 1.0.8 → 1.1.2

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.
@@ -9,8 +9,19 @@ import { promisify } from 'util';
9
9
  import { EventEmitter } from 'events';
10
10
  import * as crypto from 'crypto';
11
11
  import { execFile } from 'child_process';
12
+ import { flattenForCli, detectProfilesRoot } from '../slicer/profile-flatten.js';
12
13
  const readFileAsync = promisify(fs.readFile);
13
14
  const writeFileAsync = promisify(fs.writeFile);
15
+ const BAMBU_PROFILE_ROOTS = [
16
+ '/Applications/BambuStudio.app/Contents/Resources/profiles/BBL',
17
+ '/Applications/OrcaSlicer.app/Contents/Resources/profiles/BBL',
18
+ ];
19
+ const BAMBU_CLI_BED_TYPES = {
20
+ textured_plate: 'Textured PEI Plate',
21
+ cool_plate: 'Cool Plate',
22
+ engineering_plate: 'Engineering Plate',
23
+ hot_plate: 'High Temp Plate',
24
+ };
14
25
  export const SLICER_TYPES = [
15
26
  'bambustudio',
16
27
  'orcaslicer',
@@ -55,8 +66,13 @@ export function isBambuCompatibleSlicer(slicerType) {
55
66
  slicerType === 'orcaslicer' ||
56
67
  slicerType === 'orcaslicer-bambulab');
57
68
  }
58
- function isPathLikeExecutable(executable) {
59
- return path.isAbsolute(executable) || /[\\/]/.test(executable);
69
+ function isPathLikeExecutable(slicerPath) {
70
+ return (path.isAbsolute(slicerPath) ||
71
+ slicerPath.startsWith("./") ||
72
+ slicerPath.startsWith("../") ||
73
+ slicerPath.includes("/") ||
74
+ slicerPath.includes("\\") ||
75
+ /^[A-Za-z]:/.test(slicerPath));
60
76
  }
61
77
  function configuredBambuProfileDirs() {
62
78
  const override = process.env.BAMBU_SLICER_PROFILE_DIRS;
@@ -82,28 +98,7 @@ function configuredBambuProfileDirs() {
82
98
  ...(appData ? [appData] : []),
83
99
  ...(localAppData ? [localAppData] : []),
84
100
  ];
85
- return roots.flatMap((root) => appNames.map((appName) => path.join(root, appName, 'system', 'BBL', 'machine')));
86
- }
87
- function resolveBambuPrinterProfile(printerPreset) {
88
- if (printerPreset.includes('/') || printerPreset.includes('\\')) {
89
- return undefined;
90
- }
91
- for (const profileDir of configuredBambuProfileDirs()) {
92
- const profilePath = path.join(profileDir, `${printerPreset}.json`);
93
- if (fs.existsSync(profilePath)) {
94
- return profilePath;
95
- }
96
- }
97
- return undefined;
98
- }
99
- function generatedBambuPrinterSettings(printerPreset) {
100
- return {
101
- type: 'machine',
102
- from: 'system',
103
- name: printerPreset,
104
- inherits: printerPreset,
105
- printer_settings_id: printerPreset,
106
- };
101
+ return roots.flatMap((root) => appNames.map((appName) => path.join(root, appName, 'system', 'BBL')));
107
102
  }
108
103
  export class STLManipulator extends EventEmitter {
109
104
  constructor(tempDir = path.join(process.cwd(), 'temp')) {
@@ -121,6 +116,266 @@ export class STLManipulator extends EventEmitter {
121
116
  generateOperationId() {
122
117
  return crypto.randomUUID();
123
118
  }
119
+ getAvailableProfileRoots() {
120
+ return [...BAMBU_PROFILE_ROOTS, ...configuredBambuProfileDirs()].filter((root) => fs.existsSync(root));
121
+ }
122
+ findProfileFile(category, profileName) {
123
+ if (!profileName) {
124
+ return undefined;
125
+ }
126
+ for (const root of this.getAvailableProfileRoots()) {
127
+ const candidate = path.join(root, category, `${profileName}.json`);
128
+ if (fs.existsSync(candidate)) {
129
+ return candidate;
130
+ }
131
+ }
132
+ return undefined;
133
+ }
134
+ buildFilamentIdIndex() {
135
+ const index = new Map();
136
+ for (const root of this.getAvailableProfileRoots()) {
137
+ const filamentDir = path.join(root, 'filament');
138
+ if (!fs.existsSync(filamentDir)) {
139
+ continue;
140
+ }
141
+ for (const entry of fs.readdirSync(filamentDir)) {
142
+ if (!entry.endsWith('.json')) {
143
+ continue;
144
+ }
145
+ const filePath = path.join(filamentDir, entry);
146
+ try {
147
+ const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
148
+ const filamentId = typeof parsed?.filament_id === 'string' ? parsed.filament_id.trim() : '';
149
+ if (filamentId && !index.has(filamentId)) {
150
+ index.set(filamentId, filePath);
151
+ }
152
+ }
153
+ catch {
154
+ // Ignore malformed JSON.
155
+ }
156
+ }
157
+ }
158
+ return index;
159
+ }
160
+ readJsonFile(filePath) {
161
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
162
+ }
163
+ stripAbsoluteExtruderResets(value) {
164
+ if (typeof value === 'string') {
165
+ return value
166
+ .split(/\r?\n/)
167
+ .filter((line) => line.trim().toUpperCase() !== 'G92 E0')
168
+ .join('\n');
169
+ }
170
+ if (Array.isArray(value)) {
171
+ return value.filter((line) => String(line).trim().toUpperCase() !== 'G92 E0');
172
+ }
173
+ return value;
174
+ }
175
+ sanitizeProcessForOrca(processConfig, printerPreset) {
176
+ const sanitized = { ...processConfig };
177
+ sanitized.type = 'process';
178
+ if (!sanitized.from || sanitized.from === 'project') {
179
+ sanitized.from = 'User';
180
+ }
181
+ if (printerPreset) {
182
+ sanitized.compatible_printers = [printerPreset];
183
+ }
184
+ if (sanitized.prime_tower_brim_width !== undefined &&
185
+ Number(sanitized.prime_tower_brim_width) < 0) {
186
+ sanitized.prime_tower_brim_width = '0';
187
+ }
188
+ else if (sanitized.prime_tower_brim_width !== undefined) {
189
+ sanitized.prime_tower_brim_width = String(sanitized.prime_tower_brim_width);
190
+ }
191
+ sanitized.use_relative_e_distances = '0';
192
+ sanitized.before_layer_change_gcode = this.stripAbsoluteExtruderResets(sanitized.before_layer_change_gcode);
193
+ sanitized.layer_gcode = this.stripAbsoluteExtruderResets(sanitized.layer_gcode);
194
+ sanitized.layer_change_gcode = this.stripAbsoluteExtruderResets(sanitized.layer_change_gcode);
195
+ return sanitized;
196
+ }
197
+ writeTempJson(outputBase, suffix, value) {
198
+ const outPath = path.join(this.tempDir, `${outputBase}_${suffix}.json`);
199
+ fs.writeFileSync(outPath, JSON.stringify(value, null, 2));
200
+ return outPath;
201
+ }
202
+ resolveBambuLikeSettingsBundle(outputBase, slicerType, slicerProfile, printerPreset, bambuOptions) {
203
+ const machinePath = this.findProfileFile('machine', printerPreset);
204
+ const machineConfig = machinePath ? this.readJsonFile(machinePath) : null;
205
+ const hasSlicerProfile = !!slicerProfile && fs.existsSync(slicerProfile);
206
+ const filamentPaths = [];
207
+ let processPath;
208
+ let parsedProfile = null;
209
+ if (hasSlicerProfile) {
210
+ try {
211
+ parsedProfile = this.readJsonFile(slicerProfile);
212
+ }
213
+ catch {
214
+ parsedProfile = null;
215
+ }
216
+ }
217
+ if (parsedProfile && typeof parsedProfile === 'object') {
218
+ const inheritedProcessName = (typeof parsedProfile.inherits === 'string' && parsedProfile.inherits) ||
219
+ (typeof parsedProfile.print_settings_id === 'string' &&
220
+ parsedProfile.print_settings_id !== parsedProfile.name
221
+ ? parsedProfile.print_settings_id
222
+ : undefined) ||
223
+ (typeof parsedProfile.default_print_profile === 'string'
224
+ ? parsedProfile.default_print_profile
225
+ : undefined) ||
226
+ (typeof machineConfig?.default_print_profile === 'string'
227
+ ? machineConfig.default_print_profile
228
+ : undefined);
229
+ const inheritedProcessPath = this.findProfileFile('process', inheritedProcessName);
230
+ const inheritedProcess = inheritedProcessPath && fs.existsSync(inheritedProcessPath)
231
+ ? this.readJsonFile(inheritedProcessPath)
232
+ : {};
233
+ const mergedProcess = {
234
+ ...inheritedProcess,
235
+ ...parsedProfile,
236
+ type: 'process',
237
+ };
238
+ processPath = this.writeTempJson(outputBase, slicerType === 'orcaslicer' ? 'process_orca' : 'process', slicerType === 'orcaslicer'
239
+ ? this.sanitizeProcessForOrca(mergedProcess, printerPreset)
240
+ : mergedProcess);
241
+ const defaultFilamentProfiles = Array.isArray(parsedProfile.default_filament_profile)
242
+ ? parsedProfile.default_filament_profile
243
+ : [];
244
+ for (const profileName of defaultFilamentProfiles) {
245
+ const filamentPath = this.findProfileFile('filament', String(profileName));
246
+ if (filamentPath) {
247
+ filamentPaths.push(filamentPath);
248
+ }
249
+ }
250
+ if (filamentPaths.length === 0 && Array.isArray(parsedProfile.filament_ids)) {
251
+ const filamentIdIndex = this.buildFilamentIdIndex();
252
+ for (const filamentId of parsedProfile.filament_ids) {
253
+ const filamentPath = filamentIdIndex.get(String(filamentId));
254
+ if (filamentPath) {
255
+ filamentPaths.push(filamentPath);
256
+ }
257
+ }
258
+ }
259
+ }
260
+ else if (hasSlicerProfile) {
261
+ processPath = slicerProfile;
262
+ }
263
+ if (!processPath) {
264
+ const defaultProcessName = typeof machineConfig?.default_print_profile === 'string'
265
+ ? machineConfig.default_print_profile
266
+ : undefined;
267
+ const defaultProcessPath = this.findProfileFile('process', defaultProcessName);
268
+ if (defaultProcessPath) {
269
+ processPath =
270
+ slicerType === 'orcaslicer'
271
+ ? this.writeTempJson(outputBase, 'process_default_orca', this.sanitizeProcessForOrca(this.readJsonFile(defaultProcessPath), printerPreset))
272
+ : defaultProcessPath;
273
+ }
274
+ }
275
+ if (!bambuOptions?.loadFilaments &&
276
+ filamentPaths.length === 0 &&
277
+ Array.isArray(machineConfig?.default_filament_profile)) {
278
+ for (const profileName of machineConfig.default_filament_profile) {
279
+ const filamentPath = this.findProfileFile('filament', String(profileName));
280
+ if (filamentPath) {
281
+ filamentPaths.push(filamentPath);
282
+ }
283
+ }
284
+ }
285
+ if (bambuOptions?.loadFilaments) {
286
+ filamentPaths.length = 0;
287
+ for (const filamentPath of bambuOptions.loadFilaments.split(';')) {
288
+ const trimmed = filamentPath.trim();
289
+ if (trimmed) {
290
+ filamentPaths.push(trimmed);
291
+ }
292
+ }
293
+ }
294
+ const settingsParts = [machinePath, processPath].filter((entry) => Boolean(entry));
295
+ return {
296
+ settingsArg: settingsParts.length > 0 ? settingsParts.join(';') : undefined,
297
+ filamentPaths: Array.from(new Set(filamentPaths)),
298
+ };
299
+ }
300
+ /**
301
+ * Optionally rewrite a Bambu-like settings bundle so the paths point at
302
+ * fully-flattened temp configs instead of the BBL-shipped leaf JSONs.
303
+ *
304
+ * BambuStudio's CLI does not resolve the `inherits` chain when loading
305
+ * profiles via --load-settings / --load-filaments, which causes a
306
+ * cluster of upstream bugs (see https://github.com/bambulab/BambuStudio/issues/9636
307
+ * and #9968). Our flattener (src/slicer/profile-flatten.ts) reproduces
308
+ * what the GUI does at slice time so the CLI accepts the configs.
309
+ *
310
+ * Opt-in via `BAMBU_CLI_FLATTEN=true`. When the env var is unset or
311
+ * not "true"/"1", returns the bundle unchanged so behavior is
312
+ * backward-compatible. When enabled, only BBL-shipped leaves get
313
+ * flattened; user-provided custom configs pass through untouched.
314
+ */
315
+ async maybeFlattenBundle(bundle, bambuOptions, activeSlicerPath) {
316
+ const flag = process.env.BAMBU_CLI_FLATTEN;
317
+ if (flag !== 'true' && flag !== '1')
318
+ return bundle;
319
+ if (!bundle.settingsArg)
320
+ return bundle;
321
+ // settingsArg is "machine.json;process.json".
322
+ const parts = bundle.settingsArg.split(';').filter(Boolean);
323
+ if (parts.length < 2)
324
+ return bundle;
325
+ const [machinePath, processPath] = parts;
326
+ // Pull leaf names from each JSON's `name` field. If any is missing or
327
+ // looks non-BBL (e.g. a user-saved custom config), bail out and
328
+ // return the original bundle untouched.
329
+ const machineLeaf = this.readLeafName(machinePath);
330
+ const processLeaf = this.readLeafName(processPath);
331
+ const filamentLeaves = bundle.filamentPaths
332
+ .map((p) => this.readLeafName(p))
333
+ .filter((n) => Boolean(n));
334
+ if (!machineLeaf || !processLeaf || filamentLeaves.length === 0) {
335
+ console.log('[cli-flatten] skipping: could not derive BBL leaf names from bundle paths');
336
+ return bundle;
337
+ }
338
+ const bedType = this.resolveBambuStudioBedType(bambuOptions?.bedType);
339
+ try {
340
+ const profilesRoot = detectProfilesRoot(activeSlicerPath || process.env.SLICER_PATH);
341
+ const flat = await flattenForCli({
342
+ machineLeaf,
343
+ processLeaf,
344
+ filamentLeaves,
345
+ profilesRoot,
346
+ tempDir: this.tempDir,
347
+ bedType,
348
+ });
349
+ console.log(`[cli-flatten] applied for ${machineLeaf} (cliOverlay=${flat.meta.cliOverlayApplied})`);
350
+ return {
351
+ settingsArg: `${flat.machinePath};${flat.processPath}`,
352
+ filamentPaths: flat.filamentPaths,
353
+ };
354
+ }
355
+ catch (err) {
356
+ console.error(`[cli-flatten] failed, falling back to unflattened bundle: ${err?.message ?? err}`);
357
+ return bundle;
358
+ }
359
+ }
360
+ resolveBambuStudioBedType(bedType) {
361
+ if (!bedType)
362
+ return undefined;
363
+ const normalized = bedType.trim().toLowerCase();
364
+ if (normalized === 'supertack_plate') {
365
+ throw new Error('BambuStudio CLI SuperTack bed type is not verified; use a pre-sliced 3MF or choose textured_plate, cool_plate, engineering_plate, or hot_plate.');
366
+ }
367
+ return BAMBU_CLI_BED_TYPES[normalized] || bedType;
368
+ }
369
+ /** Read a profile JSON's top-level `name` field, or null if unreadable. */
370
+ readLeafName(filePath) {
371
+ try {
372
+ const data = this.readJsonFile(filePath);
373
+ return typeof data?.name === 'string' && data.name.length > 0 ? data.name : null;
374
+ }
375
+ catch {
376
+ return null;
377
+ }
378
+ }
124
379
  /**
125
380
  * Load STL file and return geometry and bounding box
126
381
  */
@@ -828,12 +1083,12 @@ export class STLManipulator extends EventEmitter {
828
1083
  /**
829
1084
  * Slice an STL or 3MF file using the specified slicer
830
1085
  * @param stlFilePath Path to the input STL or 3MF file
831
- * @param slicerType Type of slicer (prusaslicer, cura, slic3r, orcaslicer, orcaslicer-bambulab, bambustudio)
1086
+ * @param slicerType Type of slicer (prusaslicer, cura, slic3r, orcaslicer, bambustudio)
832
1087
  * @param slicerPath Path to the slicer executable
833
1088
  * @param slicerProfile Optional path to the slicer profile/config file
834
1089
  * @param progressCallback Optional callback for progress updates
835
- * @param printerPreset Optional Bambu-compatible printer preset name (e.g., "Bambu Lab P1S 0.4 nozzle")
836
- * @param bambuOptions Optional Bambu-compatible CLI flags
1090
+ * @param printerPreset Optional BambuStudio printer preset name (e.g., "Bambu Lab P1S 0.4 nozzle")
1091
+ * @param bambuOptions Optional BambuStudio-specific CLI flags
837
1092
  * @returns Path to the generated G-code or sliced 3MF file
838
1093
  */
839
1094
  async sliceSTL(stlFilePath, slicerType, slicerPath, slicerProfile, progressCallback, printerPreset, bambuOptions) {
@@ -882,40 +1137,31 @@ export class STLManipulator extends EventEmitter {
882
1137
  case 'orcaslicer':
883
1138
  case 'orcaslicer-bambulab':
884
1139
  // Bambu-compatible CLI: slice and export as 3MF with embedded gcode.
885
- // FULU's OrcaSlicer-bambulab fork keeps OrcaSlicer's Bambu-style
886
- // --slice/--export-3mf path, so it must not use the generic Prusa
887
- // --output G-code flow.
1140
+ // FULU's OrcaSlicer-bambulab fork keeps this Bambu-style path.
888
1141
  // For 3MF input: slice in place and export sliced 3MF
889
1142
  // For STL input: slice and export as 3MF
890
1143
  {
891
1144
  const is3mf = stlFilePath.toLowerCase().endsWith('.3mf');
892
1145
  const outputBase = path.basename(stlFilePath, is3mf ? '.3mf' : '.stl');
893
1146
  const bambuOutputPath = path.join(this.tempDir, outputBase + '_sliced.3mf');
1147
+ const outputDir = path.dirname(bambuOutputPath);
1148
+ const rawBundle = this.resolveBambuLikeSettingsBundle(outputBase, slicerType, slicerProfile, printerPreset, bambuOptions);
1149
+ // Opt-in flatten step: walks the BBL `inherits` chain so the
1150
+ // CLI accepts what we hand it. See maybeFlattenBundle docstring.
1151
+ const settingsBundle = slicerType === 'bambustudio'
1152
+ ? await this.maybeFlattenBundle(rawBundle, bambuOptions, slicerPath)
1153
+ : rawBundle;
894
1154
  args = [
895
1155
  '--slice', String(bambuOptions?.slicePlate ?? 0),
896
- '--export-3mf', bambuOutputPath,
1156
+ '--outputdir', outputDir,
1157
+ '--export-3mf', path.basename(bambuOutputPath),
897
1158
  ];
898
- if (slicerProfile) {
899
- args.push('--load-settings', slicerProfile);
1159
+ if (settingsBundle.settingsArg) {
1160
+ args.push('--load-settings', settingsBundle.settingsArg);
900
1161
  }
901
1162
  // Always allow newer-version 3MF files (the CLI rejects them by default)
902
1163
  args.push('--allow-newer-file');
903
- // If a printer preset name is given AND no explicit profile was provided,
904
- // prefer the slicer's installed machine profile. Real BambuStudio rejects
905
- // skeletal JSON without profile metadata, so only fall back to generated
906
- // settings when no installed profile can be found.
907
- if (printerPreset && !slicerProfile) {
908
- const installedProfile = resolveBambuPrinterProfile(printerPreset);
909
- if (installedProfile) {
910
- args.push('--load-settings', installedProfile);
911
- }
912
- else {
913
- const presetJson = path.join(this.tempDir, '_printer_preset.json');
914
- fs.writeFileSync(presetJson, JSON.stringify(generatedBambuPrinterSettings(printerPreset), null, 2));
915
- args.push('--load-settings', presetJson);
916
- }
917
- }
918
- // Bambu-compatible slicer flags
1164
+ // BambuSliceOptions flags
919
1165
  if (bambuOptions?.uptodate)
920
1166
  args.push('--uptodate');
921
1167
  if (bambuOptions?.ensureOnBed)
@@ -946,12 +1192,14 @@ export class STLManipulator extends EventEmitter {
946
1192
  args.push('--clone-objects', bambuOptions.cloneObjects);
947
1193
  if (bambuOptions?.skipObjects)
948
1194
  args.push('--skip-objects', bambuOptions.skipObjects);
949
- if (bambuOptions?.loadFilaments)
950
- args.push('--load-filaments', bambuOptions.loadFilaments);
1195
+ if (settingsBundle.filamentPaths.length > 0) {
1196
+ args.push('--load-filaments', settingsBundle.filamentPaths.join(';'));
1197
+ args.push('--load-defaultfila');
1198
+ }
951
1199
  if (bambuOptions?.loadFilamentIds)
952
1200
  args.push('--load-filament-ids', bambuOptions.loadFilamentIds);
953
1201
  args.push(stlFilePath);
954
- // Override outputFilePath because Bambu-compatible slicers produce 3MF, not G-code.
1202
+ // Override outputFilePath for bambustudio since it produces 3MF, not gcode
955
1203
  outputFilePath = bambuOutputPath;
956
1204
  }
957
1205
  break;
package/dist/types.d.ts CHANGED
@@ -55,3 +55,38 @@ export interface ThreeMFData {
55
55
  };
56
56
  slicerConfig?: Partial<BambuSlicerConfig>;
57
57
  }
58
+ export interface CollarCharmRole {
59
+ role: 'inner' | 'outer';
60
+ objectIndex: number;
61
+ name: string;
62
+ area: number;
63
+ filamentPosition: number;
64
+ }
65
+ export interface CollarCharmAnalysis {
66
+ plateIndex: number;
67
+ usedFilamentPositions: number[];
68
+ amsSlots: number[];
69
+ roles: CollarCharmRole[];
70
+ }
71
+ export interface ThreeMFFilamentRequirement {
72
+ filamentPosition: number;
73
+ filamentId: number;
74
+ tray_info_idx: string | null;
75
+ type: string | null;
76
+ color: string | null;
77
+ }
78
+ export interface ThreeMFAmsRequirements {
79
+ plateIndex: number;
80
+ usedFilamentPositions: number[];
81
+ filaments: ThreeMFFilamentRequirement[];
82
+ }
83
+ export interface ThreeMFPlateObject {
84
+ id: number;
85
+ name: string;
86
+ area: number | null;
87
+ bbox: unknown;
88
+ }
89
+ export interface ThreeMFPlateObjects {
90
+ plateIndex: number;
91
+ objects: ThreeMFPlateObject[];
92
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bambu-printer-mcp",
3
- "version": "1.0.8",
3
+ "version": "1.1.2",
4
4
  "description": "MCP server for Bambu Lab 3D printers with STL manipulation, slicing, and print management",
5
5
  "main": "dist/index.js",
6
6
  "repository": {
@@ -13,7 +13,8 @@
13
13
  "start:stdio": "MCP_TRANSPORT=stdio node dist/index.js",
14
14
  "start:http": "MCP_TRANSPORT=streamable-http node dist/index.js",
15
15
  "build": "tsc",
16
- "test": "npm run build && node --test tests/**/*.test.mjs"
16
+ "test": "npm run build && node --test tests/*.test.mjs tests/**/*.test.mjs",
17
+ "postinstall": "patch-package"
17
18
  },
18
19
  "bin": {
19
20
  "bambu-printer-mcp": "dist/index.js"
@@ -21,6 +22,7 @@
21
22
  "files": [
22
23
  "dist",
23
24
  "src",
25
+ "patches",
24
26
  "README.md",
25
27
  "LICENSE"
26
28
  ],
@@ -42,12 +44,15 @@
42
44
  "basic-ftp": "^5.0.5",
43
45
  "dotenv": "^16.3.1",
44
46
  "jszip": "^3.10.1",
47
+ "mqtt": "^5.15.1",
48
+ "patch-package": "^8.0.1",
45
49
  "three": "^0.173.0",
46
50
  "xml2js": "^0.6.2"
47
51
  },
48
52
  "devDependencies": {
49
53
  "@types/node": "^18.0.0",
50
54
  "@types/three": "^0.173.0",
51
- "@types/xml2js": "^0.4.14"
55
+ "@types/xml2js": "^0.4.14",
56
+ "typescript": "^6.0.3"
52
57
  }
53
58
  }
@@ -0,0 +1,16 @@
1
+ diff --git a/node_modules/bambu-node/dist/index.js b/node_modules/bambu-node/dist/index.js
2
+ index 916e924..6cc3f33 100644
3
+ --- a/node_modules/bambu-node/dist/index.js
4
+ +++ b/node_modules/bambu-node/dist/index.js
5
+ @@ -1,4 +1,4 @@
6
+ -var B=Object.defineProperty;var he=(e,_,t)=>_ in e?B(e,_,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[_]=t;var r=(e,_)=>B(e,"name",{value:_,configurable:!0});var n=(e,_,t)=>(he(e,typeof _!="symbol"?_+"":_,t),t);var U=0;function H(){return U+=1,U}r(H,"getSequenceId");var v=class v{constructor(_={}){n(this,"extra");this.extra=_}invoke(_){return _.publish({[this.category]:{sequence_id:H(),command:this.command,...this.extra}})}};r(v,"AbstractCommand");var f=v;var A=class A extends f{constructor(t){super({param:t.join(`
7
+ +var B=Object.defineProperty;var he=(e,_,t)=>_ in e?B(e,_,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[_]=t;var r=(e,_)=>B(e,"name",{value:_,configurable:!0});var n=(e,_,t)=>(he(e,typeof _!="symbol"?_+"":_,t),t);var U=0;function H(){return String(U+=1)}r(H,"getSequenceId");var v=class v{constructor(_={}){n(this,"extra");this.extra=_}invoke(_){return _.publish({[this.category]:{sequence_id:H(),command:this.command,...this.extra}})}};r(v,"AbstractCommand");var f=v;var A=class A extends f{constructor(t){super({param:t.join(`
8
+ `)+`
9
+ `});n(this,"category","print")}};r(A,"GCodeCommand");var d=A;function y(e){return!!e?.print&&!!e?.print?.command&&["push_status","resume","gcode_line","gcode_file","project_file"].includes(e.print.command)}r(y,"isPrintMessage");function q(e){return e.command==="gcode_file"}r(q,"isGcodeFileCommand");function j(e){return e.command==="gcode_line"}r(j,"isGCodeLineCommand");function Oe(e){return e.command==="project_file"}r(Oe,"isProjectFileCommand");function J(e){return e.command==="push_status"&&Object.keys(e).length<40}r(J,"isPushStatusCommand");var k={GFB00:{type:"filament",name:"Bambu ABS @base",inherits:"fdm_filament_abs",from:"system",instantiation:"false",activate_air_filtration:["1"],cool_plate_temp:["0"],cool_plate_temp_initial_layer:["0"],eng_plate_temp:["90"],eng_plate_temp_initial_layer:["90"],fan_cooling_layer_time:["30"],fan_max_speed:["80"],fan_min_speed:["10"],filament_cost:["24.99"],filament_density:["1.04"],filament_max_volumetric_speed:["28.6"],filament_type:["ABS"],hot_plate_temp:["90"],hot_plate_temp_initial_layer:["90"],nozzle_temperature:["270"],nozzle_temperature_initial_layer:["260"],nozzle_temperature_range_high:["280"],nozzle_temperature_range_low:["240"],overhang_fan_speed:["80"],overhang_fan_threshold:["25%"],reduce_fan_stop_start_freq:["1"],slow_down_layer_time:["3"],slow_down_min_speed:["20"],textured_plate_temp:["90"],textured_plate_temp_initial_layer:["90"],filament_id:"GFB00",filament_flow_ratio:["0.95"],filament_vendor:["Bambu Lab"]},GFB01:{type:"filament",name:"Bambu ASA @base",inherits:"fdm_filament_asa",from:"system",instantiation:"false",activate_air_filtration:["1"],cool_plate_temp:["0"],cool_plate_temp_initial_layer:["0"],eng_plate_temp:["90"],eng_plate_temp_initial_layer:["90"],fan_cooling_layer_time:["35"],fan_max_speed:["35"],fan_min_speed:["10"],filament_cost:["31.99"],filament_density:["1.05"],filament_max_volumetric_speed:["18"],filament_type:["ASA"],hot_plate_temp:["90"],hot_plate_temp_initial_layer:["90"],nozzle_temperature:["270"],nozzle_temperature_initial_layer:["270"],nozzle_temperature_range_high:["280"],nozzle_temperature_range_low:["240"],overhang_fan_speed:["80"],overhang_fan_threshold:["25%"],reduce_fan_stop_start_freq:["1"],slow_down_layer_time:["12"],slow_down_min_speed:["20"],textured_plate_temp:["90"],textured_plate_temp_initial_layer:["90"],filament_id:"GFB01",filament_flow_ratio:["0.95"],filament_vendor:["Bambu Lab"]},GFN03:{type:"filament",name:"Bambu PA-CF @base",inherits:"fdm_filament_pa",from:"system",instantiation:"false",activate_air_filtration:["1"],cool_plate_temp:["0"],cool_plate_temp_initial_layer:["0"],eng_plate_temp:["100"],eng_plate_temp_initial_layer:["100"],fan_cooling_layer_time:["4"],fan_max_speed:["60"],fan_min_speed:["0"],filament_cost:["84.99"],filament_density:["1.09"],filament_max_volumetric_speed:["8"],filament_type:["PA-CF"],hot_plate_temp:["100"],hot_plate_temp_initial_layer:["100"],nozzle_temperature:["280"],nozzle_temperature_initial_layer:["280"],nozzle_temperature_range_high:["300"],nozzle_temperature_range_low:["260"],overhang_fan_speed:["40"],required_nozzle_HRC:["40"],slow_down_layer_time:["2"],slow_down_min_speed:["20"],temperature_vitrification:["170"],textured_plate_temp:["100"],textured_plate_temp_initial_layer:["100"],filament_id:"GFN03",filament_flow_ratio:["0.96"],filament_vendor:["Bambu Lab"],overhang_fan_threshold:["0%"]},GFN05:{type:"filament",name:"Bambu PA6-CF @base",inherits:"fdm_filament_pa",from:"system",instantiation:"false",activate_air_filtration:["1"],cool_plate_temp:["0"],cool_plate_temp_initial_layer:["0"],eng_plate_temp:["100"],eng_plate_temp_initial_layer:["100"],fan_cooling_layer_time:["5"],fan_max_speed:["30"],fan_min_speed:["10"],filament_cost:["79.99"],filament_density:["1.10"],filament_max_volumetric_speed:["8"],filament_type:["PA6-CF"],hot_plate_temp:["100"],hot_plate_temp_initial_layer:["100"],nozzle_temperature:["275"],nozzle_temperature_initial_layer:["275"],nozzle_temperature_range_high:["300"],nozzle_temperature_range_low:["260"],overhang_fan_speed:["40"],required_nozzle_HRC:["40"],slow_down_layer_time:["2"],slow_down_min_speed:["20"],temperature_vitrification:["170"],textured_plate_temp:["100"],textured_plate_temp_initial_layer:["100"],filament_id:"GFN05",filament_flow_ratio:["0.96"],filament_vendor:["Bambu Lab"],overhang_fan_threshold:["0%"]},GFN08:{type:"filament",name:"Bambu PA6-GF @base",inherits:"fdm_filament_pa",from:"system",instantiation:"false",activate_air_filtration:["1"],cool_plate_temp:["0"],cool_plate_temp_initial_layer:["0"],eng_plate_temp:["100"],eng_plate_temp_initial_layer:["100"],fan_cooling_layer_time:["5"],fan_max_speed:["30"],fan_min_speed:["10"],filament_cost:["59.99"],filament_density:["1.14"],filament_max_volumetric_speed:["8"],filament_type:["PA-GF"],hot_plate_temp:["100"],hot_plate_temp_initial_layer:["100"],nozzle_temperature:["290"],nozzle_temperature_initial_layer:["290"],nozzle_temperature_range_high:["300"],nozzle_temperature_range_low:["260"],overhang_fan_speed:["40"],required_nozzle_HRC:["40"],slow_down_layer_time:["2"],slow_down_min_speed:["20"],temperature_vitrification:["180"],textured_plate_temp:["100"],textured_plate_temp_initial_layer:["100"],filament_id:"GFN08",filament_flow_ratio:["0.96"],filament_vendor:["Bambu Lab"],full_fan_speed_layer:["2"],overhang_fan_threshold:["0%"]},GFN04:{type:"filament",name:"Bambu PAHT-CF @base",inherits:"fdm_filament_pa",from:"system",instantiation:"false",activate_air_filtration:["1"],cool_plate_temp:["0"],cool_plate_temp_initial_layer:["0"],eng_plate_temp:["100"],eng_plate_temp_initial_layer:["100"],fan_cooling_layer_time:["5"],fan_max_speed:["30"],fan_min_speed:["10"],filament_cost:["94.99"],filament_density:["1.06"],filament_max_volumetric_speed:["8"],filament_type:["PA-CF"],hot_plate_temp:["100"],hot_plate_temp_initial_layer:["100"],nozzle_temperature:["290"],nozzle_temperature_initial_layer:["290"],nozzle_temperature_range_high:["300"],nozzle_temperature_range_low:["260"],overhang_fan_speed:["40"],required_nozzle_HRC:["40"],slow_down_layer_time:["2"],slow_down_min_speed:["20"],temperature_vitrification:["180"],textured_plate_temp:["100"],textured_plate_temp_initial_layer:["100"],filament_id:"GFN04",full_fan_speed_layer:["2"],filament_vendor:["Bambu Lab"],filament_flow_ratio:["0.96"],overhang_fan_threshold:["0%"]},GFC00:{type:"filament",name:"Bambu PC @base",inherits:"fdm_filament_pc",from:"system",instantiation:"false",cool_plate_temp:["0"],cool_plate_temp_initial_layer:["0"],eng_plate_temp:["110"],eng_plate_temp_initial_layer:["110"],fan_cooling_layer_time:["30"],fan_max_speed:["60"],fan_min_speed:["10"],filament_cost:["39.99"],filament_density:["1.04"],filament_max_volumetric_speed:["18"],filament_type:["PC"],hot_plate_temp:["110"],hot_plate_temp_initial_layer:["110"],nozzle_temperature:["280"],nozzle_temperature_initial_layer:["270"],nozzle_temperature_range_high:["290"],nozzle_temperature_range_low:["260"],overhang_fan_speed:["60"],overhang_fan_threshold:["25%"],reduce_fan_stop_start_freq:["1"],slow_down_layer_time:["2"],slow_down_min_speed:["20"],temperature_vitrification:["120"],textured_plate_temp:["110"],textured_plate_temp_initial_layer:["110"],filament_id:"GFC00",filament_vendor:["Bambu Lab"],filament_flow_ratio:["0.94"]},GFT01:{type:"filament",name:"Bambu PET-CF @base",inherits:"fdm_filament_pet",from:"system",instantiation:"false",eng_plate_temp:["80"],eng_plate_temp_initial_layer:["80"],fan_cooling_layer_time:["5"],fan_min_speed:["10"],filament_cost:["84.99"],filament_density:["1.29"],filament_max_volumetric_speed:["8"],filament_type:["PET-CF"],hot_plate_temp:["100"],hot_plate_temp_initial_layer:["100"],nozzle_temperature:["270"],nozzle_temperature_initial_layer:["270"],nozzle_temperature_range_high:["290"],nozzle_temperature_range_low:["260"],reduce_fan_stop_start_freq:["1"],temperature_vitrification:["185"],textured_plate_temp:["100"],textured_plate_temp_initial_layer:["100"],filament_start_gcode:[`; filament start gcode
10
+ {if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255
11
+ @@ -330,4 +330,4 @@ M106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]}
12
+
13
+ {if activate_air_filtration[current_extruder] && support_air_filtration}
14
+ M106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]}
15
+ -{endif}`],filament_id:"GFL01",filament_flow_ratio:["0.98"],filament_vendor:["Polymaker"]}};var W;(function(e){e[e.PRINTING=0]="PRINTING",e[e.BED_LEVELING=1]="BED_LEVELING",e[e.HEATBED_PREHEATING=2]="HEATBED_PREHEATING",e[e.XY_MECH_MODE_SWEEP=3]="XY_MECH_MODE_SWEEP",e[e.CHANGE_MATERIAL=4]="CHANGE_MATERIAL",e[e.M400_PAUSE=5]="M400_PAUSE",e[e.FILAMENT_RUNOUT_PAUSE=6]="FILAMENT_RUNOUT_PAUSE",e[e.HOTEND_HEATING=7]="HOTEND_HEATING",e[e.EXTRUDE_COMPENSATION_SCAN=8]="EXTRUDE_COMPENSATION_SCAN",e[e.BED_SCAN=9]="BED_SCAN",e[e.FIRST_LAYER_SCAN=10]="FIRST_LAYER_SCAN",e[e.BE_SURFACE_TYPT_IDENTIFICATION=11]="BE_SURFACE_TYPT_IDENTIFICATION",e[e.SCANNER_EXTRINSIC_PARA_CALI=12]="SCANNER_EXTRINSIC_PARA_CALI",e[e.TOOLHEAD_HOMING=13]="TOOLHEAD_HOMING",e[e.NOZZLE_TIP_CLEANING=14]="NOZZLE_TIP_CLEANING",e[e.EXTRUDER_TEMP_PROTECT_CALI=15]="EXTRUDER_TEMP_PROTECT_CALI",e[e.USER_PAUSE=16]="USER_PAUSE",e[e.TOOLHEAD_SHELL_OFF_PAUSE=17]="TOOLHEAD_SHELL_OFF_PAUSE",e[e.SCANNER_LASER_PARA_CALI=18]="SCANNER_LASER_PARA_CALI",e[e.EXTRUDER_ABSOLUTE_FLOW_CALI=19]="EXTRUDER_ABSOLUTE_FLOW_CALI",e[e.HOTEND_TEMPERATURE_ERROR_PAUSE=20]="HOTEND_TEMPERATURE_ERROR_PAUSE",e[e.HEATED_BED_TEMPERATURE_ERROR_PAUSE=21]="HEATED_BED_TEMPERATURE_ERROR_PAUSE",e[e.FILAMENT_UNLOADING=22]="FILAMENT_UNLOADING",e[e.SKIP_STEP_PAUSE=23]="SKIP_STEP_PAUSE",e[e.FILAMENT_LOADING=24]="FILAMENT_LOADING",e[e.MOTOR_NOISE_CALIBRATION=25]="MOTOR_NOISE_CALIBRATION",e[e.AMS_LOST_PAUSE=26]="AMS_LOST_PAUSE",e[e.HEAT_BREAK_FAN_PAUSE=27]="HEAT_BREAK_FAN_PAUSE",e[e.CHAMBER_TEMPERATURE_CONTROL_ERROR_PAUSE=28]="CHAMBER_TEMPERATURE_CONTROL_ERROR_PAUSE",e[e.CHAMBER_COOLING=29]="CHAMBER_COOLING",e[e.USER_INSERT_GCODE_PAUSE=30]="USER_INSERT_GCODE_PAUSE",e[e.MOTOR_NOISE_SHOWOFF=31]="MOTOR_NOISE_SHOWOFF",e[e.NOZZLE_FILAMENT_COVERED_DETECTED_PAUSE=32]="NOZZLE_FILAMENT_COVERED_DETECTED_PAUSE",e[e.CUTTER_ERROR_PAUSE=33]="CUTTER_ERROR_PAUSE",e[e.FIRST_LAYER_ERROR_PAUSE=34]="FIRST_LAYER_ERROR_PAUSE",e[e.NOZZLE_CLOG_PAUSE=35]="NOZZLE_CLOG_PAUSE"})(W||(W={}));var X;(function(e){e.SILENT="1",e.NORMAL="2",e.SPORT="3",e.LUDICROUS="4"})(X||(X={}));var V;(function(e){e[e.IDLE=0]="IDLE",e[e.READING=1]="READING",e[e.GCODE_TRANS=2]="GCODE_TRANS",e[e.GCODE_RUNNING=3]="GCODE_RUNNING",e[e.ASSISTANT=4]="ASSISTANT",e[e.SWITCH_FILAMENT=5]="SWITCH_FILAMENT",e[e.HAS_FILAMENT=6]="HAS_FILAMENT"})(V||(V={}));var $;(function(e){e.DOWNLOADING="DOWNLOADING",e.UPGRADE_REQUEST="UPGRADE_REQUEST",e.PRE_FLASH_START="PRE_FLASH_START",e.PRE_FLASH_SUCCESS="PRE_FLASH_SUCCESS"})($||($={}));var Z;(function(e){e.UPGRADE_SUCCESS="UPGRADE_SUCCESS",e.DOWNLOAD_FAIL="DOWNLOAD_FAIL",e.FLASH_FAIL="FLASH_FAIL",e.PRE_FLASH_FAIL="PRE_FLASH_FAIL",e.UPGRADE_FAIL="UPGRADE_FAIL"})(Z||(Z={}));var Y;(function(e){e[e.UpgradeNoError=0]="UpgradeNoError",e[e.UpgradeDownloadFailed=1]="UpgradeDownloadFailed",e[e.UpgradeVerifyFailed=2]="UpgradeVerifyFailed",e[e.UpgradeFlashFailed=3]="UpgradeFlashFailed",e[e.UpgradePrinting=4]="UpgradePrinting"})(Y||(Y={}));var K;(function(e){e[e.UNAVAILABLE=0]="UNAVAILABLE",e[e.IDLE=1]="IDLE",e[e.UPGRADING=2]="UPGRADING",e[e.UPGRADE_FINISHED=3]="UPGRADE_FINISHED"})(K||(K={}));var Q;(function(e){e.PLA="PLA",e.ABS="ABS",e.TPU="TPU",e.PC="PC",e.ASA="ASA",e.PA_CF="PA-CF",e.PA6_CF="PA6-CF",e.PET_CF="PET-CF",e.PETG="PETG",e.PETG_CF="PETG-CF",e.PLA_AERO="PLA-AERO",e.PLA_CF="PLA-CF",e.PPA_CF="PPA-CF",e.PPA_GF="PPA-GF",e.PA="PA",e.HIPS="HIPS",e.PPS="PPS",e.PPS_CF="PPS-CF",e.PVA="PVA",e.PLA_S="PLA-S",e.PA_S="PLA-S"})(Q||(Q={}));function Je(e){return k[e]??null}r(Je,"getFilamentConfig");function h(e){return e.command==="push_status"&&Object.keys(e).length>=40}r(h,"isPushAllCommand");function ee(e){return e.command==="gcode_line"&&!!e?.param?.startsWith("M106")}r(ee,"isUpdateFanCommand");function te(e){return e.command==="push_status"&&e.hasOwnProperty("lights_report")}r(te,"isUpdateLightCommand");function _e(e){return e.command==="push_status"&&(e.hasOwnProperty("spd_lvl")||e.hasOwnProperty("spd_mag"))}r(_e,"isUpdateSpeedCommand");function re(e){return e.command===e.command}r(re,"isUpdateStateCommand");function ae(e){return e.command==="gcode_line"&&!!(e?.param?.startsWith("M104")||e?.param?.startsWith("M140"))}r(ae,"isUpdateTempCommand");function g(e){return!!e?.mc_print&&!!e?.mc_print?.command&&["push_info"].includes(e.mc_print.command)}r(g,"isMCPrintMessage");function ht(e){return e.command==="push_info"}r(ht,"isPushInfoCommand");function gt(e){let[,_,t,l]=e.param.match(/^\[(.+?)](?:\[(.+?)])?\s*(.+)$/)??[];return{sequenceId:Number(e.sequence_id),category:_,subcategory:t,content:l,rawParam:e.param}}r(gt,"getCleanPushInfoCommand");function x(e){return e.command==="get_version"}r(x,"isGetVersionCommand");function z(e){return!!e?.info&&!!e?.info?.command&&["get_version"].includes(e.info.command)}r(z,"isInfoMessage");var E=class E extends f{constructor({fileName:t}){super({param:t});n(this,"category","print");n(this,"command","gcode_file");n(this,"ownsResponse",q)}};r(E,"GCodeFileCommand");var ie=E;var S=class S extends d{constructor({gcodes:t}){super(t);n(this,"command","gcode_line");n(this,"ownsResponse",j)}};r(S,"GCodeLineCommand");var ne=S;var G=class G extends f{constructor(){super();n(this,"category","info");n(this,"command","get_version");n(this,"ownsResponse",x)}};r(G,"GetVersionCommand");var b=G;var M=class M extends f{constructor(){super();n(this,"category","pushing");n(this,"command","pushall");n(this,"ownsResponse",h)}};r(M,"PushAllCommand");var c=M;var le;(function(e){e[e.PART_COOLING_FAN=1]="PART_COOLING_FAN",e[e.AUXILIARY_FAN=2]="AUXILIARY_FAN",e[e.CHAMBER_FAN=3]="CHAMBER_FAN"})(le||(le={}));var L=class L extends d{constructor({fan:t,speed:l}){super([`M106 P${t.toString()} S${255*l/100}`]);n(this,"command","gcode_line");n(this,"ownsResponse",ee)}};r(L,"UpdateFanCommand");var me=L;var F=class F extends f{constructor({light:t,mode:l,loopOptions:a={led_on_time:0,led_off_time:0,loop_times:0,interval_time:0}}){super({led_node:t,led_mode:l,...a});n(this,"category","system");n(this,"command","ledctrl");n(this,"ownsResponse",te)}};r(F,"UpdateLightCommand");var oe=F;var N=class N extends f{constructor({speed:t}){super({param:t.toString()});n(this,"category","print");n(this,"command","print_speed");n(this,"ownsResponse",_e)}};r(N,"UpdateSpeedCommand");var pe=N;var C=class C extends f{constructor({state:t}){super();n(this,"category","print");n(this,"command");n(this,"ownsResponse",re);this.command=t}};r(C,"UpdateStateCommand");var se=C;var fe;(function(e){e.BED="M140",e.EXTRUDER="M104"})(fe||(fe={}));var T=class T extends d{constructor({part:t,temperature:l}){super([`${t} S${l}`]);n(this,"command","gcode_line");n(this,"ownsResponse",ae)}};r(T,"UpdateTempCommand");var ue=T;var p;(function(e){e.X1C="X1C",e.X1="X1",e.X1E="X1E",e.P1P="P1P",e.P1S="P1S",e.A1="A1",e.A1M="A1M"})(p||(p={}));import{createId as xe}from"@paralleldrive/cuid2";var ze=new RegExp(/\.[^/.]+$/),R=class R{constructor(_,t,l,a=new Date){n(this,"_jobData");let o=[p.P1P,p.P1S].includes(l);this._jobData={id:xe(),printerId:t,printerModel:l,name:_.subtask_name.replace(ze,""),fileName:_.subtask_name,gcodeName:_.gcode_file,jobOrigin:_.print_type,totalLayerNumber:_.total_layer_num,totalPrintTime:_.mc_remaining_time,status:_.gcode_state,stage:_.stg_cur,percentDone:_.mc_percent,layerNumber:_.layer_num,remainingTime:_.mc_remaining_time,skippedObjects:_.s_obj,statusHistory:[{status:_.gcode_state,changedAt:a}],speedLevelHistory:[{speedLevel:_.spd_lvl,speedMagnitude:_.spd_mag,changedAt:a}],printingStageHistory:[{stage:_.stg_cur,changedAt:a}],temperatureHistory:[{bedTemp:_.bed_temper,bedTargetTemp:_.bed_target_temper,interiorTemp:o?_.frame_temper:_.chamber_temper,nozzleTemp:_.nozzle_temper,nozzleTargetTemp:_.nozzle_target_temper,changedAt:a}],tempLastUpdatedAt:new Date,errorCodes:_.hms.map(m=>({attr:m.attr,code:m.code,thrownAt:a,layerNumber:_.layer_num})),createdAt:a}}update(_){if(!this._jobData)return;let t=this._jobData,l=new Date,a=[p.P1P,p.P1S].includes(this._jobData.printerModel);_.gcode_state&&t.statusHistory.at(-1)?.status!==_.gcode_state&&t.statusHistory.push({status:_.gcode_state,changedAt:l}),_.spd_lvl&&_.spd_mag&&t.speedLevelHistory.at(-1)?.speedLevel!==_.spd_lvl&&t.speedLevelHistory.push({speedLevel:_.spd_lvl,speedMagnitude:_.spd_mag,changedAt:l}),_.stg_cur&&t.printingStageHistory.at(-1)?.stage!==_.stg_cur&&t.printingStageHistory.push({stage:_.stg_cur,changedAt:l});let o=!!(_.bed_temper||_.bed_target_temper||(a?_.frame_temper:_.chamber_temper)||_.nozzle_temper||_.nozzle_target_temper),m=t.tempLastUpdatedAt.getTime()+5e3<l.getTime();if(o&&m){let s=a?_.frame_temper:_.chamber_temper,u=t.temperatureHistory.at(-1);t.temperatureHistory.push({bedTemp:_.bed_temper??u.bedTemp,bedTargetTemp:_.bed_target_temper??u.bedTargetTemp,interiorTemp:s??u.interiorTemp,nozzleTemp:_.nozzle_temper??u.nozzleTemp,nozzleTargetTemp:_.nozzle_target_temper??u.nozzleTargetTemp,changedAt:l}),t.tempLastUpdatedAt=l}let i={status:_.gcode_state??t.status,stage:_.stg_cur??t.stage,percentDone:_.mc_percent??t.percentDone,layerNumber:_.layer_num??t.layerNumber,remainingTime:_.mc_remaining_time??t.remainingTime,skippedObjects:_.s_obj??t.skippedObjects,errorCodes:_.hms?.map((s,u)=>({attr:s.attr??t.errorCodes[u].attr,code:s.code??t.errorCodes[u].code,thrownAt:l??t.errorCodes[u].thrownAt,layerNumber:_.layer_num??t.errorCodes[u].layerNumber}))??t.errorCodes};this._jobData={...this._jobData,...i}}get data(){return this._jobData}};r(R,"Job");var w=R;import*as ce from"mqtt";import*as ye from"eventemitter3";import{createId as be}from"@paralleldrive/cuid2";function I(e){return new Promise(_=>setTimeout(_,e))}r(I,"sleep");function O(e,_){let t={},l=r((a,o,m)=>{for(let i in o){let s=o[i],u=a[i];if(!(i in a&&JSON.stringify(a[i])===JSON.stringify(o[i]))){if(typeof s=="object"&&s!==null&&u!==null&&!Array.isArray(s)){m[i]=m[i]||{},l(a[i],o[i],m[i]);continue}m[i]=o[i]}}},"checkDifferences");return l(e,_,t),t}r(O,"subtractObject");var D=class D extends ye.EventEmitter{constructor(t){super();n(this,"clientOptions");n(this,"id");n(this,"mqttClient");n(this,"config");n(this,"_printerData");n(this,"_printerStatus");n(this,"jobHistory");n(this,"currentJob");this.clientOptions=t,this.id=be(),this.mqttClient=void 0,this._printerData={modules:[],model:void 0},this._printerStatus="OFFLINE",this.jobHistory=[],this.currentJob=null,this.config={host:t.host,port:t.port??8883,accessToken:t.accessToken,serialNumber:t.serialNumber,throwOnOfflineCommands:t.throwOnOfflineCommands??!1,reconnectInterval:t.reconnectInterval??1e3,connectTimeout:t.connectTimeout??2e3,keepAlive:t.keepAlive??20},this.jobHistory=t.jobHistory??[],this.currentJob=t.currentJob??null}emit(t,...l){return super.emit(t,...l)}off(t,l){return super.off(t,l),this}once(t,l){return super.once(t,l),this}on(t,l){return super.on(t,l),this}async connectMQTT(){return new Promise((t,l)=>{if(this.mqttClient)throw new Error("Can't establish a new connection while running another one!");this.mqttClient=ce.connect(`mqtts://${this.config.host}:${this.config.port}`,{username:"bblp",password:this.config.accessToken,reconnectPeriod:this.clientOptions.reconnectInterval,connectTimeout:this.clientOptions.connectTimeout,keepalive:this.clientOptions.keepAlive,resubscribe:!0,rejectUnauthorized:!1}),this.mqttClient.on("connect",async(...a)=>{await this.onConnect(...a),this.emit("client:connect"),t()}),this.mqttClient.on("disconnect",()=>{this.emit("client:disconnect",!1),this.emit("printer:statusUpdate",this._printerStatus,"OFFLINE"),this._printerStatus="OFFLINE",this.currentJob&&this.emit("job:pause",this.currentJob,!0)}),this.mqttClient.on("offline",()=>{this.emit("client:disconnect",!0),this.emit("printer:statusUpdate",this._printerStatus,"OFFLINE"),this._printerStatus="OFFLINE",this.currentJob&&this.emit("job:pause",this.currentJob,!0)}),this.mqttClient.on("message",(a,o)=>this.emit("rawMessage",a,o)),this.mqttClient.on("error",a=>{this.emit("client:error",a),l(a)})})}async connect(){return await Promise.all([this.connectMQTT()])}async disconnect(t=!1,l){return new Promise(a=>this.mqttClient?.end(t,l,a))}subscribe(t){if(this._printerStatus!=="OFFLINE"&&this.config.throwOnOfflineCommands)throw new Error(`Unable to subscribe to topic "${t}" while disconnected from printer!`);return new Promise((l,a)=>{if(!this.mqttClient)return a("Client not connected.");this.mqttClient.subscribe(t,m=>{if(m)return a(`Error subscribing to topic '${t}': ${m.message}`)});let o=r(async(m,i)=>{m===t&&await this.onMessage(i.toString(),t)},"listener");this.mqttClient.on("message",o),l()})}async executeCommand(t){if(this._printerStatus!=="OFFLINE"&&this.config.throwOnOfflineCommands)throw new Error("Unable to send commands while disconnected from printer!");return new Promise((l,a)=>{t.invoke(this).catch(m=>a(m));let o=setTimeout(()=>{a(new Error("Command execution timed out after 5 seconds."))},5e3);this.on("rawMessage",(m,i)=>{let s=JSON.parse(i.toString()),u=Object.keys(s)[0];if(!(z(s)||g(s)||y(s)))return;let P=s[u];P?.command&&t.ownsResponse(P)&&(clearTimeout(o),l(P))})})}async onConnect(t){await this.subscribe(`device/${this.config.serialNumber}/report`),await I(1e3),await this.executeCommand(new b),(this._printerData.model===p.P1P||this._printerData.model===p.P1S||this._printerData.model===p.A1||this._printerData.model===p.A1M)&&(await this.executeCommand(new c),setInterval(async()=>{await this.executeCommand(new c)},5*60*1e3))}async onMessage(t,l){let a=JSON.parse(t),o=Object.keys(a)[0];if(z(a)||g(a)||y(a)){if(y(a)&&(this.emit("message",l,o,a.print),(h(a.print)||J(a.print))&&(this._printerData={...this._printerData,...a.print},this.emit("printer:dataUpdate",this._printerData,a.print),a.print.gcode_state&&a.print.gcode_state!==this._printerStatus))){let m=this._printerStatus,i=a.print.gcode_state;if(this.emit("printer:statusUpdate",m,i),(i==="PREPARE"||i==="SLICING")&&(i="IDLE"),(m==="PREPARE"||m==="SLICING")&&(m="RUNNING"),(m==="IDLE"||m==="FINISH"||m==="FAILED")&&i==="RUNNING")this.currentJob!==null&&this.jobHistory.push(this.currentJob),this.currentJob=new w(this._printerData,this.id,this._printerData.model),this.emit("job:start",this.currentJob);else if(m==="RUNNING"&&(i==="FINISH"||i==="FAILED"||i==="IDLE"))i==="FINISH"?this.currentJob!==null&&this.emit("job:finish",this.currentJob,"SUCCESS"):i==="FAILED"?this.currentJob!==null&&this.emit("job:finish",this.currentJob,"FAILED"):i==="IDLE"&&this.currentJob!==null&&this.emit("job:finish",this.currentJob,"UNEXPECTED"),this.currentJob!==null&&this.jobHistory.push(this.currentJob),this.currentJob=null;else if(m==="RUNNING"&&i==="PAUSE")this.currentJob&&this.emit("job:pause",this.currentJob,!1);else if(m==="PAUSE"&&i==="RUNNING")this.currentJob&&this.emit("job:unpause",this.currentJob);else if(m==="OFFLINE"&&i==="PAUSE")this.emit("job:offlineRecovery",this.currentJob);else if(!(m==="OFFLINE"&&i==="RUNNING")){if(!((m==="IDLE"||m==="OFFLINE")&&(i==="FINISH"||i==="FAILED"||i==="IDLE"))){if(!((m==="FINISH"||i==="FAILED")&&i==="IDLE")){if(m!==i)throw new Error("Edge case detected while updating printer status!")}}}if(this._printerStatus=a.print.gcode_state,this.currentJob){let s=this.currentJob?.data;this.currentJob.update(a.print),this.emit("job:update",this.currentJob,O(s,this.currentJob.data))}}if(g(a)&&this.emit("message",l,o,a.print),z(a)&&(this.emit("message",l,o,a.info),x(a.info))){let m=[...new Set([...this._printerData.modules,...a.info.module])];this._printerData.modules=m,this.emit("printer:dataUpdate",this._printerData,{modules:m});let i=this._printerData.modules.find(s=>s.name==="ota");if(!i)throw new Error("OTA module version data not found, unable to determine printer model!");if(i.sn.startsWith("00M"))this._printerData.model=p.X1C;else if(i.sn.startsWith("00W"))this._printerData.model=p.X1;else if(i.sn.startsWith("03W"))this._printerData.model=p.X1E;else if(i.sn.startsWith("01S"))this._printerData.model=p.P1P;else if(i.sn.startsWith("01P"))this._printerData.model=p.P1S;else if(i.sn.startsWith("030"))this._printerData.model=p.A1;else if(i.sn.startsWith("039"))this._printerData.model=p.A1M;else throw new Error("Printer model not supported!");this.emit("printer:dataUpdate",this._printerData,{model:this._printerData.model})}}}publish(t){return new Promise((l,a)=>{if(!this.mqttClient)return a("Client not connected.");let o=typeof t=="string"?t:JSON.stringify(t),m=`device/${this.config.serialNumber}/request`;this.mqttClient.publish(m,o,i=>{if(i)return a(`Error publishing to topic '${m}': ${i.message}`);l()})})}get data(){return this._printerData}get status(){return this._printerStatus}};r(D,"BambuClient");var de=D;export{f as AbstractCommand,V as AmsRFIDStatus,de as BambuClient,le as Fan,Q as FilamentType,d as GCodeCommand,ie as GCodeFileCommand,ne as GCodeLineCommand,b as GetVersionCommand,w as Job,W as PrintStage,p as PrinterModel,c as PushAllCommand,X as SpeedLevel,me as UpdateFanCommand,oe as UpdateLightCommand,pe as UpdateSpeedCommand,se as UpdateStateCommand,ue as UpdateTempCommand,K as UpgradeDisplayState,Y as UpgradeErrorCode,Z as UpgradeStatusFinishState,$ as UpgradeStatusProgressState,gt as getCleanPushInfoCommand,Je as getFilamentConfig,j as isGCodeLineCommand,q as isGcodeFileCommand,x as isGetVersionCommand,z as isInfoMessage,g as isMCPrintMessage,y as isPrintMessage,Oe as isProjectFileCommand,h as isPushAllCommand,ht as isPushInfoCommand,J as isPushStatusCommand,ee as isUpdateFanCommand,te as isUpdateLightCommand,_e as isUpdateSpeedCommand,re as isUpdateStateCommand,ae as isUpdateTempCommand};
16
+ +{endif}`],filament_id:"GFL01",filament_flow_ratio:["0.98"],filament_vendor:["Polymaker"]}};var W;(function(e){e[e.PRINTING=0]="PRINTING",e[e.BED_LEVELING=1]="BED_LEVELING",e[e.HEATBED_PREHEATING=2]="HEATBED_PREHEATING",e[e.XY_MECH_MODE_SWEEP=3]="XY_MECH_MODE_SWEEP",e[e.CHANGE_MATERIAL=4]="CHANGE_MATERIAL",e[e.M400_PAUSE=5]="M400_PAUSE",e[e.FILAMENT_RUNOUT_PAUSE=6]="FILAMENT_RUNOUT_PAUSE",e[e.HOTEND_HEATING=7]="HOTEND_HEATING",e[e.EXTRUDE_COMPENSATION_SCAN=8]="EXTRUDE_COMPENSATION_SCAN",e[e.BED_SCAN=9]="BED_SCAN",e[e.FIRST_LAYER_SCAN=10]="FIRST_LAYER_SCAN",e[e.BE_SURFACE_TYPT_IDENTIFICATION=11]="BE_SURFACE_TYPT_IDENTIFICATION",e[e.SCANNER_EXTRINSIC_PARA_CALI=12]="SCANNER_EXTRINSIC_PARA_CALI",e[e.TOOLHEAD_HOMING=13]="TOOLHEAD_HOMING",e[e.NOZZLE_TIP_CLEANING=14]="NOZZLE_TIP_CLEANING",e[e.EXTRUDER_TEMP_PROTECT_CALI=15]="EXTRUDER_TEMP_PROTECT_CALI",e[e.USER_PAUSE=16]="USER_PAUSE",e[e.TOOLHEAD_SHELL_OFF_PAUSE=17]="TOOLHEAD_SHELL_OFF_PAUSE",e[e.SCANNER_LASER_PARA_CALI=18]="SCANNER_LASER_PARA_CALI",e[e.EXTRUDER_ABSOLUTE_FLOW_CALI=19]="EXTRUDER_ABSOLUTE_FLOW_CALI",e[e.HOTEND_TEMPERATURE_ERROR_PAUSE=20]="HOTEND_TEMPERATURE_ERROR_PAUSE",e[e.HEATED_BED_TEMPERATURE_ERROR_PAUSE=21]="HEATED_BED_TEMPERATURE_ERROR_PAUSE",e[e.FILAMENT_UNLOADING=22]="FILAMENT_UNLOADING",e[e.SKIP_STEP_PAUSE=23]="SKIP_STEP_PAUSE",e[e.FILAMENT_LOADING=24]="FILAMENT_LOADING",e[e.MOTOR_NOISE_CALIBRATION=25]="MOTOR_NOISE_CALIBRATION",e[e.AMS_LOST_PAUSE=26]="AMS_LOST_PAUSE",e[e.HEAT_BREAK_FAN_PAUSE=27]="HEAT_BREAK_FAN_PAUSE",e[e.CHAMBER_TEMPERATURE_CONTROL_ERROR_PAUSE=28]="CHAMBER_TEMPERATURE_CONTROL_ERROR_PAUSE",e[e.CHAMBER_COOLING=29]="CHAMBER_COOLING",e[e.USER_INSERT_GCODE_PAUSE=30]="USER_INSERT_GCODE_PAUSE",e[e.MOTOR_NOISE_SHOWOFF=31]="MOTOR_NOISE_SHOWOFF",e[e.NOZZLE_FILAMENT_COVERED_DETECTED_PAUSE=32]="NOZZLE_FILAMENT_COVERED_DETECTED_PAUSE",e[e.CUTTER_ERROR_PAUSE=33]="CUTTER_ERROR_PAUSE",e[e.FIRST_LAYER_ERROR_PAUSE=34]="FIRST_LAYER_ERROR_PAUSE",e[e.NOZZLE_CLOG_PAUSE=35]="NOZZLE_CLOG_PAUSE"})(W||(W={}));var X;(function(e){e.SILENT="1",e.NORMAL="2",e.SPORT="3",e.LUDICROUS="4"})(X||(X={}));var V;(function(e){e[e.IDLE=0]="IDLE",e[e.READING=1]="READING",e[e.GCODE_TRANS=2]="GCODE_TRANS",e[e.GCODE_RUNNING=3]="GCODE_RUNNING",e[e.ASSISTANT=4]="ASSISTANT",e[e.SWITCH_FILAMENT=5]="SWITCH_FILAMENT",e[e.HAS_FILAMENT=6]="HAS_FILAMENT"})(V||(V={}));var $;(function(e){e.DOWNLOADING="DOWNLOADING",e.UPGRADE_REQUEST="UPGRADE_REQUEST",e.PRE_FLASH_START="PRE_FLASH_START",e.PRE_FLASH_SUCCESS="PRE_FLASH_SUCCESS"})($||($={}));var Z;(function(e){e.UPGRADE_SUCCESS="UPGRADE_SUCCESS",e.DOWNLOAD_FAIL="DOWNLOAD_FAIL",e.FLASH_FAIL="FLASH_FAIL",e.PRE_FLASH_FAIL="PRE_FLASH_FAIL",e.UPGRADE_FAIL="UPGRADE_FAIL"})(Z||(Z={}));var Y;(function(e){e[e.UpgradeNoError=0]="UpgradeNoError",e[e.UpgradeDownloadFailed=1]="UpgradeDownloadFailed",e[e.UpgradeVerifyFailed=2]="UpgradeVerifyFailed",e[e.UpgradeFlashFailed=3]="UpgradeFlashFailed",e[e.UpgradePrinting=4]="UpgradePrinting"})(Y||(Y={}));var K;(function(e){e[e.UNAVAILABLE=0]="UNAVAILABLE",e[e.IDLE=1]="IDLE",e[e.UPGRADING=2]="UPGRADING",e[e.UPGRADE_FINISHED=3]="UPGRADE_FINISHED"})(K||(K={}));var Q;(function(e){e.PLA="PLA",e.ABS="ABS",e.TPU="TPU",e.PC="PC",e.ASA="ASA",e.PA_CF="PA-CF",e.PA6_CF="PA6-CF",e.PET_CF="PET-CF",e.PETG="PETG",e.PETG_CF="PETG-CF",e.PLA_AERO="PLA-AERO",e.PLA_CF="PLA-CF",e.PPA_CF="PPA-CF",e.PPA_GF="PPA-GF",e.PA="PA",e.HIPS="HIPS",e.PPS="PPS",e.PPS_CF="PPS-CF",e.PVA="PVA",e.PLA_S="PLA-S",e.PA_S="PLA-S"})(Q||(Q={}));function Je(e){return k[e]??null}r(Je,"getFilamentConfig");function h(e){return e.command==="push_status"&&Object.keys(e).length>=40}r(h,"isPushAllCommand");function ee(e){return e.command==="gcode_line"&&!!e?.param?.startsWith("M106")}r(ee,"isUpdateFanCommand");function te(e){return e.command==="push_status"&&e.hasOwnProperty("lights_report")}r(te,"isUpdateLightCommand");function _e(e){return e.command==="push_status"&&(e.hasOwnProperty("spd_lvl")||e.hasOwnProperty("spd_mag"))}r(_e,"isUpdateSpeedCommand");function re(e){return e.command===e.command}r(re,"isUpdateStateCommand");function ae(e){return e.command==="gcode_line"&&!!(e?.param?.startsWith("M104")||e?.param?.startsWith("M140"))}r(ae,"isUpdateTempCommand");function g(e){return!!e?.mc_print&&!!e?.mc_print?.command&&["push_info"].includes(e.mc_print.command)}r(g,"isMCPrintMessage");function ht(e){return e.command==="push_info"}r(ht,"isPushInfoCommand");function gt(e){let[,_,t,l]=e.param.match(/^\[(.+?)](?:\[(.+?)])?\s*(.+)$/)??[];return{sequenceId:Number(e.sequence_id),category:_,subcategory:t,content:l,rawParam:e.param}}r(gt,"getCleanPushInfoCommand");function x(e){return e.command==="get_version"}r(x,"isGetVersionCommand");function z(e){return!!e?.info&&!!e?.info?.command&&["get_version"].includes(e.info.command)}r(z,"isInfoMessage");var E=class E extends f{constructor({fileName:t}){super({param:t});n(this,"category","print");n(this,"command","gcode_file");n(this,"ownsResponse",q)}};r(E,"GCodeFileCommand");var ie=E;var S=class S extends d{constructor({gcodes:t}){super(t);n(this,"command","gcode_line");n(this,"ownsResponse",j)}};r(S,"GCodeLineCommand");var ne=S;var G=class G extends f{constructor(){super();n(this,"category","info");n(this,"command","get_version");n(this,"ownsResponse",x)}};r(G,"GetVersionCommand");var b=G;var M=class M extends f{constructor(){super();n(this,"category","pushing");n(this,"command","pushall");n(this,"ownsResponse",h)}};r(M,"PushAllCommand");var c=M;var le;(function(e){e[e.PART_COOLING_FAN=1]="PART_COOLING_FAN",e[e.AUXILIARY_FAN=2]="AUXILIARY_FAN",e[e.CHAMBER_FAN=3]="CHAMBER_FAN"})(le||(le={}));var L=class L extends d{constructor({fan:t,speed:l}){super([`M106 P${t.toString()} S${255*l/100}`]);n(this,"command","gcode_line");n(this,"ownsResponse",ee)}};r(L,"UpdateFanCommand");var me=L;var F=class F extends f{constructor({light:t,mode:l,loopOptions:a={led_on_time:0,led_off_time:0,loop_times:0,interval_time:0}}){super({led_node:t,led_mode:l,...a});n(this,"category","system");n(this,"command","ledctrl");n(this,"ownsResponse",te)}};r(F,"UpdateLightCommand");var oe=F;var N=class N extends f{constructor({speed:t}){super({param:t.toString()});n(this,"category","print");n(this,"command","print_speed");n(this,"ownsResponse",_e)}};r(N,"UpdateSpeedCommand");var pe=N;var C=class C extends f{constructor({state:t}){super();n(this,"category","print");n(this,"command");n(this,"ownsResponse",re);this.command=t}};r(C,"UpdateStateCommand");var se=C;var fe;(function(e){e.BED="M140",e.EXTRUDER="M104"})(fe||(fe={}));var T=class T extends d{constructor({part:t,temperature:l}){super([`${t} S${l}`]);n(this,"command","gcode_line");n(this,"ownsResponse",ae)}};r(T,"UpdateTempCommand");var ue=T;var p;(function(e){e.X1C="X1C",e.X1="X1",e.X1E="X1E",e.P1P="P1P",e.P1S="P1S",e.P2S="P2S",e.A1="A1",e.A1M="A1M"})(p||(p={}));import{createId as xe}from"@paralleldrive/cuid2";var ze=new RegExp(/\.[^/.]+$/),R=class R{constructor(_,t,l,a=new Date){n(this,"_jobData");let o=[p.P1P,p.P1S].includes(l);this._jobData={id:xe(),printerId:t,printerModel:l,name:_.subtask_name.replace(ze,""),fileName:_.subtask_name,gcodeName:_.gcode_file,jobOrigin:_.print_type,totalLayerNumber:_.total_layer_num,totalPrintTime:_.mc_remaining_time,status:_.gcode_state,stage:_.stg_cur,percentDone:_.mc_percent,layerNumber:_.layer_num,remainingTime:_.mc_remaining_time,skippedObjects:_.s_obj,statusHistory:[{status:_.gcode_state,changedAt:a}],speedLevelHistory:[{speedLevel:_.spd_lvl,speedMagnitude:_.spd_mag,changedAt:a}],printingStageHistory:[{stage:_.stg_cur,changedAt:a}],temperatureHistory:[{bedTemp:_.bed_temper,bedTargetTemp:_.bed_target_temper,interiorTemp:o?_.frame_temper:_.chamber_temper,nozzleTemp:_.nozzle_temper,nozzleTargetTemp:_.nozzle_target_temper,changedAt:a}],tempLastUpdatedAt:new Date,errorCodes:_.hms.map(m=>({attr:m.attr,code:m.code,thrownAt:a,layerNumber:_.layer_num})),createdAt:a}}update(_){if(!this._jobData)return;let t=this._jobData,l=new Date,a=[p.P1P,p.P1S].includes(this._jobData.printerModel);_.gcode_state&&t.statusHistory.at(-1)?.status!==_.gcode_state&&t.statusHistory.push({status:_.gcode_state,changedAt:l}),_.spd_lvl&&_.spd_mag&&t.speedLevelHistory.at(-1)?.speedLevel!==_.spd_lvl&&t.speedLevelHistory.push({speedLevel:_.spd_lvl,speedMagnitude:_.spd_mag,changedAt:l}),_.stg_cur&&t.printingStageHistory.at(-1)?.stage!==_.stg_cur&&t.printingStageHistory.push({stage:_.stg_cur,changedAt:l});let o=!!(_.bed_temper||_.bed_target_temper||(a?_.frame_temper:_.chamber_temper)||_.nozzle_temper||_.nozzle_target_temper),m=t.tempLastUpdatedAt.getTime()+5e3<l.getTime();if(o&&m){let s=a?_.frame_temper:_.chamber_temper,u=t.temperatureHistory.at(-1);t.temperatureHistory.push({bedTemp:_.bed_temper??u.bedTemp,bedTargetTemp:_.bed_target_temper??u.bedTargetTemp,interiorTemp:s??u.interiorTemp,nozzleTemp:_.nozzle_temper??u.nozzleTemp,nozzleTargetTemp:_.nozzle_target_temper??u.nozzleTargetTemp,changedAt:l}),t.tempLastUpdatedAt=l}let i={status:_.gcode_state??t.status,stage:_.stg_cur??t.stage,percentDone:_.mc_percent??t.percentDone,layerNumber:_.layer_num??t.layerNumber,remainingTime:_.mc_remaining_time??t.remainingTime,skippedObjects:_.s_obj??t.skippedObjects,errorCodes:_.hms?.map((s,u)=>({attr:s.attr??t.errorCodes[u].attr,code:s.code??t.errorCodes[u].code,thrownAt:l??t.errorCodes[u].thrownAt,layerNumber:_.layer_num??t.errorCodes[u].layerNumber}))??t.errorCodes};this._jobData={...this._jobData,...i}}get data(){return this._jobData}};r(R,"Job");var w=R;import*as ce from"mqtt";import*as ye from"eventemitter3";import{createId as be}from"@paralleldrive/cuid2";function I(e){return new Promise(_=>setTimeout(_,e))}r(I,"sleep");function O(e,_){let t={},l=r((a,o,m)=>{for(let i in o){let s=o[i],u=a[i];if(!(i in a&&JSON.stringify(a[i])===JSON.stringify(o[i]))){if(typeof s=="object"&&s!==null&&u!==null&&!Array.isArray(s)){m[i]=m[i]||{},l(a[i],o[i],m[i]);continue}m[i]=o[i]}}},"checkDifferences");return l(e,_,t),t}r(O,"subtractObject");var D=class D extends ye.EventEmitter{constructor(t){super();n(this,"clientOptions");n(this,"id");n(this,"mqttClient");n(this,"config");n(this,"_printerData");n(this,"_printerStatus");n(this,"jobHistory");n(this,"currentJob");this.clientOptions=t,this.id=be(),this.mqttClient=void 0,this._printerData={modules:[],model:void 0},this._printerStatus="OFFLINE",this.jobHistory=[],this.currentJob=null,this.config={host:t.host,port:t.port??8883,accessToken:t.accessToken,serialNumber:t.serialNumber,throwOnOfflineCommands:t.throwOnOfflineCommands??!1,reconnectInterval:t.reconnectInterval??1e3,connectTimeout:t.connectTimeout??2e3,keepAlive:t.keepAlive??20},this.jobHistory=t.jobHistory??[],this.currentJob=t.currentJob??null}emit(t,...l){return super.emit(t,...l)}off(t,l){return super.off(t,l),this}once(t,l){return super.once(t,l),this}on(t,l){return super.on(t,l),this}async connectMQTT(){return new Promise((t,l)=>{if(this.mqttClient)throw new Error("Can't establish a new connection while running another one!");this.mqttClient=ce.connect(`mqtts://${this.config.host}:${this.config.port}`,{username:"bblp",password:this.config.accessToken,reconnectPeriod:this.clientOptions.reconnectInterval,connectTimeout:this.clientOptions.connectTimeout,keepalive:this.clientOptions.keepAlive,resubscribe:!0,rejectUnauthorized:!1}),this.mqttClient.on("connect",async(...a)=>{await this.onConnect(...a),this.emit("client:connect"),t()}),this.mqttClient.on("disconnect",()=>{this.emit("client:disconnect",!1),this.emit("printer:statusUpdate",this._printerStatus,"OFFLINE"),this._printerStatus="OFFLINE",this.currentJob&&this.emit("job:pause",this.currentJob,!0)}),this.mqttClient.on("offline",()=>{this.emit("client:disconnect",!0),this.emit("printer:statusUpdate",this._printerStatus,"OFFLINE"),this._printerStatus="OFFLINE",this.currentJob&&this.emit("job:pause",this.currentJob,!0)}),this.mqttClient.on("message",(a,o)=>this.emit("rawMessage",a,o)),this.mqttClient.on("error",a=>{this.emit("client:error",a),l(a)})})}async connect(){return await Promise.all([this.connectMQTT()])}async disconnect(t=!1,l){return new Promise(a=>this.mqttClient?.end(t,l,a))}subscribe(t){if(this._printerStatus!=="OFFLINE"&&this.config.throwOnOfflineCommands)throw new Error(`Unable to subscribe to topic "${t}" while disconnected from printer!`);return new Promise((l,a)=>{if(!this.mqttClient)return a("Client not connected.");this.mqttClient.subscribe(t,m=>{if(m)return a(`Error subscribing to topic '${t}': ${m.message}`)});let o=r(async(m,i)=>{m===t&&await this.onMessage(i.toString(),t)},"listener");this.mqttClient.on("message",o),l()})}async executeCommand(t){if(this._printerStatus!=="OFFLINE"&&this.config.throwOnOfflineCommands)throw new Error("Unable to send commands while disconnected from printer!");return new Promise((l,a)=>{t.invoke(this).catch(m=>a(m));let o=setTimeout(()=>{a(new Error("Command execution timed out after 5 seconds."))},5e3);this.on("rawMessage",(m,i)=>{let s=JSON.parse(i.toString()),u=Object.keys(s)[0];if(!(z(s)||g(s)||y(s)))return;let P=s[u];P?.command&&t.ownsResponse(P)&&(clearTimeout(o),l(P))})})}async onConnect(t){await this.subscribe(`device/${this.config.serialNumber}/report`),await I(1e3),await this.executeCommand(new b),(this._printerData.model===p.P1P||this._printerData.model===p.P1S||this._printerData.model===p.P2S||this._printerData.model===p.A1||this._printerData.model===p.A1M)&&(await this.executeCommand(new c),setInterval(async()=>{await this.executeCommand(new c)},5*60*1e3))}async onMessage(t,l){let a=JSON.parse(t),o=Object.keys(a)[0];if(z(a)||g(a)||y(a)){if(y(a)&&(this.emit("message",l,o,a.print),(h(a.print)||J(a.print))&&(this._printerData={...this._printerData,...a.print},this.emit("printer:dataUpdate",this._printerData,a.print),a.print.gcode_state&&a.print.gcode_state!==this._printerStatus))){let m=this._printerStatus,i=a.print.gcode_state;if(this.emit("printer:statusUpdate",m,i),(i==="PREPARE"||i==="SLICING")&&(i="IDLE"),(m==="PREPARE"||m==="SLICING")&&(m="RUNNING"),(m==="IDLE"||m==="FINISH"||m==="FAILED")&&i==="RUNNING")this.currentJob!==null&&this.jobHistory.push(this.currentJob),this.currentJob=new w(this._printerData,this.id,this._printerData.model),this.emit("job:start",this.currentJob);else if(m==="RUNNING"&&(i==="FINISH"||i==="FAILED"||i==="IDLE"))i==="FINISH"?this.currentJob!==null&&this.emit("job:finish",this.currentJob,"SUCCESS"):i==="FAILED"?this.currentJob!==null&&this.emit("job:finish",this.currentJob,"FAILED"):i==="IDLE"&&this.currentJob!==null&&this.emit("job:finish",this.currentJob,"UNEXPECTED"),this.currentJob!==null&&this.jobHistory.push(this.currentJob),this.currentJob=null;else if(m==="RUNNING"&&i==="PAUSE")this.currentJob&&this.emit("job:pause",this.currentJob,!1);else if(m==="PAUSE"&&i==="RUNNING")this.currentJob&&this.emit("job:unpause",this.currentJob);else if(m==="OFFLINE"&&i==="PAUSE")this.emit("job:offlineRecovery",this.currentJob);else if(!(m==="OFFLINE"&&i==="RUNNING")){if(!((m==="IDLE"||m==="OFFLINE")&&(i==="FINISH"||i==="FAILED"||i==="IDLE"))){if(!((m==="FINISH"||i==="FAILED")&&i==="IDLE")){if(m!==i)throw new Error("Edge case detected while updating printer status!")}}}if(this._printerStatus=a.print.gcode_state,this.currentJob){let s=this.currentJob?.data;this.currentJob.update(a.print),this.emit("job:update",this.currentJob,O(s,this.currentJob.data))}}if(g(a)&&this.emit("message",l,o,a.print),z(a)&&(this.emit("message",l,o,a.info),x(a.info))){let m=[...new Set([...this._printerData.modules,...a.info.module])];this._printerData.modules=m,this.emit("printer:dataUpdate",this._printerData,{modules:m});let i=this._printerData.modules.find(s=>s.name==="ota");if(!i)throw new Error("OTA module version data not found, unable to determine printer model!");if(i.sn.startsWith("00M"))this._printerData.model=p.X1C;else if(i.sn.startsWith("00W"))this._printerData.model=p.X1;else if(i.sn.startsWith("03W"))this._printerData.model=p.X1E;else if(i.sn.startsWith("01S"))this._printerData.model=p.P1P;else if(i.sn.startsWith("01P"))this._printerData.model=p.P1S;else if(i.sn.startsWith("22E"))this._printerData.model=p.P2S;else if(i.sn.startsWith("030"))this._printerData.model=p.A1;else if(i.sn.startsWith("039"))this._printerData.model=p.A1M;else throw new Error("Printer model not supported!");this.emit("printer:dataUpdate",this._printerData,{model:this._printerData.model})}}}publish(t){return new Promise((l,a)=>{if(!this.mqttClient)return a("Client not connected.");let o=typeof t=="string"?t:JSON.stringify(t),m=`device/${this.config.serialNumber}/request`;this.mqttClient.publish(m,o,i=>{if(i)return a(`Error publishing to topic '${m}': ${i.message}`);l()})})}get data(){return this._printerData}get status(){return this._printerStatus}};r(D,"BambuClient");var de=D;export{f as AbstractCommand,V as AmsRFIDStatus,de as BambuClient,le as Fan,Q as FilamentType,d as GCodeCommand,ie as GCodeFileCommand,ne as GCodeLineCommand,b as GetVersionCommand,w as Job,W as PrintStage,p as PrinterModel,c as PushAllCommand,X as SpeedLevel,me as UpdateFanCommand,oe as UpdateLightCommand,pe as UpdateSpeedCommand,se as UpdateStateCommand,ue as UpdateTempCommand,K as UpgradeDisplayState,Y as UpgradeErrorCode,Z as UpgradeStatusFinishState,$ as UpgradeStatusProgressState,gt as getCleanPushInfoCommand,Je as getFilamentConfig,j as isGCodeLineCommand,q as isGcodeFileCommand,x as isGetVersionCommand,z as isInfoMessage,g as isMCPrintMessage,y as isPrintMessage,Oe as isProjectFileCommand,h as isPushAllCommand,ht as isPushInfoCommand,J as isPushStatusCommand,ee as isUpdateFanCommand,te as isUpdateLightCommand,_e as isUpdateSpeedCommand,re as isUpdateStateCommand,ae as isUpdateTempCommand};