Skip to content

Klicky probe

Klicky magnetic probe — dock-attach macros, probe-attach/detach choreography, and the wrapping macros for QGL and bed mesh. Probe is attached only during measurement and parked on the dock the rest of the time.

The 7 files are split by responsibility:

  • klicky-variables.cfg — tunable dock/park positions and pickup/dropoff offsets
  • klicky-probe.cfg — base [probe] definition, pin assignments, sample count
  • klicky-macros.cfgAttach_Probe / Dock_Probe choreography
  • klicky-specific.cfg — V2.4-specific Klicky overrides (dock location, retract direction)
  • klicky-quad-gantry-level.cfgQUAD_GANTRY_LEVEL macro wrapping attach + level + detach
  • klicky-bed-mesh-calibrate.cfgBED_MESH_CALIBRATE wrapping attach + mesh + detach
  • (PROBE / Z_CALIBRATION macros come from printer.cfg)

klicky-variables.cfg

# This macro was provided by discord user Garrettwp to whom i give my thanks for sharing it with me.
# I have tweaked it a lot.
# They are based on the great Annex magprobe dockable probe macros "#Originally developed by Mental,
# modified for better use on K-series printers by RyanG and Trails", kudos to them.
# That macro as since evolved into a klipper plugin that currently is pending inclusion in klipper, 
# more information here, https://github.com/Annex-Engineering/Quickdraw_Probe/tree/main/Klipper_Macros
# User richardjm revised the macro variables and added some functions, thanks a lot
# by standing on the shoulders of giants, lets see if we can see further
#
# the current home for this version is https://github.com/jlas1/Klicky-Probe 
# the 1000 values below is to give an error instead of doing something wrong, hopefully, this won't be used is a printer larger than 1 meter

[gcode_macro _User_Variables]
variable_verbose:             True    # Enable verbose output
variable_travel_speed:         400    # how fast all other travel moves will be performed when running these macros
variable_move_accel:          1000    # how fast should the toolhead accelerate when moving
variable_dock_speed:           100    # how fast should the toolhead move when docking the probe for the final movement
variable_release_speed:         75    # how fast should the toolhead move to release the hold of the magnets after docking
variable_z_drop_speed:          40    # how fast the z will lower when moving to the z location to clear the probe

variable_safe_z:         	    25    # Minimum Z for attach/dock and homing functions
# if true it will move the bed away from the nozzle when Z is not homed
variable_enable_z_hop:        True    # set this to false for beds that fall significantly under gravity (almost to Z max)

variable_max_bed_y:            300    # maximum Bed size avoids doing a probe_accuracy outside the bed
variable_max_bed_x:            300    # maximum Bed size avoids doing a probe_accuracy outside the bed

# if a separate Z endstop switch is in
# use, specify the coordinates of the switch here (Voron).
# Set to 0 to have the probe move to center of bed
variable_z_endstop_x:         188.5
variable_z_endstop_y:         307
##home_xy_position:188.5,307

#Check the documentation on klipper Dock/Undock configuration, these are dummy values
#dock location 
#variable_docklocation_x:       39    # X Dock position
variable_docklocation_x:       4.5    # X Dock position
variable_docklocation_y:      307    # Y Dock position
variable_docklocation_z:      -128    # Z dock position (-128 for a gantry/frame mount)

#Dock move, final toolhead movement to release the probe on the dock
#it's a relative move
Variable_dockmove_x:            40  #1000
Variable_dockmove_y:             0
Variable_dockmove_z:             0
#Attach move. final toolhead movement to attach the probe on the mount
#it's a relative move
Variable_attachmove_x:           0
Variable_attachmove_y:          30
Variable_attachmove_z:           0

#Umbilical to help untangle the umbilical in difficult situations
variable_umbilical:          False    # should we untabgle the umbilical
variable_umbilical_x:           15    # X umbilical position
variable_umbilical_y:           15    # Y umbilical position

# location to park the toolhead
variable_park_toolhead:      False    # Enable toolhead parking
variable_parkposition_x:       125
variable_parkposition_y:       125
variable_parkposition_z:        30

variable_version:                1    # Helps users to update the necessary variables, do not update if the variables above are not updated

#Below this remark, you normally do not need to configure
#Attach move2
Variable_attachmove2_x:          0    # intermediate toolhead movement to attach
Variable_attachmove2_y:          0    # the probe on the dock
Variable_attachmove2_z:          0    # (can be negative)

