# 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
# User sporkus added led status notifications
# Thanks to all who helped,
# 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_probe_z_homed:             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 _KlickyDebug]
gcode:
    {% set message  = params.MSG %}
    {% set debug = printer["gcode_macro _User_Variables"].debug|default(False) %}

    {% if debug %}
        { action_respond_info(message) }
    {% endif %}


[gcode_macro _exit_point]
gcode:
    {% set function  = 'pre_' ~ params.FUNCTION %}
    {% set move  = params.MOVE|default(0) %}
    {% set speed = 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}
    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:
    _KlickyDebug msg="_Probe_Lock setting probe_lock variable to False"
    SET_GCODE_VARIABLE MACRO=_Probe_Variables VARIABLE=probe_lock VALUE={ False }

############
# Lock Probe
[gcode_macro _Probe_Lock]
description: Locks Klicky Probe state
gcode:
    _KlickyDebug msg="_Probe_Lock setting probe_lock variable to True"
    SET_GCODE_VARIABLE MACRO=_Probe_Variables VARIABLE=probe_lock VALUE={ True }

###################
# Klicky Dock Servo Deploy

[gcode_macro _DeployKlickyDock]
description: Deploys Klicky servo-controlled dock
gcode:
    {% set enable_dock_servo = printer["gcode_macro _User_Variables"].enable_dock_servo|default(False) %}
    {% set servo_delay = printer["gcode_macro _User_Variables"].servo_delay|default(1000)|int %}
    {% set servo_name = printer["gcode_macro _User_Variables"].servo_name %}
    {% set servo_deploy = printer["gcode_macro _User_Variables"].servo_deploy|default(360)|float %}

    #wait for all the moves to complete
    M400
    {% if enable_dock_servo != False %}
        _KlickyDebug msg="_DeployKlickyDock Klicky servo configuration enabled"
        {% if servo_deploy == 360 %}
            { action_raise_error("Klicky: servo active on klicky-variables, but no servo deploy angle specified") }
        {% endif %}
        _KlickyDebug msg="_DeployKlickyDock SET_SERVO SERVO={servo_name|string} ANGLE={servo_deploy}"
        SET_SERVO SERVO={servo_name|string} ANGLE={servo_deploy}
        M400
        G4 P{servo_delay}
        _KlickyDebug msg="_DeployKlickyDock SET_SERVO SERVO={servo_name|string} WIDTH=0"
        SET_SERVO SERVO={servo_name|string} WIDTH=0
    {% elif printer["gcode_macro _DeployDock"] is defined %}
        _KlickyDebug msg="_DeployKlickyDock calling _DeployDock"
        _DeployDock
    {% endif %}

####################
# Dock Servo Retract

[gcode_macro _RetractKlickyDock]
description: Retracts Klicky servo-controlled dock
gcode:
    {% set enable_dock_servo = printer["gcode_macro _User_Variables"].enable_dock_servo|default(False) %}
    {% set servo_delay = printer["gcode_macro _User_Variables"].servo_delay|default(1000)|int %}
    {% set servo_name = printer["gcode_macro _User_Variables"].servo_name %}
    {% set servo_retract = printer["gcode_macro _User_Variables"].servo_retract|default(360)|float %}

    #wait for all the moves to complete
    M400
    {% if enable_dock_servo != False %}
        _KlickyDebug msg="_RetractKlickyDock Klicky servo configuration enabled"
        {% if servo_retract == 360 %}
            { action_raise_error("Klicky: servo active on klicky-variables, but no servo retract angle specified") }
        {% endif %}
        _KlickyDebug msg="_RetractKlickyDock SET_SERVO SERVO={servo_name|string} ANGLE={servo_retract}"
        SET_SERVO SERVO={servo_name|string} ANGLE={servo_retract}
        M400
        G4 P{servo_delay}
        _KlickyDebug msg="_RetractKlickyDock SET_SERVO SERVO={servo_name|string} WIDTH=0"
        SET_SERVO SERVO={servo_name|string} WIDTH=0
    {% elif printer["gcode_macro _RetractDock"] is defined %}
        _KlickyDebug msg="_RetractKlickyDock calling _RetractDock"
        _RetractDock
    {% endif %}


