From 503fd6e0decbb42126dd62acb64f598937d71748 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Sat, 1 Aug 2026 19:37:13 +0100 Subject: [PATCH] Add printer configuration methods for speed, extrude, velocity, acceleration, and corner settings - Implemented new methods in PrinterClient to set speed factor, extrude factor, max velocity, max acceleration, square corner velocity, and min cruise ratio. - Enhanced error handling and logging for each method to ensure robust operation and user feedback. - Updated PrinterManager to handle new actions for these settings, allowing for dynamic adjustments during operation. --- src/printer/printerclient.js | 372 ++++++++++++++++++++++++++++++++++ src/printer/printermanager.js | 42 ++++ 2 files changed, 414 insertions(+) diff --git a/src/printer/printerclient.js b/src/printer/printerclient.js index ef02ae5..91b5858 100644 --- a/src/printer/printerclient.js +++ b/src/printer/printerclient.js @@ -1502,6 +1502,378 @@ export class PrinterClient { } } + async setSpeedFactor({ speedFactor }) { + logger.info(`Setting speed factor for ${this.printer.name}:`, speedFactor); + + if (!this.isOnline) { + logger.error( + `Cannot set speed factor: Not connected to Moonraker (${this.printer.name})`, + ); + return this.printerActionResult( + false, + "Printer is not connected to Moonraker", + ); + } + + try { + if (speedFactor === undefined || speedFactor === null) { + logger.warn( + `No speed factor provided for ${this.printer.name}`, + ); + return this.printerActionResult(false, "No speed factor provided"); + } + + const result = await this.runGcodeScript(`M220 S${speedFactor}`); + if (!result.success) { + logger.error( + `Failed to set speed factor for ${this.printer.name}`, + result.error, + ); + return result; + } + + _.merge(this.motionObject, { speedFactor: speedFactor / 100 }); + logger.info(`Successfully set speed factor for ${this.printer.name}`); + return result; + } catch (error) { + logger.error( + `Error setting speed factor for ${this.printer.name}:`, + error, + ); + await this.addMotionErrorAlert(error); + return this.printerActionResult( + false, + error?.message || "Failed to set speed factor", + error?.code, + ); + } + } + + async setExtrudeFactor({ extrudeFactor }) { + logger.info(`Setting extrude factor for ${this.printer.name}:`, extrudeFactor); + + if (!this.isOnline) { + logger.error( + `Cannot set extrude factor: Not connected to Moonraker (${this.printer.name})`, + ); + return this.printerActionResult( + false, + "Printer is not connected to Moonraker", + ); + } + + try { + if (extrudeFactor === undefined || extrudeFactor === null) { + logger.warn( + `No extrude factor provided for ${this.printer.name}`, + ); + return this.printerActionResult(false, "No extrude factor provided"); + } + + const result = await this.runGcodeScript(`M221 S${extrudeFactor}`); + if (!result.success) { + logger.error( + `Failed to set extrude factor for ${this.printer.name}`, + result.error, + ); + return result; + } + + _.merge(this.motionObject, { extrudeFactor: extrudeFactor / 100 }); + logger.info(`Successfully set extrude factor for ${this.printer.name}`); + return result; + } catch (error) { + logger.error( + `Error setting extrude factor for ${this.printer.name}:`, + error, + ); + await this.addMotionErrorAlert(error); + return this.printerActionResult( + false, + error?.message || "Failed to set extrude factor", + error?.code, + ); + } + } + + async setMaxVelocity({ maxVelocity }) { + logger.info(`Setting max velocity for ${this.printer.name}:`, maxVelocity); + + if (!this.isOnline) { + logger.error( + `Cannot set max velocity: Not connected to Moonraker (${this.printer.name})`, + ); + return this.printerActionResult( + false, + "Printer is not connected to Moonraker", + ); + } + + try { + if (maxVelocity === undefined || maxVelocity === null) { + logger.warn(`No max velocity provided for ${this.printer.name}`); + return this.printerActionResult(false, "No max velocity provided"); + } + + const result = await this.runGcodeScript( + `SET_VELOCITY_LIMIT VELOCITY=${maxVelocity}`, + ); + if (!result.success) { + logger.error( + `Failed to set max velocity for ${this.printer.name}`, + result.error, + ); + return result; + } + + _.merge(this.motionObject, { maxVelocity }); + logger.info(`Successfully set max velocity for ${this.printer.name}`); + return result; + } catch (error) { + logger.error( + `Error setting max velocity for ${this.printer.name}:`, + error, + ); + await this.addMotionErrorAlert(error); + return this.printerActionResult( + false, + error?.message || "Failed to set max velocity", + error?.code, + ); + } + } + + async setMaxAcceleration({ maxAcceleration }) { + logger.info( + `Setting max acceleration for ${this.printer.name}:`, + maxAcceleration, + ); + + if (!this.isOnline) { + logger.error( + `Cannot set max acceleration: Not connected to Moonraker (${this.printer.name})`, + ); + return this.printerActionResult( + false, + "Printer is not connected to Moonraker", + ); + } + + try { + if (maxAcceleration === undefined || maxAcceleration === null) { + logger.warn(`No max acceleration provided for ${this.printer.name}`); + return this.printerActionResult(false, "No max acceleration provided"); + } + + const result = await this.runGcodeScript( + `SET_VELOCITY_LIMIT ACCEL=${maxAcceleration}`, + ); + if (!result.success) { + logger.error( + `Failed to set max acceleration for ${this.printer.name}`, + result.error, + ); + return result; + } + + _.merge(this.motionObject, { maxAcceleration }); + logger.info(`Successfully set max acceleration for ${this.printer.name}`); + return result; + } catch (error) { + logger.error( + `Error setting max acceleration for ${this.printer.name}:`, + error, + ); + await this.addMotionErrorAlert(error); + return this.printerActionResult( + false, + error?.message || "Failed to set max acceleration", + error?.code, + ); + } + } + + async setSquareCornerVelocity({ squareCornerVelocity }) { + logger.info( + `Setting square corner velocity for ${this.printer.name}:`, + squareCornerVelocity, + ); + + if (!this.isOnline) { + logger.error( + `Cannot set square corner velocity: Not connected to Moonraker (${this.printer.name})`, + ); + return this.printerActionResult( + false, + "Printer is not connected to Moonraker", + ); + } + + try { + if ( + squareCornerVelocity === undefined || + squareCornerVelocity === null + ) { + logger.warn( + `No square corner velocity provided for ${this.printer.name}`, + ); + return this.printerActionResult( + false, + "No square corner velocity provided", + ); + } + + const result = await this.runGcodeScript( + `SET_VELOCITY_LIMIT SQUARE_CORNER_VELOCITY=${squareCornerVelocity}`, + ); + if (!result.success) { + logger.error( + `Failed to set square corner velocity for ${this.printer.name}`, + result.error, + ); + return result; + } + + _.merge(this.motionObject, { squareCornerVelocity }); + logger.info( + `Successfully set square corner velocity for ${this.printer.name}`, + ); + return result; + } catch (error) { + logger.error( + `Error setting square corner velocity for ${this.printer.name}:`, + error, + ); + await this.addMotionErrorAlert(error); + return this.printerActionResult( + false, + error?.message || "Failed to set square corner velocity", + error?.code, + ); + } + } + + async setMinCruiseRatio({ minCruiseRatio }) { + logger.info( + `Setting min cruise ratio for ${this.printer.name}:`, + minCruiseRatio, + ); + + if (!this.isOnline) { + logger.error( + `Cannot set min cruise ratio: Not connected to Moonraker (${this.printer.name})`, + ); + return this.printerActionResult( + false, + "Printer is not connected to Moonraker", + ); + } + + try { + if (minCruiseRatio === undefined || minCruiseRatio === null) { + logger.warn(`No min cruise ratio provided for ${this.printer.name}`); + return this.printerActionResult(false, "No min cruise ratio provided"); + } + + const result = await this.runGcodeScript( + `SET_VELOCITY_LIMIT MINIMUM_CRUISE_RATIO=${minCruiseRatio}`, + ); + if (!result.success) { + logger.error( + `Failed to set min cruise ratio for ${this.printer.name}`, + result.error, + ); + return result; + } + + _.merge(this.motionObject, { minCruiseRatio }); + logger.info(`Successfully set min cruise ratio for ${this.printer.name}`); + return result; + } catch (error) { + logger.error( + `Error setting min cruise ratio for ${this.printer.name}:`, + error, + ); + await this.addMotionErrorAlert(error); + return this.printerActionResult( + false, + error?.message || "Failed to set min cruise ratio", + error?.code, + ); + } + } + + updateMiscObjectFromScript(script) { + const fanMatch = script.match(/^M106 S(\d+)/); + if (fanMatch) { + const speed = Number(fanMatch[1]) / 255; + _.merge(this.miscObject, { fan: { speed, target: speed } }); + return; + } + + const lcdMatch = script.match( + /SET_LCD LCD=lcd_backlight BRIGHTNESS=([\d.]+)/, + ); + if (lcdMatch) { + _.merge(this.miscObject, { + lcdBacklight: { brightness: Number(lcdMatch[1]) }, + }); + return; + } + + const beeperMatch = script.match(/M300 .+ V(\d+)/); + if (beeperMatch) { + _.merge(this.miscObject, { + beeper: { value: Number(beeperMatch[1]) / 100 }, + }); + } + } + + async gcodeScript({ script }) { + logger.info(`Running g-code script for ${this.printer.name}:`, script); + + if (!this.isOnline) { + logger.error( + `Cannot run g-code script: Not connected to Moonraker (${this.printer.name})`, + ); + return this.printerActionResult( + false, + "Printer is not connected to Moonraker", + ); + } + + try { + if (!script) { + logger.warn(`No g-code script provided for ${this.printer.name}`); + return this.printerActionResult(false, "No g-code script provided"); + } + + const result = await this.runGcodeScript(script); + if (!result.success) { + logger.error( + `Failed to run g-code script for ${this.printer.name}`, + result.error, + ); + return result; + } + + this.updateMiscObjectFromScript(script); + logger.info(`Successfully ran g-code script for ${this.printer.name}`); + return result; + } catch (error) { + logger.error( + `Error running g-code script for ${this.printer.name}:`, + error, + ); + await this.addMotionErrorAlert(error); + return this.printerActionResult( + false, + error?.message || "Failed to run g-code script", + error?.code, + ); + } + } + async restartPrinterFirmware() { logger.info(`Restarting printer firmware for ${this.printer.name}`); if (!this.isOnline) { diff --git a/src/printer/printermanager.js b/src/printer/printermanager.js index fe5f962..125fe46 100644 --- a/src/printer/printermanager.js +++ b/src/printer/printermanager.js @@ -93,6 +93,48 @@ export class PrinterManager { callback(moveAxisResult); return; + case "setSpeedFactor": + const setSpeedFactorResult = await printer.setSpeedFactor(action.data); + callback(setSpeedFactorResult); + return; + + case "setExtrudeFactor": + const setExtrudeFactorResult = await printer.setExtrudeFactor( + action.data, + ); + callback(setExtrudeFactorResult); + return; + + case "setMaxVelocity": + const setMaxVelocityResult = await printer.setMaxVelocity(action.data); + callback(setMaxVelocityResult); + return; + + case "setMaxAcceleration": + const setMaxAccelerationResult = await printer.setMaxAcceleration( + action.data, + ); + callback(setMaxAccelerationResult); + return; + + case "setSquareCornerVelocity": + const setSquareCornerVelocityResult = + await printer.setSquareCornerVelocity(action.data); + callback(setSquareCornerVelocityResult); + return; + + case "setMinCruiseRatio": + const setMinCruiseRatioResult = await printer.setMinCruiseRatio( + action.data, + ); + callback(setMinCruiseRatioResult); + return; + + case "gcodeScript": + const gcodeScriptResult = await printer.gcodeScript(action.data); + callback(gcodeScriptResult); + return; + case "restartPrinterFirmware": const restartPrinterFirmwareResult = await printer.restartPrinterFirmware();