# Do not modify below
gcode:
    {% set Mx = printer['configfile'].config["stepper_x"]["position_max"]|float %}
    {% set My = printer['configfile'].config["stepper_y"]["position_max"]|float %}
    {% set Ox = printer['configfile'].config["probe"]["x_offset"]|float %}
    {% set Oy = printer['configfile'].config["probe"]["y_offset"]|float %}
    {% set Oz = printer['configfile'].config["probe"]["z_offset"]|float %}

    # If x, y coordinates are set for z endstop, assign them
    {% if z_endstop_x != 0 or z_endstop_y != 0 %}
        SET_GCODE_VARIABLE MACRO=_Probe_Variables VARIABLE=z_endstop_x VALUE={ z_endstop_x }
        SET_GCODE_VARIABLE MACRO=_Probe_Variables VARIABLE=z_endstop_y VALUE={ z_endstop_y }

    # if no x, y coordinates for z endstop, assume probe is endstop and move toolhead to center of bed
    {% else %}
        SET_GCODE_VARIABLE MACRO=_Probe_Variables VARIABLE=z_endstop_x VALUE={ (Mx * 0.5) - Ox }
        SET_GCODE_VARIABLE MACRO=_Probe_Variables VARIABLE=z_endstop_y VALUE={ (My * 0.5) - Oy }
    {% endif %}

klicky-probe.cfg

#Simple way to include all the various klicky macros and configurations
# the current home for this configuration is https://github.com/jlas1/Klicky-Probe, please check it

#[include ./klicky-specific.cfg]                #place to put other configurations specific to your printer
[include ./klicky-variables.cfg]                #Requires
[include ./klicky-macros.cfg]                   #Required
[include ./klicky-bed-mesh-calibrate.cfg]      #bed mesh, requires klipper configuration
#[include ./klicky-screws-tilt-calculate.cfg]   #help adjust bed screws automatically
[include ./klicky-quad-gantry-level.cfg]       #level 4 Z motors
#[include ./klicky-z-tilt-adjust.cfg]           #level 2 or 3 Z motors

klicky-macros.cfg

# This macro was provided by discord user Garrettwp to whom i give my thanks for sharing it with me.
# I have tweaked it a lot.
# They are based on the great Annex magprobe dockable probe macros "#Originally developed by Mental,
# modified for better use on K-series printers by RyanG and Trails", kudos to them.
# That macro as since evolved into a klipper plugin that currently is pending inclusion in klipper, 
# more information here, https://github.com/Annex-Engineering/Quickdraw_Probe/tree/main/Klipper_Macros
# User richardjm revised the macro variables and added some functions, thanks a lot
# by standing on the shoulders of giants, lets see if we can see further
#
# the current home for this version is https://github.com/jlas1/Klicky-Probe 

[respond]

[gcode_macro _Probe_Variables]
variable_probe_attached:            False
variable_probe_state:               False
variable_probe_lock:                False
variable_z_endstop_x:               0
variable_z_endstop_y:               0
gcode:


#checks if the variable definitions are up to date
[gcode_macro _klicky_check_variables_version]
gcode:
    {% set version = printer["gcode_macro _User_Variables"].version|default(0) %}

    {% if version != 1 %}
        { action_raise_error("Please update your klicky variables, there are some functionality changes") }
    {% endif %}

[gcode_macro _exit_point]
gcode:
    {% set function  = 'pre_' ~ params.FUNCTION %}
    {% set move  = params.MOVE|default(0) %}
    {% set speed = params.SPEED|default(printer["gcode_macro _User_Variables"].travel_speed) %}
    # mandatory to save the new safe position
    M400
    SET_VELOCITY_LIMIT ACCEL={printer.configfile.settings.printer.max_accel}
    SET_VELOCITY_LIMIT ACCEL_TO_DECEL={printer.configfile.settings.printer.max_accel_to_decel}
    RESTORE_GCODE_STATE NAME={function} MOVE={move} MOVE_SPEED={speed}


[gcode_macro _entry_point]
gcode:
    {% set function  = 'pre_' ~ params.FUNCTION %}
    {% set move_accel = printer["gcode_macro _User_Variables"].move_accel|default(1000) %}
    # mandatory to save the new safe position
    M400
    SAVE_GCODE_STATE NAME={function}
    # removes the Z offset for better bed based docking
    SET_GCODE_OFFSET Z=0
    # all the macros initially assume absolute positioning
    G90
    # set a safe(sane) Acceleration
    SET_VELOCITY_LIMIT ACCEL={move_accel}

[gcode_macro _Homing_Variables]
gcode:
    {% set reset  = params.RESET|default(0) %}
    {% if reset %}
        SET_GCODE_VARIABLE MACRO=_Probe_Variables VARIABLE=probe_lock VALUE={ False }
    {% endif %}

##########################
# Attach probe and lock it
[gcode_macro Attach_Probe_Lock]
description: Attaches Klicky Probe, can only be docked after unlocking
gcode:
    Attach_Probe
    _Probe_Lock

########################
# Dock probe and lock it
[gcode_macro Dock_Probe_Unlock]
description: Docks Klicky Probe even if it was locked
gcode:
    _Probe_Unlock
    Dock_Probe