######################
# 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)|float %}
    {% set dockmove_y = printer["gcode_macro _User_Variables"].dockmove_y|default(0)|float %}
    {% set dockmove_z = printer["gcode_macro _User_Variables"].dockmove_z|default(0)|float %}
    {% set docklocation_x = printer["gcode_macro _User_Variables"].docklocation_x|float %}
    {% set docklocation_y = printer["gcode_macro _User_Variables"].docklocation_y|float %}
    {% set docklocation_z = printer["gcode_macro _User_Variables"].docklocation_z|float %}
    {% set attachmove_x = printer["gcode_macro _User_Variables"].attachmove_x|default(0)|float %}
    {% set attachmove_y = printer["gcode_macro _User_Variables"].attachmove_y|default(0)|float %}
    {% set attachmove_z = printer["gcode_macro _User_Variables"].attachmove_z|default(0)|float %}
    {% set attachmove2_x = printer["gcode_macro _User_Variables"].attachmove2_x|default(0)|float %}
    {% set attachmove2_y = printer["gcode_macro _User_Variables"].attachmove2_y|default(0)|float %}
    {% set attachmove2_z = printer["gcode_macro _User_Variables"].attachmove2_z|default(0)|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 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 %}
    {% set bypass_probe_docking = printer["gcode_macro _User_Variables"].bypass_probe_docking|default(False) %}

    _entry_point function=Attach_Probe

    {% if bypass_probe_docking == False %}

        # 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!") }
            _KlickyDebug msg="Attach_Probe Axis homed"

        # If probe not attached and locked
        {% elif not probe_attached and not probe_lock %}
            _KlickyDebug msg="Attach_Probe going to attach probe"
            {% if verbose %}
                { action_respond_info("Attaching Probe") }
            {% endif %}
            _KLICKY_STATUS_BUSY

            {% if not 'z' in printer.toolhead.homed_axes %}
                {% if verbose %}
                    { action_respond_info("Resetting Z position to zero") }
                {% endif %}
                _KlickyDebug msg="Attach_Probe Z not homed, setting position as X=Y=Z=0"
                SET_KINEMATIC_POSITION Z=0
                {% if not enable_z_hop %} # Disables safe_z
                    _KlickyDebug msg="Attach_Probe z_hop disabled"
                    {% 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.gcode_move.gcode_position.z < safe_z %}
                _KlickyDebug msg="Attach_Probe toolhead too low, raising it to {safe_z}mm from {printer.gcode_move.gcode_position.z}mm"
                {% 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 %} #duplicate??
                {% if verbose %}
                    { action_respond_info("Resetting Z position to zero, duplicate?") }
                {% endif %}
                _KlickyDebug msg="Attach_Probe Z not homed, setting position as X=Y=Z=0"
                SET_KINEMATIC_POSITION Z=0
            {% endif %}

            {% if printer.gcode_move.gcode_position.z < safe_z %} #duplicate??
                _KlickyDebug msg="Attach_Probe toolhead too low, raising it to {safe_z}mm from {printer.gcode_move.gcode_position.z}mm"
                G0 Z{safe_z} F{z_drop_feedrate}
            {% endif %}

            _Umbilical_Path

            _entry_point function=Attach_Probe_intern

            # Probe entry location
            _KlickyDebug msg="Attach_Probe moving near the dock with G0 X{docklocation_x - attachmove_x - attachmove2_x} Y{docklocation_y - attachmove_y - attachmove2_y} F{travel_feedrate}"
            G0 X{docklocation_x - attachmove_x - attachmove2_x} Y{docklocation_y - attachmove_y - attachmove2_y} F{travel_feedrate}
            {% if docklocation_z != -128 %}
                _KlickyDebug msg="Attach_Probe moving near the dock with G0 Z{docklocation_z - attachmove_z - attachmove2_z} F{dock_feedrate}"
                G0 Z{docklocation_z - attachmove_z - attachmove2_z} F{dock_feedrate}
                _KlickyDebug msg="Attach_Probe moving near the dock with G0 Z{docklocation_z - attachmove_z} F{dock_feedrate}"
                G0 Z{docklocation_z - attachmove_z} F{dock_feedrate}
				{% endif %}
            # if necessary do some actions before moving the toolhead to dock
            _DeployKlickyDock
                              
            # Drop Probe to Probe location
            {% if docklocation_z != -128 %}
                _KlickyDebug msg="Attach_Probe moving to the dock with G0 Z{docklocation_z} F{dock_feedrate}"
                G0 Z{docklocation_z} F{dock_feedrate}
            {% endif %}
            _KlickyDebug msg="Attach_Probe moving to the dock with G0 X{docklocation_x - attachmove2_x} Y{docklocation_y - attachmove2_y} F{dock_feedrate}"
            G0 X{docklocation_x - attachmove2_x} Y{docklocation_y - attachmove2_y} F{dock_feedrate}
            _KlickyDebug msg="Attach_Probe moving to the dock with G0 X{docklocation_x} Y{docklocation_y} F{dock_feedrate}"
            G0 X{docklocation_x} Y{docklocation_y} F{dock_feedrate}
            # Probe Attached
            {% if docklocation_z != -128 %}
                _KlickyDebug msg="Attach_Probe moving from the dock to G0 Z{docklocation_z - attachmove_z} F{z_drop_feedrate}"
                G0 Z{docklocation_z - attachmove_z} F{z_drop_feedrate}
            {% endif %}
            _KlickyDebug msg="Attach_Probe moving from the dock to G0 X{docklocation_x - attachmove_x} Y{docklocation_y - attachmove_y} F{release_feedrate}"
            G0 X{docklocation_x - attachmove_x} Y{docklocation_y - attachmove_y} F{release_feedrate}
            # if necessary do some actions after attaching the probe
            _RetractKlickyDock
            ## Go to Z safe distance
            {% if ((printer.gcode_move.gcode_position.z < safe_z) or (docklocation_z != -128 and docklocation_z < safe_z ))%}
              _KlickyDebug msg="Attach_Probe moving to a safe Z position: G0 Z{safe_z} F{z_drop_feedrate} from {printer.gcode_move.gcode_position.z}"
              G0 Z{safe_z} F{z_drop_feedrate}
            {% endif %}

            _Park_Toolhead

            _CheckProbe action=attach

            _exit_point function=Attach_Probe_intern move={goback}
            _KLICKY_STATUS_READY

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

            # Probe attached, do nothing
            _KlickyDebug msg="Attach_Probe probe locked not attaching probe"
            _CheckProbe action=query

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

            # Probe attached, do nothing
            _KlickyDebug msg="Attach_Probe probe already attached, doing nothing"
            _CheckProbe action=query

        {% endif %}

        _exit_point function=Attach_Probe
    {% else %}
        _KlickyDebug msg="Attach_Probe probe docking bypassed, doing nothing"
    {% endif %}


