|
| 1 | +## Client klipper macro definitions |
| 2 | +## |
| 3 | +## Copyright (C) 2022 Alex Zellner <[email protected]> |
| 4 | +## |
| 5 | +## This file may be distributed under the terms of the GNU GPLv3 license |
| 6 | +## |
| 7 | +## !!! This file is read-only. Maybe the used editor indicates that. !!! |
| 8 | +## |
| 9 | +## Customization: |
| 10 | +## 1) copy the gcode_macro _CLIENT_VARIABLE (see below) to your printer.cfg |
| 11 | +## 2) remove the comment mark (#) from all lines |
| 12 | +## 3) change any value in there to your needs |
| 13 | +## |
| 14 | +## Use the PAUSE macro direct in your M600: |
| 15 | +## e.g. with a different park position front left and a minimal height of 50 |
| 16 | +## [gcode_macro M600] |
| 17 | +## description: Filament change |
| 18 | +## gcode: PAUSE X=10 Y=10 Z_MIN=50 |
| 19 | +## Z_MIN will park the toolhead at a minimum of 50 mm above to bed to make it easier for you to swap filament. |
| 20 | +## |
| 21 | +## Client variable macro for your printer.cfg |
| 22 | +#[gcode_macro _CLIENT_VARIABLE] |
| 23 | +#variable_use_custom_pos : False ; use custom park coordinates for x,y [True/False] |
| 24 | +#variable_custom_park_x : 0.0 ; custom x position; value must be within your defined min and max of X |
| 25 | +#variable_custom_park_y : 0.0 ; custom y position; value must be within your defined min and max of Y |
| 26 | +#variable_custom_park_dz : 2.0 ; custom dz value; the value in mm to lift the nozzle when move to park position |
| 27 | +#variable_retract : 1.0 ; the value to retract while PAUSE |
| 28 | +#variable_cancel_retract : 5.0 ; the value to retract while CANCEL_PRINT |
| 29 | +#variable_speed_retract : 35.0 ; retract speed in mm/s |
| 30 | +#variable_unretract : 1.0 ; the value to unretract while RESUME |
| 31 | +#variable_speed_unretract : 35.0 ; unretract speed in mm/s |
| 32 | +#variable_speed_hop : 15.0 ; z move speed in mm/s |
| 33 | +#variable_speed_move : 100.0 ; move speed in mm/s |
| 34 | +#variable_park_at_cancel : False ; allow to move the toolhead to park while execute CANCEL_PRINT [True/False] |
| 35 | +#variable_park_at_cancel_x : None ; different park position during CANCEL_PRINT [None/Position as Float]; park_at_cancel must be True |
| 36 | +#variable_park_at_cancel_y : None ; different park position during CANCEL_PRINT [None/Position as Float]; park_at_cancel must be True |
| 37 | +## !!! Caution [firmware_retraction] must be defined in the printer.cfg if you set use_fw_retract: True !!! |
| 38 | +#variable_use_fw_retract : False ; use fw_retraction instead of the manual version [True/False] |
| 39 | +#variable_idle_timeout : 0 ; time in sec until idle_timeout kicks in. Value 0 means that no value will be set or restored |
| 40 | +#variable_runout_sensor : "" ; If a sensor is defined, it will be used to cancel the execution of RESUME in case no filament is detected. |
| 41 | +## Specify the config name of the runout sensor e.g "filament_switch_sensor runout". Hint use the same as in your printer.cfg |
| 42 | +## !!! Custom macros, please use with care and review the section of the corresponding macro. |
| 43 | +## These macros are for simple operations like setting a status LED. Please make sure your macro does not interfere with the basic macro functions. |
| 44 | +## Only single line commands are supported, please create a macro if you need more than one command. |
| 45 | +#variable_user_pause_macro : "" ; Everything inside the "" will be executed after the klipper base pause (PAUSE_BASE) function |
| 46 | +#variable_user_resume_macro: "" ; Everything inside the "" will be executed before the klipper base resume (RESUME_BASE) function |
| 47 | +#variable_user_cancel_macro: "" ; Everything inside the "" will be executed before the klipper base cancel (CANCEL_PRINT_BASE) function |
| 48 | +#gcode: |
| 49 | + |
| 50 | +[virtual_sdcard] |
| 51 | +path: ~/printer_data/gcodes |
| 52 | +on_error_gcode: CANCEL_PRINT |
| 53 | + |
| 54 | +[pause_resume] |
| 55 | +#recover_velocity: 50. |
| 56 | +# When capture/restore is enabled, the speed at which to return to |
| 57 | +# the captured position (in mm/s). Default is 50.0 mm/s. |
| 58 | + |
| 59 | +[display_status] |
| 60 | + |
| 61 | +[respond] |
| 62 | + |
| 63 | +[gcode_macro CANCEL_PRINT] |
| 64 | +description: Cancel the actual running print |
| 65 | +rename_existing: CANCEL_PRINT_BASE |
| 66 | +gcode: |
| 67 | + ##### get user parameters or use default ##### |
| 68 | + {% set client = printer['gcode_macro _CLIENT_VARIABLE'] | default({}) %} |
| 69 | + {% set allow_park = client.park_at_cancel | default(false) | lower == 'true' %} |
| 70 | + {% set retract = client.cancel_retract | default(5.0) | abs %} |
| 71 | + ##### define park position ##### |
| 72 | + {% set park_x = "" if (client.park_at_cancel_x | default(none) is none) |
| 73 | + else "X=" ~ client.park_at_cancel_x %} |
| 74 | + {% set park_y = "" if (client.park_at_cancel_y | default(none) is none) |
| 75 | + else "Y=" ~ client.park_at_cancel_y %} |
| 76 | + {% set custom_park = park_x | length > 0 or park_y | length > 0 %} |
| 77 | + ##### end of definitions ##### |
| 78 | + # restore idle_timeout time if needed |
| 79 | + {% if printer['gcode_macro RESUME'].restore_idle_timeout > 0 %} |
| 80 | + SET_IDLE_TIMEOUT TIMEOUT={printer['gcode_macro RESUME'].restore_idle_timeout} |
| 81 | + {% endif %} |
| 82 | + {% if (custom_park or not printer.pause_resume.is_paused) and allow_park %} _TOOLHEAD_PARK_PAUSE_CANCEL {park_x} {park_y} {% endif %} |
| 83 | + _CLIENT_RETRACT LENGTH={retract} |
| 84 | + TURN_OFF_HEATERS |
| 85 | + M106 S0 |
| 86 | + {client.user_cancel_macro | default("")} |
| 87 | + SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=idle_state VALUE=False |
| 88 | + # clear pause_next_layer and pause_at_layer as preparation for next print |
| 89 | + SET_PAUSE_NEXT_LAYER ENABLE=0 |
| 90 | + SET_PAUSE_AT_LAYER ENABLE=0 LAYER=0 |
| 91 | + |
| 92 | + # bed fans off |
| 93 | + SET_FAN_SPEED FAN=Bed_Fan1 SPEED=0 |
| 94 | + SET_FAN_SPEED FAN=Bed_Fan2 SPEED=0 |
| 95 | + |
| 96 | + # run Nevermore for 3 minutes after print finishes |
| 97 | + UPDATE_DELAYED_GCODE ID=filter_off DURATION=120 |
| 98 | + |
| 99 | + CANCEL_PRINT_BASE |
| 100 | + |
| 101 | +[gcode_macro PAUSE] |
| 102 | +description: Pause the actual running print |
| 103 | +rename_existing: PAUSE_BASE |
| 104 | +gcode: |
| 105 | + ##### get user parameters or use default ##### |
| 106 | + {% set client = printer['gcode_macro _CLIENT_VARIABLE'] | default({}) %} |
| 107 | + {% set idle_timeout = client.idle_timeout | default(0) %} |
| 108 | + {% set temp = printer[printer.toolhead.extruder].target if printer.toolhead.extruder != '' else 0 %} |
| 109 | + {% set restore = False if printer.toolhead.extruder == '' |
| 110 | + else True if params.RESTORE | default(1) | int == 1 else False %} |
| 111 | + ##### end of definitions ##### |
| 112 | + SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=last_extruder_temp VALUE="{{'restore': restore, 'temp': temp}}" |
| 113 | + # set a new idle_timeout value |
| 114 | + {% if idle_timeout > 0 %} |
| 115 | + SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=restore_idle_timeout VALUE={printer.configfile.settings.idle_timeout.timeout} |
| 116 | + SET_IDLE_TIMEOUT TIMEOUT={idle_timeout} |
| 117 | + {% endif %} |
| 118 | + PAUSE_BASE |
| 119 | + {client.user_pause_macro | default("")} |
| 120 | + _TOOLHEAD_PARK_PAUSE_CANCEL {rawparams} |
| 121 | + |
| 122 | +[gcode_macro RESUME] |
| 123 | +description: Resume the actual running print |
| 124 | +rename_existing: RESUME_BASE |
| 125 | +variable_last_extruder_temp: {'restore': False, 'temp': 0} |
| 126 | +variable_restore_idle_timeout: 0 |
| 127 | +variable_idle_state: False |
| 128 | +gcode: |
| 129 | + ##### get user parameters or use default ##### |
| 130 | + {% set client = printer['gcode_macro _CLIENT_VARIABLE'] | default({}) %} |
| 131 | + {% set velocity = printer.configfile.settings.pause_resume.recover_velocity %} |
| 132 | + {% set sp_move = client.speed_move | default(velocity) %} |
| 133 | + {% set runout_resume = True if client.runout_sensor | default("") == "" # no runout |
| 134 | + else True if not printer[client.runout_sensor].enabled # sensor is disabled |
| 135 | + else printer[client.runout_sensor].filament_detected %} # sensor status |
| 136 | + {% set can_extrude = True if printer.toolhead.extruder == '' # no extruder defined in config |
| 137 | + else printer[printer.toolhead.extruder].can_extrude %} # status of active extruder |
| 138 | + {% set do_resume = False %} |
| 139 | + {% set prompt_txt = [] %} |
| 140 | + ##### end of definitions ##### |
| 141 | + #### Printer comming from timeout idle state #### |
| 142 | + {% if printer.idle_timeout.state | upper == "IDLE" or idle_state %} |
| 143 | + SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=idle_state VALUE=False |
| 144 | + {% if last_extruder_temp.restore %} |
| 145 | + # we need to use the unicode (\u00B0) for the ° as py2 env's would throw an error otherwise |
| 146 | + RESPOND TYPE=echo MSG='{"Restoring \"%s\" temperature to %3.1f\u00B0C, this may take some time" % (printer.toolhead.extruder, last_extruder_temp.temp) }' |
| 147 | + M109 S{last_extruder_temp.temp} |
| 148 | + {% set do_resume = True %} |
| 149 | + {% elif can_extrude %} |
| 150 | + {% set do_resume = True %} |
| 151 | + {% else %} |
| 152 | + RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder}' |
| 153 | + {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} |
| 154 | + {% endif %} |
| 155 | + #### Printer comming out of regular PAUSE state #### |
| 156 | + {% elif can_extrude %} |
| 157 | + {% set do_resume = True %} |
| 158 | + {% else %} |
| 159 | + RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder}' |
| 160 | + {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} |
| 161 | + {% endif %} |
| 162 | + {% if runout_resume %} |
| 163 | + {% if do_resume %} |
| 164 | + {% if restore_idle_timeout > 0 %} SET_IDLE_TIMEOUT TIMEOUT={restore_idle_timeout} {% endif %} # restore idle_timeout time |
| 165 | + {client.user_resume_macro | default("")} |
| 166 | + _CLIENT_EXTRUDE |
| 167 | + RESUME_BASE VELOCITY={params.VELOCITY | default(sp_move)} |
| 168 | + {% endif %} |
| 169 | + {% else %} |
| 170 | + RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" detects no filament, please load filament and press RESUME" % (client.runout_sensor.split(" "))[1]}' |
| 171 | + {% set _d = prompt_txt.append("\"%s\" detects no filament, please load filament and press RESUME" % (client.runout_sensor.split(" "))[1]) %} |
| 172 | + {% endif %} |
| 173 | + ##### Generate User Information box in case of abort ##### |
| 174 | + {% if not (runout_resume and do_resume) %} |
| 175 | + RESPOND TYPE=command MSG="action:prompt_begin RESUME aborted !!!" |
| 176 | + {% for element in prompt_txt %} |
| 177 | + RESPOND TYPE=command MSG='{"action:prompt_text %s" % element}' |
| 178 | + {% endfor %} |
| 179 | + RESPOND TYPE=command MSG="action:prompt_footer_button Ok|RESPOND TYPE=command MSG=action:prompt_end|info" |
| 180 | + RESPOND TYPE=command MSG="action:prompt_show" |
| 181 | + {% endif %} |
| 182 | + |
| 183 | +# Usage: SET_PAUSE_NEXT_LAYER [ENABLE=[0 | 1]] [MACRO=<name>] |
| 184 | +[gcode_macro SET_PAUSE_NEXT_LAYER] |
| 185 | +description: Enable a pause if the next layer is reached |
| 186 | +gcode: |
| 187 | + {% set pause_next_layer = printer['gcode_macro SET_PRINT_STATS_INFO'].pause_next_layer %} |
| 188 | + {% set ENABLE = params.ENABLE | default(1)|int != 0 %} |
| 189 | + {% set MACRO = params.MACRO | default(pause_next_layer.call, True) %} |
| 190 | + SET_GCODE_VARIABLE MACRO=SET_PRINT_STATS_INFO VARIABLE=pause_next_layer VALUE="{{ 'enable': ENABLE, 'call': MACRO }}" |
| 191 | + |
| 192 | +# Usage: SET_PAUSE_AT_LAYER [ENABLE=[0 | 1]] [LAYER=<number>] [MACRO=<name>] |
| 193 | +[gcode_macro SET_PAUSE_AT_LAYER] |
| 194 | +description: Enable/disable a pause if a given layer number is reached |
| 195 | +gcode: |
| 196 | + {% set pause_at_layer = printer['gcode_macro SET_PRINT_STATS_INFO'].pause_at_layer %} |
| 197 | + {% set ENABLE = params.ENABLE | int != 0 if params.ENABLE is defined |
| 198 | + else params.LAYER is defined %} |
| 199 | + {% set LAYER = params.LAYER | default(pause_at_layer.layer) | int %} |
| 200 | + {% set MACRO = params.MACRO | default(pause_at_layer.call, True) %} |
| 201 | + SET_GCODE_VARIABLE MACRO=SET_PRINT_STATS_INFO VARIABLE=pause_at_layer VALUE="{{ 'enable': ENABLE, 'layer': LAYER, 'call': MACRO }}" |
| 202 | + |
| 203 | +# Usage: SET_PRINT_STATS_INFO [TOTAL_LAYER=<total_layer_count>] [CURRENT_LAYER= <current_layer>] |
| 204 | +[gcode_macro SET_PRINT_STATS_INFO] |
| 205 | +rename_existing: SET_PRINT_STATS_INFO_BASE |
| 206 | +description: Overwrite, to get pause_next_layer and pause_at_layer feature |
| 207 | +variable_pause_next_layer: { 'enable': False, 'call': "PAUSE" } |
| 208 | +variable_pause_at_layer : { 'enable': False, 'layer': 0, 'call': "PAUSE" } |
| 209 | +gcode: |
| 210 | + {% if pause_next_layer.enable %} |
| 211 | + RESPOND TYPE=echo MSG='{"%s, forced by pause_next_layer" % pause_next_layer.call}' |
| 212 | + {pause_next_layer.call} ; execute the given gcode to pause, should be either M600 or PAUSE |
| 213 | + SET_PAUSE_NEXT_LAYER ENABLE=0 |
| 214 | + {% elif pause_at_layer.enable and params.CURRENT_LAYER is defined and params.CURRENT_LAYER | int == pause_at_layer.layer %} |
| 215 | + RESPOND TYPE=echo MSG='{"%s, forced by pause_at_layer [%d]" % (pause_at_layer.call, pause_at_layer.layer)}' |
| 216 | + {pause_at_layer.call} ; execute the given gcode to pause, should be either M600 or PAUSE |
| 217 | + SET_PAUSE_AT_LAYER ENABLE=0 |
| 218 | + {% endif %} |
| 219 | + SET_PRINT_STATS_INFO_BASE {rawparams} |
| 220 | + |
| 221 | +##### internal use ##### |
| 222 | +[gcode_macro _TOOLHEAD_PARK_PAUSE_CANCEL] |
| 223 | +description: Helper: park toolhead used in PAUSE and CANCEL_PRINT |
| 224 | +gcode: |
| 225 | + ##### get user parameters or use default ##### |
| 226 | + {% set client = printer['gcode_macro _CLIENT_VARIABLE'] | default({}) %} |
| 227 | + {% set velocity = printer.configfile.settings.pause_resume.recover_velocity %} |
| 228 | + {% set use_custom = client.use_custom_pos | default(false) | lower == 'true' %} |
| 229 | + {% set custom_park_x = client.custom_park_x | default(0.0) %} |
| 230 | + {% set custom_park_y = client.custom_park_y | default(0.0) %} |
| 231 | + {% set park_dz = client.custom_park_dz | default(2.0) | abs %} |
| 232 | + {% set sp_hop = client.speed_hop | default(15) * 60 %} |
| 233 | + {% set sp_move = client.speed_move | default(velocity) * 60 %} |
| 234 | + ##### get config and toolhead values ##### |
| 235 | + {% set origin = printer.gcode_move.homing_origin %} |
| 236 | + {% set act = printer.gcode_move.gcode_position %} |
| 237 | + {% set max = printer.toolhead.axis_maximum %} |
| 238 | + {% set cone = printer.toolhead.cone_start_z | default(max.z) %} ; height as long the toolhead can reach max and min of an delta |
| 239 | + {% set round_bed = True if printer.configfile.settings.printer.kinematics is in ['delta','polar','rotary_delta','winch'] |
| 240 | + else False %} |
| 241 | + ##### define park position ##### |
| 242 | + {% set z_min = params.Z_MIN | default(0) | float %} |
| 243 | + {% set z_park = [[(act.z + park_dz), z_min]|max, (max.z - origin.z)] | min %} |
| 244 | + {% set x_park = params.X if params.X is defined |
| 245 | + else custom_park_x if use_custom |
| 246 | + else 0.0 if round_bed |
| 247 | + else (max.x - 5.0) %} |
| 248 | + {% set y_park = params.Y if params.Y is defined |
| 249 | + else custom_park_y if use_custom |
| 250 | + else (max.y - 5.0) if round_bed and z_park < cone |
| 251 | + else 0.0 if round_bed |
| 252 | + else (max.y - 5.0) %} |
| 253 | + ##### end of definitions ##### |
| 254 | + _CLIENT_RETRACT |
| 255 | + {% if "xyz" in printer.toolhead.homed_axes %} |
| 256 | + G90 |
| 257 | + G1 Z{z_park} F{sp_hop} |
| 258 | + G1 X{x_park} Y{y_park} F{sp_move} |
| 259 | + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} |
| 260 | + {% else %} |
| 261 | + RESPOND TYPE=echo MSG='Printer not homed' |
| 262 | + {% endif %} |
| 263 | + |
| 264 | +[gcode_macro _CLIENT_EXTRUDE] |
| 265 | +description: Extrudes, if the extruder is hot enough |
| 266 | +gcode: |
| 267 | + ##### get user parameters or use default ##### |
| 268 | + {% set client = printer['gcode_macro _CLIENT_VARIABLE'] | default({}) %} |
| 269 | + {% set use_fw_retract = (client.use_fw_retract | default(false) | lower == 'true') and (printer.firmware_retraction is defined) %} |
| 270 | + {% set length = params.LENGTH | default(client.unretract) | default(1.0) | float %} |
| 271 | + {% set speed = params.SPEED | default(client.speed_unretract) | default(35) %} |
| 272 | + {% set absolute_extrude = printer.gcode_move.absolute_extrude %} |
| 273 | + ##### end of definitions ##### |
| 274 | + {% if printer.toolhead.extruder != '' %} |
| 275 | + {% if printer[printer.toolhead.extruder].can_extrude %} |
| 276 | + {% if use_fw_retract %} |
| 277 | + {% if length < 0 %} |
| 278 | + G10 |
| 279 | + {% else %} |
| 280 | + G11 |
| 281 | + {% endif %} |
| 282 | + {% else %} |
| 283 | + M83 |
| 284 | + G1 E{length} F{(speed | float | abs) * 60} |
| 285 | + {% if absolute_extrude %} |
| 286 | + M82 |
| 287 | + {% endif %} |
| 288 | + {% endif %} |
| 289 | + {% else %} |
| 290 | + RESPOND TYPE=echo MSG='{"\"%s\" not hot enough" % printer.toolhead.extruder}' |
| 291 | + {% endif %} |
| 292 | + {% endif %} |
| 293 | + |
| 294 | +[gcode_macro _CLIENT_RETRACT] |
| 295 | +description: Retracts, if the extruder is hot enough |
| 296 | +gcode: |
| 297 | + {% set client = printer['gcode_macro _CLIENT_VARIABLE'] | default({}) %} |
| 298 | + {% set length = params.LENGTH | default(client.retract) | default(1.0) | float %} |
| 299 | + {% set speed = params.SPEED | default(client.speed_retract) | default(35) %} |
| 300 | + |
| 301 | + _CLIENT_EXTRUDE LENGTH=-{length | float | abs} SPEED={speed | float | abs} |
0 commit comments