##############
# Unlock Probe
[gcode_macro _Probe_Unlock]
description: Unlocks Klicky Probe state
gcode:
    SET_GCODE_VARIABLE MACRO=_Probe_Variables VARIABLE=probe_lock VALUE={ False }

############
# Lock Probe
[gcode_macro _Probe_Lock]
description: Locks Klicky Probe state
gcode:
    SET_GCODE_VARIABLE MACRO=_Probe_Variables VARIABLE=probe_lock VALUE={ True }

######################
# Attach Probe Routine
[gcode_macro Attach_Probe]
description: Attaches Klicky Probe
gcode:
    # See if the position should be restored after the attach
    {% set goback  = params.BACK|default(0) %}
    # Get probe attach status
    {% set probe_attached = printer["gcode_macro _Probe_Variables"].probe_attached %}
    {% set probe_lock = printer["gcode_macro _Probe_Variables"].probe_lock %}
    {% set verbose = printer["gcode_macro _User_Variables"].verbose %}
    # Get Docking location
    {% set dockmove_x = printer["gcode_macro _User_Variables"].dockmove_x|default(0) %}
    {% set dockmove_y = printer["gcode_macro _User_Variables"].dockmove_y|default(0) %}
    {% set dockmove_z = printer["gcode_macro _User_Variables"].dockmove_z|default(0) %}
    {% set docklocation_x = printer["gcode_macro _User_Variables"].docklocation_x %}
    {% set docklocation_y = printer["gcode_macro _User_Variables"].docklocation_y %}
    {% set docklocation_z = printer["gcode_macro _User_Variables"].docklocation_z %}
    {% set attachmove_x = printer["gcode_macro _User_Variables"].attachmove_x|default(0) %}
    {% set attachmove_y = printer["gcode_macro _User_Variables"].attachmove_y|default(0) %}
    {% set attachmove_z = printer["gcode_macro _User_Variables"].attachmove_z|default(0) %}
    {% set attachmove2_x = printer["gcode_macro _User_Variables"].attachmove2_x|default(0) %}
    {% set attachmove2_y = printer["gcode_macro _User_Variables"].attachmove2_y|default(0) %}
    {% set attachmove2_z = printer["gcode_macro _User_Variables"].attachmove2_z|default(0) %}
    # Safe Z for travel
	{% set safe_z = printer["gcode_macro _User_Variables"].safe_z %}
	{% set enable_z_hop = printer["gcode_macro _User_Variables"].enable_z_hop %}
    # Set feedrates
    {% set travel_feedrate = printer["gcode_macro _User_Variables"].travel_speed * 60 %}
    {% set dock_feedrate = printer["gcode_macro _User_Variables"].dock_speed * 60 %}
    {% set release_feedrate = printer["gcode_macro _User_Variables"].release_speed * 60 %}
    {% set z_drop_feedrate = printer["gcode_macro _User_Variables"].z_drop_speed * 60 %}

    _entry_point function=Attach_Probe

    # If there is no undock movement, fail
    {% if dockmove_x == dockmove_y == dockmove_z == 0 %}
        { action_raise_error("No dockmove location!! To restore old behavior place 40 in dockmove_x") }
    {% endif %}
    # If there is no Attach movement, fail
    {% if attachmove_x == attachmove_y == attachmove_z == 0 %}
        { action_raise_error("No attachmove location!!  To restore old behavior place dockarmslenght value in dockmove_x") }
    {% endif %}

    # If x and y are not homed
    {% if not 'xy' in printer.toolhead.homed_axes %}
        { action_raise_error("Must Home X and Y Axis First!") }

    # If probe not attached and locked
    {% elif not probe_attached and not probe_lock %}
        {% if verbose %}
            { action_respond_info("Attaching Probe") }
        {% endif %}

        {% if not 'z' in printer.toolhead.homed_axes %}
            {% if verbose %}
                { action_respond_info("Resetting Z position to zero") }
            {% endif %}
            SET_KINEMATIC_POSITION Z=0
            {% if not enable_z_hop %} # Disables safe_z
                {% set safe_z = 0 %}
            {% endif %}
        {% endif %}

        # Prior to saving actual position, check if its necessary to move to a safe Z
        # that has enought overhead for the attached probe
        {% if printer.toolhead.position.z < safe_z %}
            {% if verbose %}
                { action_respond_info("moving to a safe Z distance") }
            {% endif %}
            G0 Z{safe_z} F{z_drop_feedrate}
        {% endif %}

        {% if not 'z' in printer.toolhead.homed_axes %}
            {% if verbose %}
                { action_respond_info("Resetting Z position to zero") }
            {% endif %}
            SET_KINEMATIC_POSITION Z=0
        {% endif %}

        {% if printer.toolhead.position.z < safe_z %}
            G0 Z{safe_z} F{z_drop_feedrate}
        {% endif %}

        _Umbilical_Path

        _entry_point function=Attach_Probe_intern

        # if necessary do some actions before moving the toolhead to the docking position
        {% if printer["gcode_macro _DeployDock"] is defined %}
            _DeployDock
        {% endif %}

        # Probe entry location
        G0 X{docklocation_x|int - attachmove_x|int - attachmove2_x|int} Y{docklocation_y|int - attachmove_y|int - attachmove2_y} F{travel_feedrate}
        {% if docklocation_z != -128 %}
            G0 Z{docklocation_z|int - attachmove_z|int - attachmove2_z|int} F{dock_feedrate}
			G0 Z{docklocation_z|int - attachmove_z|int} F{dock_feedrate}
        {% endif %}

        # Drop Probe to Probe location
        {% if docklocation_z != -128 %}
            G0 Z{docklocation_z} F{dock_feedrate}
        {% endif %}
		G0 X{docklocation_x|int - attachmove2_x|int} Y{docklocation_y|int - attachmove2_y} F{travel_feedrate}
        G0 X{docklocation_x} Y{docklocation_y} F{dock_feedrate}

        # Probe Attach
        {% if docklocation_z != -128 %}
        G0 Z{docklocation_z|int - attachmove_z|int} F{z_drop_feedrate}
        {% endif %}
        G0 X{docklocation_x|int - attachmove_x|int} Y{docklocation_y|int - attachmove_y|int} F{release_feedrate}

        # if necessary do some actions after attaching the probe
        {% if printer["gcode_macro _RetractDock"] is defined %}
            _RetractDock
        {% endif %}
		
        # Go to Z safe distance
        {% if printer.toolhead.position.z < safe_z %}
          G0 Z{safe_z} F{z_drop_feedrate}
        {% endif %}

        _Park_Toolhead

        _CheckProbe action=attach

        _exit_point function=Attach_Probe_intern move={goback}

    {% elif probe_lock %}
        {% if verbose %}
            { action_respond_info("Probe locked!") }
        {% endif %}

        # Probe attached, do nothing
        _CheckProbe action=query

    {% else %}
        {% if verbose %}
            { action_respond_info("Probe already attached!") }
        {% endif %}

        # Probe attached, do nothing
        _CheckProbe action=query

    {% endif %}

    _exit_point function=Attach_Probe

