From e22df9b5ab4c248f0dcc37bd4eccca7360559689 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 13 Mar 2026 16:38:54 +0000 Subject: [PATCH] Feat: Replace custom KNCM with official Open-Elegoo-Community version Replaced our custom nozzle cleaning macros with the official Klipper Nozzle Clean Macro (KNCM) from Open-Elegoo-Community. Changes: - Added KNCM/nozzle_clean.cfg (official macro code) - Updated KNCM_settings.cfg with official variable-based config - Updated KNCM/KNCM_settings.cfg (copy for include path) - Removed custom CLEAN_NOZZLE, SMART_PARK, LINE_PURGE macros Benefits of official KNCM: - Proper wiper position calculation (not hardcoded X0 Y0!) - Variable-based configuration (easy to customize) - Filament-specific cleaning temperatures - Sinusoidal wiping pattern for better cleaning - PurgeShake to remove strings before wiping - Actively maintained by Open-Elegoo-Community Neptune 4 Plus specific settings: - printer_bed_y_max: 330 - wiping_axis: Y (bed moves) - cleaning_height: 30 (CALIBRATE THIS!) - bed_corner_to_wiper_offset: 40.5 (MEASURE THIS!) Reference: https://github.com/Open-Elegoo-Community/klipper-nozzle-clean-macro --- KNCM/KNCM_settings.cfg | 94 ++++++++ KNCM/nozzle_clean.cfg | 473 +++++++++++++++++++++++++++++++++++++++++ KNCM_settings.cfg | 218 +++++++++---------- 3 files changed, 673 insertions(+), 112 deletions(-) create mode 100644 KNCM/KNCM_settings.cfg create mode 100644 KNCM/nozzle_clean.cfg diff --git a/KNCM/KNCM_settings.cfg b/KNCM/KNCM_settings.cfg new file mode 100644 index 0000000..ad23a23 --- /dev/null +++ b/KNCM/KNCM_settings.cfg @@ -0,0 +1,94 @@ +############################################################################# +# NOZZLE CLEAN SETTINGS - Neptune 4 Plus +############################################################################# +# Original: https://github.com/Open-Elegoo-Community/klipper-nozzle-clean-macro +# Adapted for Neptune 4 Plus with corner wiper holder +############################################################################# + +[include KNCM/nozzle_clean.cfg] + +[gcode_macro _KNCM_SETTINGS] +description: "Nozzle cleaning settings for Neptune 4 Plus" + +# ------------------------------------------------------------------------ +# BASIC CLEANING CONFIGURATION +# ------------------------------------------------------------------------ + +# Set nozzle height for cleaning at the brush +# IMPORTANT: Calibrate this value! Start high (35) and work down +variable_cleaning_height: 30 + +# Specifies the axis that will move during wiping (X or Y) +# Y = Bed moves (Neptune 4), X = Nozzle moves (most CoreXY) +variable_wiping_axis: 'Y' + +# Set maximum Y value of the usable bed area (not the nozzle max travel) +# N4=229, N4Plus=330, N4Max=430 +variable_printer_bed_y_max: 330 + +# Number of times the cleaning motions are executed +# 1 loop = 3 passes (first, second, third) +variable_cleaning_loops: 1 + +# Disable (0) / Enable (1) PurgeShake motion before cleaning +variable_purge_shake: 1 + +# Disable (0) / Enable (1) Wait for nozzle temp restore +variable_wait_nozzle_temp_restore: 1 + +# Disable (0) / Enable (1) debug messages in console +variable_debug: 0 + +# ------------------------------------------------------------------------ +# ACCELERATION (in mm/s²) & SPEED SETTINGS (in mm/s) +# ------------------------------------------------------------------------ +# Acceleration (0 = use printer default) +variable_acceleration: 0 + +# Travel speed (fast non-cleaning moves) +variable_travel_speed: 350 + +# Speed for slow cleaning moves +variable_slow_speed: 250 + +# Speed for fast cleaning moves +variable_fast_speed: 500 + +# ------------------------------------------------------------------------ +# FILAMENT CLEANING TEMPERATURES +# ------------------------------------------------------------------------ +# Cleaning temperatures by filament type (cooler than print temp) +variable_cleaning_temperatures: { + "PLA":140, + "PETG":160, + "TPU":180, + "ABS":190, + "ASA":190 +} + +# ------------------------------------------------------------------------ +# WIPER SETUP (brush geometry and offsets) - NEPTUNE 4 PLUS SPECIFIC +# ------------------------------------------------------------------------ + +# Wiper width (X-axis space used by the brush) +variable_wiper_width: 8 + +# Wiper length (Y-axis space used by the brush) +variable_wiper_length: 37 + +# Thickness of the wiper holder wall (distance from bed to silicone) +variable_wiper_walloffset: 0 + +# Distance from bed origin (X=0) to start of silicone brush area +# Neptune 4 Plus: Wiper is in corner, measure from X=0 to brush start +variable_bed_corner_to_wiper_offset: 40.5 + +# Number of sinusoidal waves during cleaning motion +variable_waves: 2 + +# ------------------------------------------------------------------------ +# !!! DO NOT EDIT BELOW !!! +# ------------------------------------------------------------------------ +gcode: + ; This macro only stores shared variables, no actual commands + {action_respond_info("Running KNCM_SETTINGS does nothing - it stores settings only")} diff --git a/KNCM/nozzle_clean.cfg b/KNCM/nozzle_clean.cfg new file mode 100644 index 0000000..a5111af --- /dev/null +++ b/KNCM/nozzle_clean.cfg @@ -0,0 +1,473 @@ +############################################################################# +# NOZZLE CLEAN CODE +############################################################################# + +# ------------------------------------------------------------------------ +# !!! DO NOT EDIT THIS FILE !!! - Changes below are unsupported +# ------------------------------------------------------------------------ + +[gcode_macro CLEAN_NOZZLE] +description: Nozzle cleaning using a brush +gcode: + # ------------------------------------------------------------------------ + # LOAD SETTINGS + # ------------------------------------------------------------------------ + # Load variables from KNCM_settings.cfg + {% set KNCM_SETTINGS = printer['gcode_macro _KNCM_SETTINGS'] %} + # cleaningHeight + {% set cleaningHeight = KNCM_SETTINGS.cleaning_height %} + # wipingAxis + {% set wipingAxis = KNCM_SETTINGS.wiping_axis %} + # printerBedYMax + {% set printerBedYMax = KNCM_SETTINGS.printer_bed_y_max %} + # cleaningLoops + {% set cleaningLoops = KNCM_SETTINGS.cleaning_loops %} + # purgeSHake + {% set purgeShake = KNCM_SETTINGS.purge_shake %} + # waitNozzleTempRestore + {% set waitNozzleTempRestore = KNCM_SETTINGS.wait_nozzle_temp_restore %} + # debug + {% set debug = KNCM_SETTINGS.debug %} + # acceleration + {% set acceleration = KNCM_SETTINGS.acceleration %} + # speed + {% set travelSpeed = KNCM_SETTINGS.travel_speed %} + {% set slowSpeed = KNCM_SETTINGS.slow_speed %} + {% set fastSpeed = KNCM_SETTINGS.fast_speed %} + # cleaningTemperatures + {% set cleaningTemperatures = KNCM_SETTINGS.cleaning_temperatures %} + # wiperWidth + {% set wiperWidth = KNCM_SETTINGS.wiper_width %} + # wiperLength + {% set wiperLength = KNCM_SETTINGS.wiper_length %} + # wiperWallOffset + {% set wiperWallOffset = KNCM_SETTINGS.wiper_walloffset %} + # bedCornerToWiperOffset + {% set bedCornerToWiperOffset = KNCM_SETTINGS.bed_corner_to_wiper_offset %} + # waves + {% set waves = KNCM_SETTINGS.waves %} + + # ------------------------------------------------------------------------ + # DEBUG MESSAGE - LOADED VARIABLES + # ------------------------------------------------------------------------ + {% if debug == 1 %} + RESPOND MSG="INFO: loaded Variables" + RESPOND MSG=" - cleaningHeight : { cleaningHeight }" + RESPOND MSG=" - wipingAxis : { wipingAxis }" + RESPOND MSG=" - printerBedYMax : { printerBedYMax }" + RESPOND MSG=" - cleaningLoops : { cleaningLoops }" + RESPOND MSG=" - purgeShake : { purgeShake }" + RESPOND MSG=" - waitNozzleTempRestore : { waitNozzleTempRestore }" + RESPOND MSG=" - debug : { debug }" + RESPOND MSG=" - wiperWidth : { wiperWidth }" + RESPOND MSG=" - wiperLength : { wiperLength }" + RESPOND MSG=" - wiperWallOffset : { wiperWallOffset }" + RESPOND MSG=" - bedCornerToWiperOffset : { bedCornerToWiperOffset }" + RESPOND MSG=" - waves : { waves }" + RESPOND MSG=" - acceleration : { acceleration }" + RESPOND MSG=" - travelSpeed : { travelSpeed }" + RESPOND MSG=" - slowSpeed : { slowSpeed }" + RESPOND MSG=" - fastSpeed : { fastSpeed }" + RESPOND MSG=" - cleaningTemperatures : { cleaningTemperatures }" + {% endif %} + + # ------------------------------------------------------------------------ + # INITIALIZE, CHECK AND PROCESS VARIABLES + # ------------------------------------------------------------------------ + {% set filamentType = params.FILAMENT_TYPE|default("PLA")|string|upper %} # Set filamentType to the provided variable (fallback to PLA) + {% set error = 0 %} # Initialize error variable + + {% if wipingAxis not in ["x", "X", "y", "Y"] %} # Check for a valid wipingAxis + RESPOND MSG="ERROR: Wiping axis configuration error. Please check your wipingAxis setting!" + {% set error = 1 %} + {% endif %} + + {% if wipingAxis in ["x", "X"] %} # Check clearances for cleaning with head movements + {% if ((printer.toolhead.axis_maximum.y - printerBedYMax) < 3.2) %} + RESPOND MSG="ERROR: Insufficient vertical clearance between printerBedYMax ({printerBedYMax}) and nozzle max Y ({printer.toolhead.axis_maximum.y}). Minimum required: 3.2mm." + {% set error = 1 %} + {% endif %} + {% if ((printerBedYMax < 1) or ((printerBedYMax > 1000))) %} + RESPOND MSG="ERROR: Printer bed Y-axis size ({printerBedYMax}) out of expected range. Please verify configuration." + {% set error = 1 %} + {% endif %} + {% elif ((printer.configfile.config.stepper_x.position_endstop|float + 3.2) > 0) %} # Check clearances for cleaning with bed movements + RESPOND MSG="ERROR: X homing sensor position ({printer.configfile.config.stepper_x.position_endstop}) is too close to the bed. Required: ≤ -3.2mm." + {% set error = 1 %} + {% endif %} + + {% if cleaningLoops < 1 %} # Check if cleaningLoops is set to a minimum of 1 loop + RESPOND MSG="WARNING: cleaningLoops set to false value:{cleaningLoops} - changed to default 1 " + {% set cleaningLoops = 1 %} + {% endif %} + + {% if wipingAxis in ["y", "Y"] %} # Cleaning using bed movement + {% set wiperYmax = printerBedYMax %} + {% if wiperWidth + wiperWallOffset + printer.configfile.config.stepper_x.position_endstop|float > 0 %} # limited clearance + {% set wiperXmin = printer.configfile.config.stepper_x.position_endstop|float %} + {% set wiperWidth = 0 - wiperWallOffset - printer.configfile.config.stepper_x.position_endstop|float %} + {% else %} + {% set wiperXmin = 0 - wiperWallOffset - wiperWidth %} + {% endif %} + {% else %} # Cleaning using head movement + {% set wiperXmin = bedCornerToWiperOffset %} + {% if printer.toolhead.axis_maximum.y - printerBedYMax - wiperWallOffset - wiperWidth < 0 %} + {% set wiperYmax = printer.toolhead.axis_maximum.y %} + {% set wiperWidth = printer.toolhead.axis_maximum.y - printerBedYMax - wiperWallOffset %} + {% else %} + {% set wiperYmax = printerBedYMax + wiperWallOffset + wiperWidth %} + {% endif %} + {% endif %} + + {% if acceleration != 0 %} + {% if acceleration > printer.configfile.config['printer']['max_accel']|float %} + {% set accelerationValidated = printer.configfile.config['printer']['max_accel']|float %} + {% else %} + {% set accelerationValidated = acceleration %} + {% endif %} + {% endif %} + + {% if travelSpeed > printer.configfile.config['printer']['max_velocity'] | float %} + {% set travelSpeed = printer.configfile.config['printer']['max_velocity'] | float %} + {% endif %} + {% set travelFeedrate = travelSpeed * 60 %} # Convert travelSpeed to travelFeedrate + {% if slowSpeed > printer.configfile.config['printer']['max_velocity'] | float %} + {% set slowSpeed = printer.configfile.config['printer']['max_velocity'] | float / 2 %} + {% endif %} + {% set slowFeedrate = slowSpeed * 60 %} # Convert slowSpeed to slowFeedrate + {% if fastSpeed > printer.configfile.config['printer']['max_velocity'] | float %} + {% set fastSpeed = printer.configfile.config['printer']['max_velocity'] | float %} + {% endif %} + {% set fastFeedrate = fastSpeed * 60 %} # Convert fastSpeed to fastFeedrate + + {% if debug == 1 %} + RESPOND MSG="INFO: processed Variables" + RESPOND MSG=" - wiperYmax : { wiperYmax }" + RESPOND MSG=" - wiperXmin : { wiperXmin }" + RESPOND MSG=" - wiperWidth : { wiperWidth }" + RESPOND MSG=" - acceleration : { accelerationValidated }" + RESPOND MSG=" - travelFeedrate : F{ travelFeedrate }" + RESPOND MSG=" - slowFeedrate : F{ slowFeedrate }" + RESPOND MSG=" - fastFeedrate : F{ fastFeedrate }" + {% endif %} + + # ------------------------------------------------------------------------ + # ERROR CHECK + # ------------------------------------------------------------------------ + {% if error == 0 %} # Continue only if error is zero + + # ------------------------------------------------------------------------ + # SET CLEANING ACCELERATION + # ------------------------------------------------------------------------ + {% if acceleration != 0 %} + SET_VELOCITY_LIMIT ACCEL={accelerationValidated} + {% endif %} + + # ------------------------------------------------------------------------ + # HOMING PROCESS + # ------------------------------------------------------------------------ + {% if "x" not in printer.toolhead.homed_axes and "y" not in printer.toolhead.homed_axes and "z" not in printer.toolhead.homed_axes %} + G28 + {% elif "x" not in printer.toolhead.homed_axes %} + G28 X + {% elif "y" not in printer.toolhead.homed_axes %} + G28 Y + {% elif "z" not in printer.toolhead.homed_axes %} + G28 Z + {% endif %} + + # ------------------------------------------------------------------------ + # SAVE Z AXIS POSITION + # ------------------------------------------------------------------------ + {% set zHeight = printer.toolhead.position.z %} + {% if zHeight == 0 %} + {% set zHeight = 10 %} + {% set travelHeight = zHeight %} + {% else %} + {% set travelHeight = zHeight + 10 %} + {% if travelHeight > printer.toolhead.axis_maximum.z|float %} + {% set travelHeight = printer.toolhead.axis_maximum.z|float -10 %} + {% endif %} + {% endif %} + {% if debug == 1 %} + RESPOND MSG="INFO: travelHeight set to {travelHeight}" + {% endif %} + + # ------------------------------------------------------------------------ + # CHECK FOR BLENDED FILAMENTS + # ------------------------------------------------------------------------ + {% if "-" in filamentType %} + {% set baseFilament = filamentType.split("-")[0] %} + {% set stringSplitted = 1 %} + {% else %} + {% set baseFilament = filamentType %} + {% set stringSplitted = 0 %} + {% endif %} + + # ------------------------------------------------------------------------ + # EVALUATE CLEANING TEMPERATURE + # ------------------------------------------------------------------------ + {% if baseFilament in cleaningTemperatures %} + {% set cleaningTemperature = cleaningTemperatures[baseFilament] %} + {% if debug == 1 %} + {% if stringSplitted == 0 %} + RESPOND MSG="INFO: Detected filament type {filamentType}. Cleaning temperature set to {cleaningTemperature}c." + {% else %} + RESPOND MSG="INFO: Detected filament type {filamentType} (base: {baseFilament}). Cleaning temperature set to {cleaningTemperature}c." + {% endif %} + {% endif %} + {% else %} + {% set cleaningTemperature = 140 %} + RESPOND MSG="WARNING: Unknown filament type {filamentType}. Default cleaning temperature of {cleaningTemperature}c will be used." + {% endif %} + + # ------------------------------------------------------------------------ + # SAVE NOZZLE TARGET TEMPERATURE + # ------------------------------------------------------------------------ + {% set nozzleTargetTemperature = printer['extruder'].target %} + + # ------------------------------------------------------------------------ + # HEAT EXTRUDER + # ------------------------------------------------------------------------ + {% if cleaningTemperature != nozzleTargetTemperature %} + SET_HEATER_TEMPERATURE HEATER=extruder TARGET={cleaningTemperature} + {% if debug == 1 %} + RESPOND MSG="INFO: Heating extruder to {cleaningTemperature}c for cleaning..." + {% endif %} + TEMPERATURE_WAIT SENSOR=extruder MINIMUM={cleaningTemperature-4} MAXIMUM={cleaningTemperature+10} + {% endif %} + + # ------------------------------------------------------------------------ + # CLEANING SEQUENCE + # ------------------------------------------------------------------------ + {% if debug == 1 %} + RESPOND MSG="INFO: Initiating nozzle cleaning sequence..." + {% endif %} + + # ------------------------------------------------------------------------ + # Purge Shake + # ------------------------------------------------------------------------ + {% if purgeShake == 1 %} + # Travel to PurgeShake position + G90 + G1 Z{travelHeight} F3000 + {% if wipingAxis in ["y", "Y"] %} + {% if debug == 1 %} + RESPOND MSG="INFO: Shaking movement starting at X=0, Y={printerBedYMax-1} (1mm safety margin)." + {% endif %} + G1 X0 Y{printerBedYMax-1} F{travelFeedrate} + {% else %} + {% if debug == 1 %} + RESPOND MSG="INFO: Shaking movement starting at X={bedCornerToWiperOffset+wiperLength+1}, Y={printerBedYMax-1} (1mm safety margin)." + {% endif %} + G1 X{bedCornerToWiperOffset+wiperLength+1} Y{printerBedYMax-1} F{travelFeedrate} + {% endif %} + + # Quick left/right movements to clear filament strings + G91 + G1 X20 F{fastFeedrate} + G1 X-20 + G1 X20 + G1 X-20 + G1 X20 + G1 X-20 + {% endif %} + + # ------------------------------------------------------------------------ + # Nozzle cleaning + # ------------------------------------------------------------------------ + {% if wipingAxis in ["y", "Y"] %} + # --- BED MOVEMENT CLEANING SEQUENCE --- + {% if debug == 1 %} + RESPOND MSG="INFO: Repeating cleaning motions for {cleaningLoops} times" + {% if wiperXmin == printer.configfile.config.stepper_x.position_endstop|float %} + RESPOND MSG="INFO: Starting first cleaning passes near X endstop at X={wiperXmin+0.2}, Y={wiperYmax} (limited X clearance)." + {% else %} + RESPOND MSG="INFO: Starting first cleaning passes at X={wiperXmin+(wiperWidth/4)}, Y={wiperYmax}." + {% endif %} + {% endif %} + + {% for loops in range(0, cleaningLoops) %} + G90 + {% if wiperXmin == printer.configfile.config.stepper_x.position_endstop|float %} + G1 X{wiperXmin+0.2} Y{wiperYmax} F{travelFeedrate} + {% else %} + G1 X{wiperXmin+(wiperWidth/4)} Y{wiperYmax} F{travelFeedrate} + {% endif %} + + # Lower nozzle and start cleaning motion + G1 Z{cleaningHeight} F1200 + + # Perform pseudosinusoidal cleaning motion + G91 + {%set ymov=(wiperLength/(waves*4)) %} + G1 F{slowFeedrate} + {% for i in range(0,waves) %} + G1 X{wiperWidth/2} Y-{ymov} + G1 Y-{ymov} + G1 X-{wiperWidth/2} Y-{ymov} + G1 Y-{ymov} + {% endfor %} + G1 X{wiperWidth/2} + {% for i in range(0,waves) %} + G1 X-{wiperWidth/2} Y{ymov} + G1 Y{ymov} + G1 X{wiperWidth/2} Y{ymov} + G1 Y{ymov} + {% endfor %} + + G1 F{fastFeedrate} + G1 X-{wiperWidth/2} + {% for i in range(0,waves) %} + G1 Y-{ymov} + G1 X{wiperWidth/2} Y-{ymov} + G1 Y-{ymov} + G1 X-{wiperWidth/2} Y-{ymov} + {% endfor %} + G1 X{wiperWidth/2} + {% for i in range(0,waves) %} + G1 Y{ymov} + G1 X-{wiperWidth/2} Y{ymov} + G1 Y{ymov} + G1 X{wiperWidth/2} Y{ymov} + {% endfor %} + + G1 F{slowFeedrate} + G1 X-{wiperWidth/2} + {% for i in range(0,waves) %} + G1 X{wiperWidth/2} Y-{2*ymov} + G1 X-{wiperWidth/2} Y-{2*ymov} + {% endfor %} + G1 X{wiperWidth/2} + {% for i in range(0,waves) %} + G1 X-{wiperWidth/2} Y{2*ymov} + G1 X{wiperWidth/2} Y{2*ymov} + {% endfor %} + {% endfor %} + + {% else %} + # --- HEAD MOVEMENT CLEANING SEQUENCE --- + {% if debug == 1 %} + RESPOND MSG="INFO: Repeating cleaning motions for {cleaningLoops} times" + {% if wiperYmax == printer.toolhead.axis_maximum.y %} + RESPOND MSG="INFO: Starting first cleaning passes near bed edge at X={wiperXmin+wiperLength}, Y={wiperYmax-0.1} (limited Y clearance)." + {% else %} + RESPOND MSG="INFO: Starting first cleaning passes at X={wiperXmin+wiperLength}, Y={wiperYmax-(wiperWidth/4)}." + {% endif %} + {% endif %} + + {% for loops in range(0, cleaningLoops) %} + G90 + {% if wiperYmax == printer.toolhead.axis_maximum.y %} + G1 X{wiperXmin+wiperLength} Y{wiperYmax-0.1} F{travelFeedrate} + {% else %} + G1 X{wiperXmin+wiperLength} Y{wiperYmax-(wiperWidth/4)} F{travelFeedrate} + {% endif %} + + # Lower nozzle and start cleaning motion + G1 Z{cleaningHeight} F1200 + + # Perform pseudosinusoidal cleaning motion + G91 + {%set xmov=(wiperLength/(waves*4)) %} + G1 F{slowFeedrate} + {% for i in range(0,waves) %} + G1 X-{xmov} Y-{wiperWidth} + G1 X-{xmov} + G1 X-{xmov} Y+{wiperWidth} + G1 X-{xmov} + {% endfor %} + G1 Y-{wiperWidth} + {% for i in range(0,waves) %} + G1 X{xmov} Y+{wiperWidth} + G1 X{xmov} + G1 X{xmov} Y-{wiperWidth} + G1 X{xmov} + {% endfor %} + + G1 F{fastFeedrate} + G1 Y+{wiperWidth} + {% for i in range(0,waves) %} + G1 X-{xmov} + G1 X-{xmov} Y-{wiperWidth} + G1 X-{xmov} + G1 X-{xmov} Y+{wiperWidth} + {% endfor %} + G1 Y-{wiperWidth} + {% for i in range(0,waves) %} + G1 X{xmov} + G1 X{xmov} Y+{wiperWidth} + G1 X{xmov} + G1 X{xmov} Y-{wiperWidth} + {% endfor %} + + G1 F{slowFeedrate} + G1 Y+{wiperWidth} + {% for i in range(0,waves) %} + G1 X-{xmov*2} Y-{wiperWidth} + G1 X-{xmov*2} Y+{wiperWidth} + {% endfor %} + G1 Y-{wiperWidth} + {% for i in range(0,waves) %} + G1 X{xmov*2} Y+{wiperWidth} + G1 X{xmov*2} Y-{wiperWidth} + {% endfor %} + {% endfor %} + {% endif %} + + # ------------------------------------------------------------------------ + # Restore saved nozze target temperature & move to middle of bed + # ------------------------------------------------------------------------ + {% if waitNozzleTempRestore == 0 %} + SET_HEATER_TEMPERATURE HEATER=extruder TARGET={nozzleTargetTemperature} + G1 Z{travelHeight} F3000 + {% else %} + G1 Z{travelHeight} F3000 + {% if nozzleTargetTemperature <= 60 %} # Nozzle is considered cold, use fans at 100% for faster cooldown + SET_HEATER_TEMPERATURE HEATER=extruder TARGET={nozzleTargetTemperature} + M106 S255 + {% if debug == 1 %} + RESPOND MSG="INFO: Nozzle was cold. Waiting for temperature to rise into 50-60c range..." + {% endif %} + TEMPERATURE_WAIT SENSOR=extruder MINIMUM={50} MAXIMUM={60} + M106 S0 + {% if debug == 1 %} + RESPOND MSG="INFO: Nozzle temperature reached target range (50-60c)." + {% endif %} + {% elif nozzleTargetTemperature > 60 and nozzleTargetTemperature < cleaningTemperature %} # Nozzle is preheated, use fans at 50% for faster cooldown + SET_HEATER_TEMPERATURE HEATER=extruder TARGET={nozzleTargetTemperature} + M106 S128 + {% if debug == 1 %} + RESPOND MSG="INFO: Restoring nozzle temperature to {nozzleTargetTemperature}c. Please wait for stabilization..." + {% endif %} + TEMPERATURE_WAIT SENSOR=extruder MINIMUM={nozzleTargetTemperature} MAXIMUM={nozzleTargetTemperature+10} + M106 S0 + {% if debug == 1 %} + RESPOND MSG="INFO: Nozzle temperature stabilized at ~{nozzleTargetTemperature}c." + {% endif %} + {% elif nozzleTargetTemperature >= cleaningTemperature %} # Nozzle is hot, use no fans for faster heating + SET_HEATER_TEMPERATURE HEATER=extruder TARGET={nozzleTargetTemperature} + {% if debug == 1 %} + RESPOND MSG="INFO: Restoring nozzle temperature to {nozzleTargetTemperature}c. Please wait for stabilization..." + {% endif %} + TEMPERATURE_WAIT SENSOR=extruder MINIMUM={nozzleTargetTemperature} MAXIMUM={nozzleTargetTemperature+10} + {% if debug == 1 %} + RESPOND MSG="INFO: Nozzle temperature stabilized at ~{nozzleTargetTemperature}c." + {% endif %} + {% endif %} + G90 + G1 X{printer.toolhead.axis_maximum.x/2} Y{printer.toolhead.axis_maximum.y/2} F{travelFeedrate} + {% endif %} + + # ------------------------------------------------------------------------ + # Reset Acceleration + # ------------------------------------------------------------------------ + SET_VELOCITY_LIMIT ACCEL={printer.configfile.config['printer']['max_accel']|float} + + # ------------------------------------------------------------------------ + # Print finish message + # ------------------------------------------------------------------------ + {% if debug == 1 %} + RESPOND MSG="INFO: Nozzle cleaning sequence complete." + {% endif %} + {% endif %} \ No newline at end of file diff --git a/KNCM_settings.cfg b/KNCM_settings.cfg index 8d49b92..eb177d9 100644 --- a/KNCM_settings.cfg +++ b/KNCM_settings.cfg @@ -1,114 +1,108 @@ -# ============================================================================ -# KNCM - Nozzle Cleaning Macros -# Simplified nozzle cleaning for reliable prints -# ============================================================================ +############################################################################# +# NOZZLE CLEAN SETTINGS - Neptune 4 Plus +############################################################################# +# Original: https://github.com/Open-Elegoo-Community/klipper-nozzle-clean-macro +# Adapted for Neptune 4 Plus with corner wiper holder +# +# INSTALLATION: +# 1. Install wiper holder: https://www.printables.com/model/1221208-neptune-4-plus-corner-guide-with-wiper +# 2. Measure your wiper position and adjust variables below +# 3. Calibrate cleaning_height carefully! +############################################################################# -# ---------------------------------------------------------------------------- -# SDCARD_RESET_FILE - Fix for Klipper SD card reset error -# ---------------------------------------------------------------------------- -[gcode_macro SDCARD_RESET_FILE] -description: Reset SD card file (placeholder to prevent errors) +[include KNCM/nozzle_clean.cfg] + +[gcode_macro _KNCM_SETTINGS] +description: "Nozzle cleaning settings for Neptune 4 Plus" + +# ------------------------------------------------------------------------ +# BASIC CLEANING CONFIGURATION +# ------------------------------------------------------------------------ + +# Set nozzle height for cleaning at the brush +# ⚠️ IMPORTANT: Calibrate this value! Start high (35) and work down +# Too low = damages wiper, Too high = doesn't clean +variable_cleaning_height: 30 + +# Specifies the axis that will move during wiping (X or Y) +# Y = Bed moves (Neptune 4 series) +# X = Nozzle moves (most CoreXY printers) +variable_wiping_axis: 'Y' + +# Set maximum Y value of the usable bed area (not the nozzle max travel) +# Neptune 4: 229, Neptune 4 Plus: 330, Neptune 4 Max: 430 +variable_printer_bed_y_max: 330 + +# Number of times the cleaning motions are executed +# 1 loop = 3 passes (first, second, third pass) +variable_cleaning_loops: 1 + +# Disable (0) / Enable (1) PurgeShake motion before cleaning +# Shakes off filament strings before wiping +variable_purge_shake: 1 + +# Disable (0) / Enable (1) Wait for nozzle temp restore after cleaning +variable_wait_nozzle_temp_restore: 1 + +# Disable (0) / Enable (1) debug messages in console +variable_debug: 0 + +# ------------------------------------------------------------------------ +# ACCELERATION (mm/s²) & SPEED SETTINGS (mm/s) +# ------------------------------------------------------------------------ +# Acceleration (0 = use printer default acceleration) +variable_acceleration: 0 + +# Travel speed (fast non-cleaning moves) +variable_travel_speed: 350 + +# Speed for slow cleaning moves (deep cleaning) +variable_slow_speed: 250 + +# Speed for fast cleaning moves (final wipe) +variable_fast_speed: 500 + +# ------------------------------------------------------------------------ +# FILAMENT CLEANING TEMPERATURES +# ------------------------------------------------------------------------ +# Cleaning temperatures by filament type (lower than print temp) +# Prevents oozing during cleaning +variable_cleaning_temperatures: { + "PLA":140, + "PETG":160, + "TPU":180, + "ABS":190, + "ASA":190 +} + +# ------------------------------------------------------------------------ +# WIPER SETUP (brush geometry and offsets) - NEPTUNE 4 PLUS +# ------------------------------------------------------------------------ +# ⚠️ MEASURE THESE VALUES for your specific wiper installation! +# ------------------------------------------------------------------------ + +# Wiper width (X-axis space used by the brush in mm) +variable_wiper_width: 8 + +# Wiper length (Y-axis space used by the brush in mm) +variable_wiper_length: 37 + +# Thickness of the wiper holder wall (distance from bed to silicone start) +# Usually 0 if silicone starts at wall edge +variable_wiper_walloffset: 0 + +# Distance from bed origin (X=0) to start of silicone brush area +# ⚠️ MEASURE THIS: From X=0 to where silicone begins +# Neptune 4 Plus typical: 40.5mm (adjust for your setup!) +variable_bed_corner_to_wiper_offset: 40.5 + +# Number of sinusoidal waves during cleaning motion +# More waves = more thorough cleaning, but slower +variable_waves: 2 + +# ------------------------------------------------------------------------ +# !!! DO NOT EDIT BELOW !!! +# ------------------------------------------------------------------------ gcode: - # Placeholder - SD card operations handled by Klipper - RESPOND MSG="SD card reset acknowledged" - -# ---------------------------------------------------------------------------- -# PRINTER VARIABLES - Neptune 4 Plus -# ---------------------------------------------------------------------------- -# Adjust these values in your user_settings.cfg if needed! -# ---------------------------------------------------------------------------- - -# Bed dimensions (not nozzle travel, but usable bed area) -# N4=229, N4Plus=330, N4Max=430 -# This is set via mesh_max in [bed_mesh] section - -# ---------------------------------------------------------------------------- -# CLEAN_NOZZLE - Wipe nozzle on brush/cloth -# ---------------------------------------------------------------------------- -[gcode_macro CLEAN_NOZZLE] -description: Clean nozzle on brush or cloth -gcode: - {% set FILAMENT_TYPE = params.FILAMENT_TYPE|default("PLA")|upper %} - {% set CLEAN_X = params.CLEAN_X|default(0)|int %} - {% set CLEAN_Y = params.CLEAN_Y|default(0)|int %} - {% set CLEAN_Z = params.CLEAN_Z|default(0.5)|float %} - {% set PASSES = params.PASSES|default(3)|int %} - - RESPOND MSG="Cleaning nozzle..." - - # Move to clean position - G1 X{CLEAN_X} Y{CLEAN_Y} Z{CLEAN_Z} F3000 - - # Wipe passes - {% for i in range(PASSES) %} - G1 X{CLEAN_X + 10} F1800 - G1 X{CLEAN_X} F1800 - {% endfor %} - - # Lift Z - G1 Z10 F600 - - RESPOND MSG="Nozzle clean complete!" - -# ---------------------------------------------------------------------------- -# SMART_PARK - Park near front for easy access -# ---------------------------------------------------------------------------- -[gcode_macro SMART_PARK] -description: Park nozzle at front of bed for easy access -gcode: - {% set PARK_X = params.PARK_X|default(165)|int %} - {% set PARK_Y = params.PARK_Y|default(10)|int %} - {% set PARK_Z = params.PARK_Z|default(50)|int %} - - G1 X{PARK_X} Y{PARK_Y} Z{PARK_Z} F6000 - - RESPOND MSG="Printer parked at front" - -# ---------------------------------------------------------------------------- -# LINE_PURGE - Print purge line at start of bed -# ---------------------------------------------------------------------------- -[gcode_macro LINE_PURGE] -description: Print purge line at start of bed -gcode: - {% set PURGE_START_X = params.START_X|default(10)|int %} - {% set PURGE_END_X = params.END_X|default(300)|int %} - {% set PURGE_Y = params.Y|default(10)|int %} - {% set PURGE_Z = params.Z|default(0.2)|float %} - {% set PURGE_AMOUNT = params.AMOUNT|default(30)|int %} - - # Move to purge start - G1 X{PURGE_START_X} Y{PURGE_Y} Z{PURGE_Z} F3000 - - # Extrude purge line - G1 X{PURGE_END_X} E{PURGE_AMOUNT} F600 - - # Lift Z - G1 Z2 F600 - - RESPOND MSG="Purge line printed" - -# ---------------------------------------------------------------------------- -# Frame Light Control (Neptune 4 Plus) -# ---------------------------------------------------------------------------- -[gcode_macro Frame_Light_ON] -description: Turn on frame LED lights -gcode: - SET_PIN PIN=frame_light VALUE=1 - -[gcode_macro Frame_Light_OFF] -description: Turn off frame LED lights -gcode: - SET_PIN PIN=frame_light VALUE=0 - -# ---------------------------------------------------------------------------- -# Part Light Control (Neptune 4 Plus) -# ---------------------------------------------------------------------------- -[gcode_macro Part_Light_ON] -description: Turn on part cooling fan light -gcode: - SET_PIN PIN=part_light VALUE=1 - -[gcode_macro Part_Light_OFF] -description: Turn off part cooling fan light -gcode: - SET_PIN PIN=part_light VALUE=0 + # This macro only stores shared variables, no actual commands + {action_respond_info("Running KNCM_SETTINGS does nothing - it stores settings only")}