####################
# 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)|float %}
    {% set dockmove_y = printer["gcode_macro _User_Variables"].dockmove_y|default(0)|float %}
    {% set dockmove_z = printer["gcode_macro _User_Variables"].dockmove_z|default(0)|float %}
    {% set docklocation_x = printer["gcode_macro _User_Variables"].docklocation_x|float %}
    {% set docklocation_y = printer["gcode_macro _User_Variables"].docklocation_y|float %}
    {% set docklocation_z = printer["gcode_macro _User_Variables"].docklocation_z|float %}
    {% set attachmove_x = printer["gcode_macro _User_Variables"].attachmove_x|default(0)|float %}
    {% set attachmove_y = printer["gcode_macro _User_Variables"].attachmove_y|default(0)|float %}
    {% set attachmove_z = printer["gcode_macro _User_Variables"].attachmove_z|default(0)|float %}
    # 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 %}
    {% set bypass_probe_docking = printer["gcode_macro _User_Variables"].bypass_probe_docking|default(False) %}
    {% if bypass_probe_docking == True %}
        _KlickyDebug msg="Attach_Probe probe docking bypassed, doing nothing"
    {% endif %}

    {% if bypass_probe_docking != True %}
        _entry_point function=Dock_Probe

        # If probe not attached and not locked
        {% if probe_attached and not probe_lock %}
          _KLICKY_STATUS_BUSY
          {% if printer.gcode_move.gcode_position.z < safe_z %}
              _KlickyDebug msg="Dock_Probe toolhead too low, raising it to {safe_z}mm from {printer.gcode_move.gcode_position.z}mm"
              G0 Z{safe_z} F{z_drop_feedrate}
          {% endif %}
          _Umbilical_Path

          # Probe entry location
          _KlickyDebug msg="Dock_Probe moving near the dock with G0 X{docklocation_x - attachmove_x} Y{docklocation_y - attachmove_y} F{travel_feedrate}"
          G0 X{docklocation_x - attachmove_x} Y{docklocation_y - attachmove_y} F{travel_feedrate}

          {% if docklocation_z != -128 %}
            _KlickyDebug msg="Dock_Probe moving near the dock with G0 Z{docklocation_z - attachmove_z} F{dock_feedrate}"
            G0 Z{docklocation_z - attachmove_z} F{dock_feedrate}
          {% endif %}

          # if necessary do some actions before moving the toolhead to dock
          _DeployKlickyDock

          # Drop Probe to Probe location
          _KlickyDebug msg="Dock_Probe moving to the dock with G0 X{docklocation_x} Y{docklocation_y} F{dock_feedrate}"

          G0 X{docklocation_x} Y{docklocation_y} F{dock_feedrate}
          {% if docklocation_z != -128 %}
            _KlickyDebug msg="Attach_Probe moving to the dock with G0 Z{docklocation_z} F{dock_feedrate}"
            G0 Z{docklocation_z} F{dock_feedrate}
          {% endif %}

          # Probe decoupling
          {% if docklocation_z != -128 %}
            _KlickyDebug msg="Dock_Probe moving from the dock to G0 Z{docklocation_z + dockmove_z} F{release_feedrate}"
            G0 Z{docklocation_z + dockmove_z} F{release_feedrate}
          {% endif %}

          _KlickyDebug msg="Dock_Probe moving from the dock to G0 X{docklocation_x + dockmove_x} Y{docklocation_y + dockmove_y} F{release_feedrate}"
          G0 X{docklocation_x + dockmove_x} Y{docklocation_y + dockmove_y} F{release_feedrate}

          #Do an extra move away
          _KlickyDebug msg="Dock_Probe moving away from the dock to G0 X{docklocation_x + dockmove_x - attachmove_x} Y{docklocation_y + dockmove_y - attachmove_y} F{release_feedrate}"
          G0 X{docklocation_x + dockmove_x - attachmove_x} Y{docklocation_y + dockmove_y - attachmove_y} F{release_feedrate}

	  # if necessary do some actions after attaching the probe
          _RetractKlickyDock

	  ## Go to Z safe distance
          {% if (printer.gcode_move.gcode_position.z < safe_z) %}
            _KlickyDebug msg="Dock_Probe moving to a safe Z position: G0 Z{safe_z} F{z_drop_feedrate} from {printer.gcode_move.gcode_position.z}"
            G0 Z{safe_z} F{z_drop_feedrate}
          {% endif %}

          _Park_Toolhead

          G4 P1000
          _CheckProbe action=dock
          _KLICKY_STATUS_READY

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

            # Probe docked, do nothing
            _KlickyDebug msg="Dock_Probe probe locked not docking probe"
            _CheckProbe action=query

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

            # Probe docked, do nothing
            _KlickyDebug msg="Dock_Probe probe already docked, doing nothing"
            _CheckProbe action=query

        {% endif %}

        _exit_point function=Dock_Probe move={goback}
    {% else %}
        _KlickyDebug msg="Dock_Probe probe docking bypassed, doing nothing"
    {% endif %}