####################
# Deploy klicky dock
[gcode_macro _DeployDock]
description: Deploys the dock
gcode:

####################
# Retracts klicky dock
[gcode_macro _RetractDock]
description: Retracts the dock
gcode:

####################
# Dock Probe Routine
[gcode_macro Dock_Probe]
description: Docks Klicky Probe
gcode:
	# See if the position should be restored after the dock
    {% set goback  = params.back|default(0) %}
    # Get probe attach status
    {% set probe_attached = printer["gcode_macro _Probe_Variables"].probe_attached %}
    {% set probe_lock = printer["gcode_macro _Probe_Variables"].probe_lock %}
    {% set verbose = printer["gcode_macro _User_Variables"].verbose %}
    # Get Docking location
    {% set dockmove_x = printer["gcode_macro _User_Variables"].dockmove_x|default(0) %}
    {% set dockmove_y = printer["gcode_macro _User_Variables"].dockmove_y|default(0) %}
    {% set dockmove_z = printer["gcode_macro _User_Variables"].dockmove_z|default(0) %}
    {% set docklocation_x = printer["gcode_macro _User_Variables"].docklocation_x %}
    {% set docklocation_y = printer["gcode_macro _User_Variables"].docklocation_y %}
    {% set docklocation_z = printer["gcode_macro _User_Variables"].docklocation_z %}
    {% set attachmove_x = printer["gcode_macro _User_Variables"].attachmove_x|default(0) %}
    {% set attachmove_y = printer["gcode_macro _User_Variables"].attachmove_y|default(0) %}
    {% set attachmove_z = printer["gcode_macro _User_Variables"].attachmove_z|default(0) %}
    # Safe Z for travel
    {% set safe_z = printer["gcode_macro _User_Variables"].safe_z|float %}
    # Set feedrates
    {% set travel_feedrate = printer["gcode_macro _User_Variables"].travel_speed * 60 %}
    {% set dock_feedrate = printer["gcode_macro _User_Variables"].dock_speed * 60 %}
    {% set release_feedrate = printer["gcode_macro _User_Variables"].release_speed * 60 %}
    {% set z_drop_feedrate = printer["gcode_macro _User_Variables"].z_drop_speed * 60 %}

    # If there is no undock movement, fail
    {% if dockmove_x == dockmove_y == dockmove_z == 0 %}
        { action_raise_error("No dockmove location!! To restore old behavior place 40 in dockmove_x") }
    {% endif %}
    # If there is no Attach movement, fail
    {% if attachmove_x == attachmove_y == attachmove_z == 0 %}
        { action_raise_error("No attachmove location!!  To restore old behavior place dockarmslenght value in dockmove_x") }
    {% endif %}

    # If axis aren't homed, fail
    {% if not 'xyz' in printer.toolhead.homed_axes %}
        { action_raise_error("Must Home X, Y and Z Axis First!") }
    {% endif %}

    _entry_point function=Dock_Probe

    # If probe not attached and not locked
    {% if probe_attached and not probe_lock %}
        {% if verbose %}
            { action_respond_info("Docking Probe") }
        {% endif %}

        {% if printer.toolhead.position.z < safe_z %}
            G0 Z{safe_z} F{z_drop_feedrate}
        {% endif %}

        _Umbilical_Path

        # if necessary do some actions before moving the toolhead to the docking position
        {% if printer["gcode_macro _DeployDock"] is defined %}
            _DeployDock
        {% endif %}

        # Probe entry location
        G0 X{docklocation_x|int - attachmove_x|int} Y{docklocation_y|int - attachmove_y|int} F{travel_feedrate}
        {% if docklocation_z != -128 %}
            G0 Z{docklocation_z|int - attachmove_z|int} F{dock_feedrate}
        {% endif %}

        # Drop Probe to Probe location
        G0 X{docklocation_x} Y{docklocation_y} F{dock_feedrate}
        {% if docklocation_z != -128 %}
            G0 Z{docklocation_z} F{dock_feedrate}
        {% endif %}

        # Probe decoupling
        {% if docklocation_z != -128 %}
            G0 Z{docklocation_z|int + dockmove_z|int} F{release_feedrate}
        {% endif %}
        G0 X{docklocation_x|int + dockmove_x|int} Y{docklocation_y|int + dockmove_y|int} F{release_feedrate}
        G0 X{docklocation_x|int + dockmove_x|int - attachmove_x|int} Y{docklocation_y|int + dockmove_y|int - attachmove_y|int} F{release_feedrate}

        # if necessary do some actions after docking the probe
        {% if printer["gcode_macro _RetractDock"] is defined %}
            _RetractDock
        {% endif %}

        # Go to Z safe distance
        {% if printer.toolhead.position.z < safe_z %}
          G0 Z{safe_z} F{z_drop_feedrate}
        {% endif %}

        _Park_Toolhead

        G4 P1000
        _CheckProbe action=dock

    {% elif probe_lock %}
        {% if verbose %}
            { action_respond_info("Probe locked") }
        {% endif %}

        # Probe docked, do nothing
        _CheckProbe action=query

    {% else %}
        {% if verbose %}
            { action_respond_info("Probe already docked") }
        {% endif %}

        # Probe docked, do nothing
        _CheckProbe action=query

    {% endif %}

    _exit_point function=Dock_Probe move={goback}

#################
# Probe Calibrate
[gcode_macro PROBE_CALIBRATE]
rename_existing: _PROBE_CALIBRATE
description:Calibrate the probes z_offset with klicky automount
gcode:
    {% set safe_z = printer["gcode_macro _User_Variables"].safe_z|float %}
    {% set z_drop_feedrate = printer["gcode_macro _User_Variables"].z_drop_speed * 60 %}
    {% set travel_feedrate = printer["gcode_macro _User_Variables"].travel_speed %}
    {% set max_x = printer["gcode_macro _User_Variables"].max_bed_x %}
    {% set max_y = printer["gcode_macro _User_Variables"].max_bed_y %}
    {% set probe_offset_x = printer['configfile'].config["probe"]["x_offset"]|float %}
    {% set probe_offset_y = printer['configfile'].config["probe"]["y_offset"]|float %}

    {% if not 'xyz' in printer.toolhead.homed_axes %}
        { action_raise_error("Must Home X, Y and Z Axis First!") }
    {% endif %}

    # Protect against PROBE CALIBRATE performed from outside the bed
    {% if printer['gcode_move'].position.y > (max_y - probe_offset_y)
          or printer['gcode_move'].position.y < probe_offset_y
          or printer['gcode_move'].position.x > (max_x - probe_offset_x)
          or printer['gcode_move'].position.x < probe_offset_x %}
      { action_raise_error("Must perform PROBE_CALIBRATE with the probe above the BED!") }
    {% endif%}

    _CheckProbe action=query
    G90
    Attach_Probe back=1

    _PROBE_CALIBRATE {% for p in params
            %}{'%s=%s ' % (p, params[p])}{%
           endfor %}

    M118 moving the toolhead 20 mm from the bed
    TESTZ Z=20
    M118 remove manually the probe and continue calibration