#################
# 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 max_x = printer["gcode_macro _User_Variables"].max_bed_x|float %}
    {% set max_y = printer["gcode_macro _User_Variables"].max_bed_y|float %}
    {% set probe_offset_x = printer['configfile'].config["probe"]["x_offset"]|float %}
    {% set probe_offset_y = printer['configfile'].config["probe"]["y_offset"]|float %}
    {% set bypass_probe_docking = printer["gcode_macro _User_Variables"].bypass_probe_docking|default(False) %}


    {% if not 'xyz' in printer.toolhead.homed_axes %}
        { action_raise_error("Must Home X, Y and Z Axis First!") }
    {% endif %}
    _KlickyDebug msg="probe_calibrate Axis homed"
    _KlickyDebug msg="probe_calibrate Variables max_x={max_x},max_y={max_y},probe_offset_x={probe_offset_x},probe_offset_y={probe_offset_y}"

    # 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, check klicky_variables bed size!") }
    {% endif %}

    {% if bypass_probe_docking == False %}
        _CheckProbe action=query
        G90
        Attach_Probe back=1
        _KLICKY_STATUS_CALIBRATING_Z

        _KlickyDebug msg="probe_calibrate calling klipper probe_calibrate"
        _PROBE_CALIBRATE {% for p in params
                %}{'%s=%s ' % (p, params[p])}{%
               endfor %}

        M118 moving the toolhead 20 mm from the bed
        _KlickyDebug msg="probe_calibrate Moving Z up by 20mm"
        TESTZ Z=20
        M118 remove manually the probe and continue calibration
        _KLICKY_STATUS_READY
    {% else %}
        _KLICKY_STATUS_CALIBRATING_Z
        _KlickyDebug msg="probe_calibrate calling klipper probe_calibrate"
        _PROBE_CALIBRATE {% for p in params
                %}{'%s=%s ' % (p, params[p])}{%
               endfor %}
        _KLICKY_STATUS_READY
    {% endif %}