################
# Probe Accuracy
[gcode_macro PROBE_ACCURACY]
rename_existing: _PROBE_ACCURACY
description:Probe Z-height accuracy at current XY position with klicky automount
gcode:
    {% set safe_z = printer["gcode_macro _User_Variables"].safe_z|float %}
    {% set z_drop_feedrate = printer["gcode_macro _User_Variables"].z_drop_speed * 60 %}
    {% set travel_feedrate = printer["gcode_macro _User_Variables"].travel_speed %}
    {% set max_x = printer["gcode_macro _User_Variables"].max_bed_x %}
    {% set max_y = printer["gcode_macro _User_Variables"].max_bed_y %}
    {% set probe_offset_x = printer['configfile'].config["probe"]["x_offset"]|float %}
    {% set probe_offset_y = printer['configfile'].config["probe"]["y_offset"]|float %}

    {% if not 'xyz' in printer.toolhead.homed_axes %}
        { action_raise_error("Must Home X, Y and Z Axis First!") }
    {% endif %}

    _entry_point function=PROBE_ACCURACY

    # Protect against PROBE_ACCURACY performed from outside the bed
    {% if printer['gcode_move'].position.y > (max_y - probe_offset_y)
          or printer['gcode_move'].position.y < probe_offset_y
          or printer['gcode_move'].position.x > (max_x - probe_offset_x)
          or printer['gcode_move'].position.x < probe_offset_x %}
      { action_raise_error("Must perform PROBE_ACCURACY with the probe above the BED!") }
    {% endif%}

    _CheckProbe action=query
    Attach_Probe back=1

    _PROBE_ACCURACY {% for p in params
            %}{'%s=%s ' % (p, params[p])}{%
           endfor %}

    Dock_Probe back=1										   

    _exit_point function=PROBE_ACCURACY move=1

#############################################
# Enable to SET_KINEMATIC_POSITION for Z hop
[force_move]
enable_force_move: True

#################
# Homing Override
[homing_override]
axes: xyz
gcode:
    # collect user state variables
    _User_Variables
    {% set verbose = printer["gcode_macro _User_Variables"].verbose %}
    {% set safe_z = printer["gcode_macro _User_Variables"].safe_z|float %}
    # Safe Z for travel
    {% set safe_z = printer["gcode_macro _User_Variables"].safe_z %}
    {% set enable_z_hop = printer["gcode_macro _User_Variables"].enable_z_hop %}
    {% set attachmove_x = printer["gcode_macro _User_Variables"].attachmove_x|default(0) %}
    {% set attachmove_y = printer["gcode_macro _User_Variables"].attachmove_y|default(0) %}
    {% set attachmove_z = printer["gcode_macro _User_Variables"].attachmove_z|default(0) %}
    {% set z_drop_feedrate = printer["gcode_macro _User_Variables"].z_drop_speed * 60 %}

    #checks if the variable definitions are up to date
    _klicky_check_variables_version

    # if there is no Attach movement, fail
    {% if attachmove_x == attachmove_y == attachmove_z == 0 %}
        { action_raise_error("No attachmove location!") }
    {% endif %}

    _CheckProbe action=query

    # reset parameters
    {% set home_x, home_y, home_z, leave_probe_attached = False, False, False, False %}

    {% if 'PROBE_LOCK' in params%}
        {% if verbose %}
            { action_respond_info("PROBE_LOCK = True") }
        {% endif %}
        {% set leave_probe_attached = True %}
    {% endif %}

    # which axes have been requested for homing
    {% if not 'X' in params
        and not 'Y' in params
        and not 'Z' in params %}

        {% set home_x, home_y, home_z = True, True, True %}

    {% else %}
        # Frame mount x-endstop - home Y before X
        {% if 'X' in params %}
            {% set home_x = True %}
        {% endif %}

        {% if 'Y' in params %}
            {% set home_y = True %}
        {% endif %}

        {% if 'Z' in params %}
            {% set home_z = True %}
        {% endif %}

        {% if 'X' in params
          and 'Y' in params
          and 'Z' in params %}
            # reset homing state variables
            # if homing all axes
            _Homing_Variables reset=1
         {% endif %}

    {% endif %}

    _entry_point function=homing_override

    # if Z is not homed, do not move the bed if it goes down
    {% if 'z' not in printer.toolhead.homed_axes %}
         {% if not enable_z_hop %} # Disables safe_z
            {% set safe_z = 0 %}
        {% endif %}
    {% endif %}

    {% if home_z %}
        {% if 'z' in printer.toolhead.homed_axes %}
            {% if printer.toolhead.position.z < safe_z %}
                {% if verbose %}
                    { action_respond_info("Z too low, performing ZHOP") }
                {% endif %}
                G0 Z{safe_z} F{z_drop_feedrate}
            {% endif %}
        {% else %}
            {% if verbose %}
                { action_respond_info("Z not homed, forcing full G28") }
            {% endif %}
            SET_KINEMATIC_POSITION X=0 Y=0 Z=0
            G0 Z{safe_z} F{z_drop_feedrate}
            {% set home_x, home_y, home_z = True, True, True %}
        {% endif %}
    {% endif %}

    # if the dock is oriented on the Y, first do Y endstop
    {% if attachmove_y == 0 %}
        # Home y
        {% if home_y %}
            {% if verbose %}
                { action_respond_info("Homing Y") }
            {% endif %}
            G28 Y0
        {% endif %}
        {% set home_y = False %}
    {% endif %}


    # Home x
    {% if home_x %}
        {% if verbose %}
            { action_respond_info("Homing X") }
        {% endif %}
        {% if printer["gcode_macro _HOME_X"] is defined %}
            _HOME_X
        {% else %}
            G28 X0
        {% endif %}
    {% endif %}

    # Home y
    {% if home_y %}
        {% if verbose %}
            { action_respond_info("Homing Y") }
        {% endif %}
        {% if printer["gcode_macro _HOME_Y"] is defined %}
            _HOME_Y
        {% else %}
            G28 Y0
        {% endif %}
    {% endif %}
    # Home z
    {% if home_z %}
        {% if verbose %}
            { action_respond_info("Homing Z") }
        {% endif %}

        # if probe is configured as endstop, attach it, else dock the probe if attached
        {% if printer['configfile'].config["stepper_z"]["endstop_pin"] == 'probe:z_virtual_endstop' %}
            Attach_Probe
            # if PROBE_LOCK parameter is given, Attach Probe and lock until it´s unlocked
            {% if leave_probe_attached %}
                _Probe_Lock
            {% endif %}
        {% else %}
            Dock_Probe
        {% endif %}

        _Home_Z

        # if probe is configured as endstop, dock it
        {% if printer['configfile'].config["stepper_z"]["endstop_pin"] == 'probe:z_virtual_endstop' %}
            Dock_Probe
        {% endif %}
    {% endif %}
    _CheckProbe action=query

    # park the toolhead
    _Park_Toolhead

    _exit_point function=homing_override

# Umbilical path setup
[gcode_macro _Umbilical_Path]
gcode:
    {% set umbilical = printer["gcode_macro _User_Variables"].umbilical %}
    {% set umbilical_x = printer["gcode_macro _User_Variables"].umbilical_x %}
    {% set umbilical_y = printer["gcode_macro _User_Variables"].umbilical_y %}
    {% set safe_z = printer["gcode_macro _User_Variables"].safe_z|float %}
    {% set travel_feedrate = printer["gcode_macro _User_Variables"].travel_speed * 60 %}

    {% if umbilical %}
        # Used to give the umbilical a better path to follow and coil properly if dock is tight in space
        _entry_point function=Umbilical_Path

        G0 X{umbilical_x} Y{umbilical_y} Z{safe_z} F{travel_feedrate}

        _exit_point function=Umbilical_Path
    {% endif %}

# Home Z Routine
[gcode_macro _Home_Z]
gcode:
    {% set z_endstop_x = printer["gcode_macro _Probe_Variables"].z_endstop_x %}
    {% set z_endstop_y = printer["gcode_macro _Probe_Variables"].z_endstop_y %}
    {% set safe_z = printer["gcode_macro _User_Variables"].safe_z|float %}
    {% set travel_feedrate = printer["gcode_macro _User_Variables"].travel_speed * 60 %}
    {% set z_drop_feedrate = printer["gcode_macro _User_Variables"].z_drop_speed * 60 %}
    {% set verbose = printer["gcode_macro _User_Variables"].verbose %}

    _entry_point function=Home_Z

    # if x and y are not homed yet, raise error
    {% if not 'xy' in printer.toolhead.homed_axes %}
        { action_raise_error("Must Home X and Y Axis First!") }
    {% else %}
        {% if not 'z' in printer.toolhead.homed_axes %}
            {% if verbose %}
                { action_respond_info("Resetting Z position to zero") }
            {% endif %}
            SET_KINEMATIC_POSITION Z=0
        {% endif %}

        # Move tool to safe homing position and home Z axis
        # location of z endstop
        G0 X{z_endstop_x} Y{z_endstop_y} F{travel_feedrate}
        G28 Z0
        G0 Z{safe_z} F{z_drop_feedrate}
    {% endif %}

    _exit_point function=Home_Z

# Check to see if probe is where it is supposed to be after
# attaching/docking maneuver and set homing error or shutdown
[gcode_macro _CheckProbe]
variable_probe_state: 0
gcode:
    Query_Probe
    _SetProbeState action={ params.ACTION }