################
# 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 max_x = printer["gcode_macro _User_Variables"].max_bed_x|float %}
    {% set max_y = printer["gcode_macro _User_Variables"].max_bed_y|float %}
    {% 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 %}
    _KlickyDebug msg="probe_accuracy Axis homed"
    _KlickyDebug msg="probe_accuracy Variables max_x={max_x},max_y={max_y},probe_offset_x={probe_offset_x},probe_offset_y={probe_offset_y}"

    _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, check klicky_variables bed size!") }
    {% endif%}

    _CheckProbe action=query
    Attach_Probe back=1

    _KlickyDebug msg="probe_accuracy calling klipper probe accuracy"
    _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 kinematic_z = 0 %}
    {% set dock_on_zhome = printer["gcode_macro _User_Variables"].dock_on_zhome|default(True) %}
    {% set attachmove_y = printer["gcode_macro _User_Variables"].attachmove_y|default(0)|float %}
    {% set z_drop_feedrate = printer["gcode_macro _User_Variables"].z_drop_speed * 60 %}
    {% set travel_feedrate = printer["gcode_macro _User_Variables"].travel_speed * 60 %}
    {% set home_backoff_x = printer["gcode_macro _User_Variables"].home_backoff_x|default(0)|float %}
    {% set home_backoff_y = printer["gcode_macro _User_Variables"].home_backoff_y|default(0)|float %}
    {% set override_homing = printer["gcode_macro _User_Variables"].override_homing|default('') %}

    #checks if the variable definitions are up to date
    _klicky_check_variables_version

    _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 %}
        _KlickyDebug msg="homing_override going to home all axes"

    {% else %}
        {% if 'X' in params %}
            {% set home_x = True %}
             _KlickyDebug msg="homing_override going to home X"

        {% endif %}

        {% if 'Y' in params %}
            {% set home_y = True %}
            _KlickyDebug msg="homing_override going to home Y"
        {% endif %}

        {% if 'Z' in params %}
            {% set home_z = True %}
            _KlickyDebug msg="homing_override going to home Z"
        {% 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
            _KlickyDebug msg="homing_override going to home all axes"
         {% endif %}

    {% endif %}

    _entry_point function=homing_override
    _KLICKY_STATUS_HOMING

    # if Z is not homed, do not move the bed if it goes down
    {% if 'z' not in printer.toolhead.homed_axes %}
         {% if enable_z_hop == False %} # Disables safe_z
            _KlickyDebug msg="homing_override z_hop disabled"
            #preserve safe_z to use as the SET KINEMATIC Z position, so that the toolhead does not move to pick up the probe
            {% set kinematic_z = safe_z %}
            {% set safe_z = safe_z %}
        {% endif %}
    {% endif %}

    #On the first G28 after motors losing power, moves the Z to safe_z distance, if z_hop is enabled
    {% if 'x' not in printer.toolhead.homed_axes and 'y' not in printer.toolhead.homed_axes and 'z' not in printer.toolhead.homed_axes%}
        {% if verbose %}
            { action_respond_info("No axis homed") }
        {% endif %}
        _KlickyDebug msg="homing_override no axis homed, setting position as X=Y=0 Z={kinematic_z}"
        SET_KINEMATIC_POSITION X=0 Y=0 Z={kinematic_z}
        M400
        _KlickyDebug msg="homing_override moving toolhead to {safe_z}mm from {printer.gcode_move.gcode_position.z}mm"
        {% if verbose %}
            { action_respond_info("moving to a safe Z distance") }
        {% endif %}
        G0 Z{safe_z} F{z_drop_feedrate}
    	{% if home_z != True %} 
          _KlickyDebug msg="homing_override clearing axis homed state if not already homing Z"
          M84
          {% endif %}
    {% else %}
        _KlickyDebug msg="All axis homed"
        {% if printer.gcode_move.gcode_position.z > safe_z %} 
          {% set safe_z = printer.gcode_move.gcode_position.z|float %}
          _KlickyDebug msg="Setting Safe_z to {printer.gcode_move.gcode_position.z}mm as Z is now above configured safe_z"
        {% endif %}
    {% endif %}

    {% if home_z %}
        {% if 'x' not in printer.toolhead.homed_axes and 'y' not in printer.toolhead.homed_axes%}
            {% if verbose %}
                { action_respond_info("X or Y not homed, forcing full G28") }
            {% endif %}
            {% 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 and override_homing == '' ) or (override_homing == 'Y'))%}
        # Home y
        {% if home_y %}
            {% if override_homing == 'Y' %}
              _KlickyDebug msg="homing_override Y homing first override, due to override_homing = Y"
            {% else %}
              _KlickyDebug msg="homing_override Y homing first override, due to attachmove_y = 0"
            {% endif %}
            {% if verbose %}
                { action_respond_info("Homing Y") }
            {% endif %}
            {% if 'z' in printer.toolhead.homed_axes and printer.gcode_move.gcode_position.z < safe_z %}
                _KlickyDebug msg="homing_override moving toolhead to {safe_z}mm from {printer.gcode_move.gcode_position.z}mm in Y homing seq"
                {% if verbose %}
                    { action_respond_info("moving to a safe Z distance") }
                {% endif %}
                G0 Z{safe_z} F{z_drop_feedrate}
            {% endif %}
            {% if printer["gcode_macro _HOME_Y"] is defined %}
                _KlickyDebug msg="homing_override calling _HOME_Y external script to handle the Y homing"
                _HOME_Y
            {% else %}
                _KlickyDebug msg="homing_override Homing Y G28 Y0"
                G28 Y0
                # does it need to back away from the home position
                {% if home_backoff_y != 0 %}
                    {% if (printer.configfile.settings.stepper_y.position_endstop > (printer.configfile.settings.stepper_y.position_min|default(0) + printer.configfile.settings.stepper_y.position_max)/2) %}
                        _KlickyDebug msg="homing_override backing off Y endstop, G0 Y{printer.configfile.settings.stepper_y.position_endstop-home_backoff_y} F{travel_feedrate}"
                        G0 Y{printer.configfile.settings.stepper_y.position_endstop - home_backoff_y} F{travel_feedrate}
                    {% else %}
                        _KlickyDebug msg="homing_override backing off Y endstop, G0 Y{printer.configfile.settings.stepper_y.position_endstop + home_backoff_y} F{travel_feedrate}"
                        G0 Y{printer.configfile.settings.stepper_y.position_endstop + home_backoff_y} F{travel_feedrate}
                    {%endif %}
                {%endif %}
            {% endif %}
        {% endif %}
        {% set home_y = False %}
    {% endif %}


    # Home x
    {% if home_x %}
        {% if verbose %}
            { action_respond_info("Homing X") }
        {% endif %}
        {% if 'z' in printer.toolhead.homed_axes and printer.gcode_move.gcode_position.z < safe_z %}
            _KlickyDebug msg="homing_override moving toolhead to {safe_z}mm from {printer.gcode_move.gcode_position.z}mm in X homing seq"
            {% if verbose %}
                { action_respond_info("moving to a safe Z distance") }
            {% endif %}
            G0 Z{safe_z} F{z_drop_feedrate}
        {% endif %}
        {% if printer["gcode_macro _HOME_X"] is defined %}
            _KlickyDebug msg="homing_override calling _HOME_X external script to handle the X homing"
            _HOME_X
        {% else %}
            _KlickyDebug msg="homing_override Homing X, G28 X0"
            G28 X0
            # does it need to back away from the home position
            {% if home_backoff_x != 0 %}
                {% if (printer.configfile.settings.stepper_x.position_endstop > (printer.configfile.settings.stepper_x.position_min|default(0) + printer.configfile.settings.stepper_x.position_max)/2) %}
                    _KlickyDebug msg="homing_override backing off X endstop, G0 X{printer.configfile.settings.stepper_x.position_endstop - home_backoff_x} F{travel_feedrate}"
                    G0 X{printer.configfile.settings.stepper_x.position_endstop - home_backoff_x} F{travel_feedrate}
                {% else %}
                    _KlickyDebug msg="homing_override backing off X endstop, G0 X{printer.configfile.settings.stepper_x.position_endstop + home_backoff_x} F{travel_feedrate}"
                    G0 X{printer.configfile.settings.stepper_x.position_endstop + home_backoff_x} F{travel_feedrate}
                {%endif %}
            {%endif %}
        {% endif %}
    {% endif %}

    # Home y
    {% if home_y %}
        {% if verbose %}
            { action_respond_info("Homing Y") }
        {% endif %}
        {% if 'z' in printer.toolhead.homed_axes and printer.gcode_move.gcode_position.z < safe_z %}
            _KlickyDebug msg="homing_override moving toolhead to {safe_z}mm from {printer.gcode_move.gcode_position.z}mm in Y homing seq"
            {% if verbose %}
                { action_respond_info("moving to a safe Z distance") }
            {% endif %}
            G0 Z{safe_z} F{z_drop_feedrate}
        {% endif %}
        {% if printer["gcode_macro _HOME_Y"] is defined %}
            _KlickyDebug msg="homing_override calling _HOME_Y external script to handle the Y homing"
            _HOME_Y
        {% else %}
          _KlickyDebug msg="homing_override Homing Y, G28 Y0"
            G28 Y0
            {% if home_backoff_y != 0 %}
                {% if (printer.configfile.settings.stepper_y.position_endstop > (printer.configfile.settings.stepper_y.position_min|default(0) + printer.configfile.settings.stepper_y.position_max)/2) %}
                    _KlickyDebug msg="homing_override backing off Y endstop, G0 Y{printer.configfile.settings.stepper_y.position_endstop - home_backoff_y} F{travel_feedrate}"
                    G0 Y{printer.configfile.settings.stepper_y.position_endstop - home_backoff_y} F{travel_feedrate}
                {% else %}
                    _KlickyDebug msg="homing_override backing off Y endstop, G0 Y{printer.configfile.settings.stepper_y.position_endstop + home_backoff_y} F{travel_feedrate}"
                    G0 Y{printer.configfile.settings.stepper_y.position_endstop + home_backoff_y} F{travel_feedrate}
                {%endif %}
            {%endif %}
        {% endif %}
    {% endif %}
    # Home z
    {% if home_z %}
        {% if verbose %}
            { action_respond_info("Homing Z") }
        {% endif %}
        {% if 'z' in printer.toolhead.homed_axes and printer.gcode_move.gcode_position.z < safe_z %}
            _KlickyDebug msg="homing_override moving toolhead to {safe_z}mm from {printer.gcode_move.gcode_position.z}mm in Y homing seq"
            {% if verbose %}
                { action_respond_info("moving to a safe Z distance") }
            {% endif %}
            G0 Z{safe_z} F{z_drop_feedrate}
        {% endif %}

        # if probe is configured as endstop, attach it, else check if the probe needs to be docked if attached
        {% if 'z_virtual_endstop' in printer['configfile'].config["stepper_z"]["endstop_pin"] %}
            _KlickyDebug msg="homing_override probe configured as a virtual Z endstop attaching probe"
            Attach_Probe
            # if PROBE_LOCK parameter is given, Attach Probe and lock until it´s unlocked
            {% if leave_probe_attached %}
                _Probe_Lock
            {% endif %}
        {% elif dock_on_zhome == True %}
            Dock_Probe
        {% endif %}

        _Home_Z_

        # if probe is configured as endstop, dock it
        {% if 'z_virtual_endstop' in printer['configfile'].config["stepper_z"]["endstop_pin"] %}
            _KlickyDebug msg="homing_override probe no longer required, docking probe"
            Dock_Probe
        {% elif dock_on_zhome == False %}
            Dock_Probe
        {% endif %}
    {% endif %}
    _CheckProbe action=query

    # park the toolhead
    _Park_Toolhead

    _exit_point function=homing_override
    _KLICKY_STATUS_READY

# 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

        _KlickyDebug msg="_Umbilical_Path moving to G0 X{umbilical_x} Y{umbilical_y} Z{safe_z} F{travel_feedrate}"
        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 %}
        _KlickyDebug msg="_Home_Z_ XY Axis homed"
        {% if not 'z' in printer.toolhead.homed_axes %}
            {% if verbose %}
                { action_respond_info("Resetting Z position to zero") }
            {% endif %}
             _KlickyDebug msg="_Home_Z_ Z not homed, setting position as X=Y=Z=0"
            SET_KINEMATIC_POSITION Z=0
        {% endif %}

        # Move tool to safe homing position and home Z axis
        # location of z endstop
        _KlickyDebug msg="_Home_Z_ moving to Z endstop position G0 X{z_endstop_x} Y{z_endstop_y} F{travel_feedrate}"
        G0 X{z_endstop_x} Y{z_endstop_y} F{travel_feedrate}
        _KlickyDebug msg="_Home_Z_ Homing Z G28 Z"
        G28 Z0
        _KlickyDebug msg="_Home_Z_ toolhead too low, raising it to {safe_z}mm from {printer.gcode_move.gcode_position.z}mm"
        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 %}
        {% if parkposition_z == -128 %}
            _KlickyDebug msg="_Park_Toolhead moving to G0 X{parkposition_x} Y{parkposition_y} F{travel_feedrate}"
            G0 X{parkposition_x} Y{parkposition_y} F{travel_feedrate}

        {% else %}

            _KlickyDebug msg="_Park_Toolhead moving to G0 X{parkposition_x} Y{parkposition_y} Z{parkposition_z} F{travel_feedrate}"
            G0 X{parkposition_x} Y{parkposition_y} Z{parkposition_z} F{travel_feedrate}

        {% endif %}

    {% endif %}
    _exit_point function=Park_Toolhead