# Due to how templates are evaluated, we have query endstops in one
# macro and call another macro to make decisions based on the result
[gcode_macro _SetProbeState]
gcode:
    {% set query_probe_triggered = printer.probe.last_query %}
    {% set action  = params.ACTION|default('') %}

    # If triggered (true), probe not attached
    {% if query_probe_triggered %}
        SET_GCODE_VARIABLE MACRO=_Probe_Variables VARIABLE=probe_attached VALUE={ False }
    {% else %}
        # If not triggered (false), probe attached
        SET_GCODE_VARIABLE MACRO=_Probe_Variables VARIABLE=probe_attached VALUE={ True }
    {% endif %}

    {% if action == 'query' %}
          SET_GCODE_VARIABLE MACRO=_Probe_Variables VARIABLE=probe_state VALUE={ query_probe_triggered }
    {% endif %}

    # If probe fails to attach/detach

    # If not docked
    {% if not query_probe_triggered and action == 'dock' %}
        { action_raise_error("Probe dock failed!") }
    {% endif %}

    # If not attached
    {% if query_probe_triggered and action == 'attach' %}
        { action_raise_error("Probe attach failed!") }
    {% endif %}

# Park Toolhead Routine
[gcode_macro _Park_Toolhead]
gcode:
    {% set park_toolhead = printer["gcode_macro _User_Variables"].park_toolhead %}
    {% set parkposition_x = printer["gcode_macro _User_Variables"].parkposition_x %}
    {% set parkposition_y = printer["gcode_macro _User_Variables"].parkposition_y %}
    {% set parkposition_z = printer["gcode_macro _User_Variables"].parkposition_z %}
    {% set travel_feedrate = printer["gcode_macro _User_Variables"].travel_speed * 60 %}
    {% set verbose = printer["gcode_macro _User_Variables"].verbose %}

    _entry_point function=Park_Toolhead

    {% if park_toolhead and 'xyz' in printer.toolhead.homed_axes %}
        {% if verbose %}
            { action_respond_info("Parking Toolhead") }
        {% endif %}
        G0 X{parkposition_x} Y{parkposition_y} Z{parkposition_z} F{travel_feedrate}
    {% endif %}
    _exit_point function=Park_Toolhead

klicky-specific.cfg

klicky-quad-gantry-level.cfg

# This macro was provided by discord user Garrettwp to whom i give my thanks for sharing it with me.
# I have tweaked it a lot.
#
# this macro is  based on the great Annex magprobe dockable probe macros "#Originally developed by Mental, modified for better use on K-series printers by RyanG and Trails"
# that macro as since evolved into a klipper plugin that currently is pending inclusion in klipper
# more information here https://github.com/Annex-Engineering/Quickdraw_Probe/tree/main/Klipper_Macros
#
# by standing on the shoulders of giants, lets see if we can see further
# User richardjm revised the macro variables and added some functions, thanks a lot
# This macro home is https://github.com/jlas1/Klicky-Probe

###################
# Quad Gantry Level
[gcode_macro QUAD_GANTRY_LEVEL]
rename_existing: _QUAD_GANTRY_LEVEL
description: Conform a moving, twistable gantry to the shape of a stationary bed with klicky automount
gcode:
    {% set V = printer["gcode_macro _User_Variables"].verbose %}
    {% if V %}
        { action_respond_info("QG Level") }
    {% endif %}

    _CheckProbe action=query
	G90
    Attach_Probe

    _QUAD_GANTRY_LEVEL {% for p in params
            %}{'%s=%s ' % (p, params[p])}{%
            endfor %}
    Dock_Probe

klicky-bed-mesh-calibrate.cfg

# This macro was provided by discord user Garrettwp to whom i give my thanks for sharing it with me.
# I have tweaked it a lot.
# They are based on the great Annex magprobe dockable probe macros "#Originally developed by Mental,
# modified for better use on K-series printers by RyanG and Trails", kudos to them.
# That macro as since evolved into a klipper plugin that currently is pending inclusion in klipper, 
# more information here, https://github.com/Annex-Engineering/Quickdraw_Probe/tree/main/Klipper_Macros
# User richardjm revised the macro variables and added some functions, thanks a lot
# by standing on the shoulders of giants, lets see if we can see further
#
# the current home for this version is https://github.com/jlas1/Klicky-Probe 

###################
# Bed mesh calibrate
[gcode_macro BED_MESH_CALIBRATE]
rename_existing: _BED_MESH_CALIBRATE
description: Perform Mesh Bed Leveling with klicky automount
gcode:

    {% set V = printer["gcode_macro _User_Variables"].verbose %}
    {% if V %}
        { action_respond_info("Bed Mesh Calibrate") }
    {% endif %}

    _CheckProbe action=query
	G90
    Attach_Probe

    _BED_MESH_CALIBRATE {% for p in params
           %}{'%s=%s ' % (p, params[p])}{%
          endfor %}

    Dock_Probe