#################
# Status LEDs
# This enables stealthburner-led status macros to be used in klicky macros if they exist.
# https://github.com/VoronDesign/Voron-Afterburner/blob/sb-beta/Klipper_Macros/stealthburner_leds.cfg
[gcode_macro _klicky_status_ready]
gcode:
    {% if printer['gcode_macro status_ready'] is defined %}
        _KlickyDebug msg="_klicky_status_ready activating the LED STATUS_READY"
        STATUS_READY
    {% endif %}

[gcode_macro _klicky_status_busy]
gcode:
    {% if printer['gcode_macro status_busy'] is defined %}
        _KlickyDebug msg="_klicky_status_busy activating the LED STATUS_BUSY"
        STATUS_BUSY
    {% endif %}

[gcode_macro _klicky_status_leveling]
gcode:
    {% if printer['gcode_macro status_leveling'] is defined %}
        _KlickyDebug msg="_klicky_status_leveling activating the LED STATUS_LEVELING"
        STATUS_LEVELING
    {% endif %}

[gcode_macro _klicky_status_homing]
gcode:
    {% if printer['gcode_macro status_homing'] is defined %}
        _KlickyDebug msg="_klicky_status_homing activating the LED STATUS_HOMING"
        STATUS_HOMING
    {% endif %}

[gcode_macro _klicky_status_cleaning]
gcode:
    {% if printer['gcode_macro status_cleaning'] is defined %}
        _KlickyDebug msg="_klicky_status_cleaning activating the LED STATUS_CLEANING"
        STATUS_CLEANING
    {% endif %}

[gcode_macro _klicky_status_meshing]
gcode:
    {% if printer['gcode_macro status_meshing'] is defined %}
        _KlickyDebug msg="_klicky_status_meshing activating the LED STATUS_MESHING"
        STATUS_MESHING
    {% endif %}

[gcode_macro _klicky_status_calibrating_z]
gcode:
    {% if printer['gcode_macro status_calibrating_z'] is defined %}
        _KlickyDebug msg="_klicky_status_calibrating_z activating the LED STATUS_CALIBRATING_Z"
        STATUS_CALIBRATING_Z
    {% endif %}
