[include mainsail.cfg]

[virtual_sdcard]
path: ~/printer_data/gcodes
on_error_gcode: CANCEL_PRINT

[save_variables]
filename: ~/printer_data/config/config_variables.cfg

[exclude_object]

[gcode_arcs]
resolution: 1.0

[force_move]
enable_force_move: True

[idle_timeout]
gcode:
    {% if printer.webhooks.state|lower == 'ready' %}
        {% if printer.pause_resume.is_paused %}
            {% if printer["extruder"] is defined %}
                SET_HEATER_TEMPERATURE HEATER=extruder
            {% endif %}
            {% if printer["extruder1"] is defined %}
                SET_HEATER_TEMPERATURE HEATER=extruder1
            {% endif %}
        {% else %}
            TURN_OFF_HEATERS
        {% endif %}
    {% endif %}
timeout: 1800 # 0.5 hour timeout

# F446 MotherBoard ID
[mcu]
canbus_uuid:000000000010
canbus_interface: can0

[printer]
kinematics: cartesian
max_velocity: 300
max_accel: 5000
max_z_velocity: 10
max_z_accel: 100
square_corner_velocity: 2.5

[bed_mesh]
speed: 300
horizontal_move_z: 5
mesh_min: 40,60
mesh_max: 600, 600
probe_count: 6,6
mesh_pps: 2,2
fade_end: 10
algorithm: bicubic
bicubic_tension: 0.2

[stepper_x]
step_pin: PD1
dir_pin: PD0
enable_pin: !PA15
rotation_distance: 75
microsteps: 100
full_steps_per_rotation: 200
position_min: 0
position_endstop: 0
position_max: 600
homing_speed: 100
homing_retract_speed: 50
second_homing_speed: 5
homing_retract_dist: 10
# homing_positive_dir: true

[stepper_y]
step_pin: PD4
dir_pin: !PD3
enable_pin: !PD2
rotation_distance: 75
microsteps: 40
full_steps_per_rotation: 200
gear_ratio: 2.5:1
endstop_pin: PC11
position_min: 0
position_endstop: 0
position_max: 600
homing_speed: 100
homing_retract_speed: 50
second_homing_speed: 5
homing_retract_dist: 10
# homing_positive_dir: true

[stepper_z]
step_pin: PD7
dir_pin: PD6
enable_pin: !PD5
rotation_distance: 5
gear_ratio: 2.5:1
microsteps: 16
full_steps_per_rotation: 200
endstop_pin: probe:z_virtual_endstop
position_max: 600
position_min: -4
homing_speed: 10
second_homing_speed: 1
homing_retract_dist: 2.0

[heater_bed]
heater_pin: PD12
sensor_type: Generic 3950
sensor_pin: PC0
max_power: 1.0
min_temp: 0
max_temp: 130
# control: pid
# pid_kp: 59.368
# pid_ki: 1.656
# pid_kd: 532.083

[verify_heater heater_bed]
max_error: 20
hysteresis: 5
check_gain_time: 120
heating_gain: 1

[heater_generic chamber]
heater_pin:PD15
max_power:1.0
sensor_type: Generic 3950
sensor_pin:PC3
min_temp: 0
max_temp: 80
pwm_cycle_time: 0.3
# control: pid
# pid_kp: 30.68
# pid_ki: 0.21
# pid_kd: 0

[verify_heater chamber]
max_error: 120
hysteresis: 100
check_gain_time: 3600
heating_gain: 0.01

[fan_generic Air_filter_fan]
pin: PC8
max_power: 1.0
shutdown_speed: 0.0
kick_start_time: 1.0
off_below: 0.10

[filament_switch_sensor extruder]
pause_on_runout: False
runout_gcode: _RUNOUT_HANDLE
event_delay: 3.0
pause_delay: 0.5
switch_pin: ^PC14

[filament_switch_sensor extruder1]
pause_on_runout: False
runout_gcode: _RUNOUT_HANDLE
event_delay: 3.0
pause_delay: 0.5
switch_pin: ^PC15

# F072 nozzle ID
[mcu tool]
canbus_uuid: 000000000001
canbus_interface: can0

[stepper_x]
endstop_pin: tool:PC0

[adxl345]
spi_speed: 5000000
cs_pin: tool:PB12
spi_software_sclk_pin:tool:PB13
spi_software_mosi_pin:tool:PB15
spi_software_miso_pin:tool:PB14
rate: 3200

[resonance_tester]
accel_chip: adxl345
probe_points: 300, 300, 20
min_freq: 5
max_freq: 133.3
accel_per_hz: 75
hz_per_sec: 1

[input_shaper]
#shaper_freq_x: 0
#shaper_freq_y: 0
shaper_type: mzv
#shaper_type_x:
#shaper_type_y:
damping_ratio_x: 0.1
damping_ratio_y: 0.1

[fan]
pin:tool:PA10
kick_start_time: 0.5
off_below: 0.10
max_power: 1.0

[heater_fan Sink_fan_0]
pin:tool:PA8
max_power: 1.0
kick_start_time: 0.5
heater: extruder
off_below: 0.10
heater_temp: 100

[heater_fan Sink_fan_1]
pin:tool:PA9
max_power: 1.0
kick_start_time: 0.5
heater: extruder1
off_below: 0.10
heater_temp: 100

[extruder]
sensor_type: MAX31855
sensor_pin: tool:PD2
spi_software_sclk_pin:tool:PB3
spi_software_mosi_pin:tool:PB5
spi_software_miso_pin:tool:PB4

[verify_heater extruder]
max_error: 20
check_gain_time: 60
hysteresis: 10
heating_gain: 1

[extruder]
step_pin: tool:PB1
dir_pin: tool:PB2
enable_pin: !tool:PB0
microsteps: 16
full_steps_per_rotation: 200
rotation_distance:22.9116807962642578993
gear_ratio: 48:19
nozzle_diameter: 0.6
filament_diameter: 1.750
max_extrude_only_distance: 500.0
max_extrude_only_velocity: 60.0
max_extrude_only_accel: 1000.0
max_extrude_cross_section:5
heater_pin: tool:PC6
max_power: 1.0
min_temp: 0
max_temp: 435
min_extrude_temp: 180
pressure_advance: 0.03
pressure_advance_smooth_time:0.040
# control = pid
# pid_kp = 21.950
# pid_ki = 0.887
# pid_kd = 135.815

[tmc5160 extruder]
cs_pin:tool:PB7
spi_software_sclk_pin:tool:PB3
spi_software_mosi_pin:tool:PB5
spi_software_miso_pin:tool:PB4
run_current: 0.8
interpolate: False
sense_resistor: 0.075
stealthchop_threshold: 0

[extruder1]
sensor_type: MAX31855
sensor_pin: tool:PC12
spi_software_sclk_pin:tool:PB3
spi_software_mosi_pin:tool:PB5
spi_software_miso_pin:tool:PB4

[verify_heater extruder1]
max_error: 20
check_gain_time: 60
hysteresis: 10
heating_gain: 1

[extruder1]
step_pin: tool:PC4
dir_pin: tool:PA7
enable_pin: !tool:PC5
microsteps: 16
full_steps_per_rotation: 200
rotation_distance: 22.9116807962642578993
gear_ratio: 48:19
nozzle_diameter: 0.6
filament_diameter: 1.750
max_extrude_only_distance: 500.0
max_extrude_only_velocity: 60.0
max_extrude_only_accel: 1000.0
max_extrude_cross_section:5
heater_pin: tool:PC7
max_power: 1.0
min_temp: 0
max_temp: 435
min_extrude_temp: 180
pressure_advance: 0.032
pressure_advance_smooth_time:0.040
# control = pid
# pid_kp = 21.950
# pid_ki = 0.887
# pid_kd = 135.815

[tmc5160 extruder1]
cs_pin:tool:PC11
spi_software_sclk_pin:tool:PB3
spi_software_mosi_pin:tool:PB5
spi_software_miso_pin:tool:PB4
run_current: 0.8
interpolate: False
sense_resistor: 0.075
stealthchop_threshold: 0

[probe]
pin: !tool:PC2
x_offset: 36
y_offset: 59
#z_offset: 4
speed: 5.0
samples: 3
samples_result: median
sample_retract_dist: 2.0
samples_tolerance: 0.05
samples_tolerance_retries: 3
deactivate_on_each_sample: False
activate_gcode: PROBE_SERVO_OPEN
deactivate_gcode: PROBE_SERVO_CLOSE

[servo probe_servo]
pin: tool:PC8
maximum_servo_angle: 180
minimum_pulse_width: 0.000900
maximum_pulse_width: 0.002100
initial_angle: 130
steps_decomposed: 60
signal_duration: 0.1
# initial_pulse_width:

[servo switch_nozzle]
pin: tool:PC9
maximum_servo_angle: 270
minimum_pulse_width: 0.000512
maximum_pulse_width: 0.002528
initial_angle: 135
# initial_pulse_width:

[safe_z_home]
home_xy_position: 300,300
speed:100
z_hop:5
z_hop_speed: 10

[gcode_macro ENABLE_MOTOR]
gcode:
    SET_STEPPER_ENABLE STEPPER=stepper_x ENABLE=1
    SET_STEPPER_ENABLE STEPPER=stepper_y ENABLE=1
    SET_STEPPER_ENABLE STEPPER=stepper_z ENABLE=1
    SET_KINEMATIC_POSITION X=300 Y=300 Z=0

[gcode_macro T0]
gcode:
    {% set filament_insert = printer["filament_switch_sensor extruder"].filament_detected|default(False) %}
    {% set printing = printer.print_stats.state ==  "printing" %}
    {% if filament_insert or printing == False %}
        SET_SERVO SERVO=switch_nozzle angle=135
        G4 P500
        {% if "z" in printer.toolhead.homed_axes | lower %}
            SET_GCODE_OFFSET Z=0 MOVE=1
        {% else %}
            SET_GCODE_OFFSET Z=0
        {% endif %}
        SET_GCODE_OFFSET Y=0
        SET_GCODE_OFFSET X=0
        SET_SERVO SERVO=switch_nozzle angle=45
        ACTIVATE_EXTRUDER EXTRUDER=extruder
    {% else %}
        PAUSE
        SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE='"T0"'
        RESPOND TYPE=error MSG='{"Noting! Left extruder filament has been run out."}'
    {% endif %}

[gcode_macro T1]
gcode:
    {% set sv = printer.save_variables.variables %}
    {% set x_offset = sv.nozzle_x_offset_val|default(0)|float %}
    {% set y_offset = sv.nozzle_y_offset_val|default(0)|float %}
    {% set z_offset = sv.nozzle_z_offset_val|default(0)|float %}
    {% set x_offset = x_offset - 59 %}
    {% set filament_insert = printer["filament_switch_sensor extruder1"].filament_detected|default(False) %}
    {% set printing = (printer.print_stats.state == "printing") %}
    {% if filament_insert or printing == False %}
        SET_SERVO SERVO=switch_nozzle angle=135
        G4 P500
        {% if "z" in printer.toolhead.homed_axes | lower %}
            SET_GCODE_OFFSET Z={z_offset} MOVE=1
        {% else %}
            SET_GCODE_OFFSET Z={z_offset}
        {% endif %}
        SET_GCODE_OFFSET Y={y_offset}
        SET_GCODE_OFFSET X={x_offset}
        SET_SERVO SERVO=switch_nozzle angle=225
        ACTIVATE_EXTRUDER EXTRUDER=extruder1
    {% else %}
        PAUSE
        SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE='"T1"'
        RESPOND TYPE=error MSG='{"Noting! Right extruder filament has been run out."}'
    {% endif %}

[gcode_macro PROBE_SERVO_OPEN]
gcode:
    SET_SERVO SERVO=probe_servo angle=15
    G4 P2000

[gcode_macro PROBE_SERVO_CLOSE]
gcode:
   SET_SERVO SERVO=probe_servo angle=130
   G4 P2000

[gcode_macro _START_PRINT_BASE]
description: Call when starting to print
gcode:
    _CLEAR_LAST_FILE
    _RUNOUT_HANDLE

[gcode_macro _CANCEL_PRINT_BASE]
description: Call when cancelled to print
gcode:
    # Nothing

[gcode_macro START_PRINT]
gcode:
    {% set BED_TEMP = params.BED|default(0)|float %}
    {% set EXTRUDER_TEMP = params.EXTRUDER|default(0)|float %}
    {% set EXTRUDER_TEMP1 = params.EXTRUDER1|default(0)|float %}
    {% set CHAMBER_TEMP = params.CHAMBER|default(0)|float %}
    {% if params.BED is defined %}
        M140 S{BED_TEMP}
    {% endif %}
    {% if params.EXTRUDER is defined %}
        M104 T0 S{EXTRUDER_TEMP}
    {% endif %}
    {% if params.EXTRUDER1 is defined %}
        M104 T1 S{EXTRUDER_TEMP1}
    {% endif %}
    {% if params.CHAMBER is defined %}
        M141 S{CHAMBER_TEMP}
    {% endif %}
    G28
    _START_PRINT_BED_MESH
    {% if BED_TEMP != 0 %}
        M190 S{BED_TEMP}
    {% endif %}
    {% if EXTRUDER_TEMP != 0 %}
        M109 T0 S{EXTRUDER_TEMP}
    {% endif %}
    {% if EXTRUDER_TEMP1 != 0 %}
        M109 T1 S{EXTRUDER_TEMP1}
    {% endif %}
    {% if CHAMBER_TEMP != 0 %}
        M191 S{CHAMBER_TEMP}
    {% endif %}
    G92 E0
    M117 Printing start...

[gcode_macro PRINT_START]
gcode:
    START_PRINT

[gcode_macro END_PRINT]
gcode:
    M400
    G92 E0
    G1 E-10.0 F3600
    G91
    G0 Z1.00 X20.0 Y20.0 F6000
    TURN_OFF_HEATERS
    M107
    G1 Z2 F3000
    G90
    G0  X590 Y590 F3600
    # BED_MESH_CLEAR

[gcode_macro PRINT_END]
gcode:
    END_PRINT

[gcode_macro LOAD_FILAMENT]
variable_load_distance: 120
variable_purge_distance: 25
gcode:
    {% set speed = params.SPEED|default(200) %}
    {% set max_velocity = printer.configfile.settings['extruder'].max_extrude_only_velocity  * 10 %}
    SAVE_GCODE_STATE NAME=load_state
    G91
    G92 E0
    G1 E{load_distance} F{max_velocity} # fast-load
    G1 E{purge_distance} F{speed} # purge
    RESTORE_GCODE_STATE NAME=load_state

[gcode_macro UNLOAD_FILAMENT]
variable_unload_distance: 50
variable_advance_unload_distance: 80
variable_purge_distance: 10
gcode:
    {% set speed = params.SPEED|default(200) %}
    {% set max_velocity = printer.configfile.settings['extruder'].max_extrude_only_velocity  * 10 %}
    SAVE_GCODE_STATE NAME=unload_state
    G91
    G92 E0
    G1 E{purge_distance} F{speed} # purge
    G1 E-{advance_unload_distance} F{max_velocity}
    G1 E-{4} F60
    G1 E-{unload_distance} F{max_velocity} # fast-unload
    RESTORE_GCODE_STATE NAME=unload_state

[gcode_macro _ACTIVATE_DEFAULT_EXTRUDER]
  gcode:
    {% if printer.toolhead.extruder == 'extruder' %}
      T0
    {% elif printer.toolhead.extruder == 'extruder1' %}
      T1
    {% endif %}

########################################
# GCODE
########################################

[gcode_macro G28]
rename_existing: C28
gcode:
    {% set homing_cmd = ''%}
    {% set do_x = 'X' in params|string %}
    {% set do_y = 'Y' in params|string %}
    {% set do_z = 'Z' in params|string %}

    {% if do_x %}
        {% set homing_cmd = 'X ' %}
    {% endif %}
    {% if do_y %}
        {% set homing_cmd = homing_cmd + 'Y ' %}
    {% endif %}
    {% if do_z %}
        {% if 'x' not in printer.toolhead.homed_axes|lower or 'y' not in printer.toolhead.homed_axes|lower %}
            {% set homing_cmd = 'X Y Z' %}
        {% else %}
           {% set homing_cmd = homing_cmd + 'Z' %}
        {% endif %}
    {% endif %}
    {% if not homing_cmd %}
        C28
        _ACTIVATE_DEFAULT_EXTRUDER
    {% else %}
        C28 {homing_cmd}
        {% if 'X' in homing_cmd %}
            _ACTIVATE_DEFAULT_EXTRUDER
        {% endif %}
    {% endif %}

[gcode_macro M109]
rename_existing: C109
gcode:
    {% set hotend = printer.toolhead.extruder %}
    {% set s = params.S|default(0)|float %}
    {% set t = params.T|default(0)|int %}
    {% if params.S is defined %}
        {% if params.T is defined %}
           {% set hotend = "extruder" ~ (t if t != 0 else '') %}
        {% endif %}
        SET_HEATER_TEMPERATURE HEATER={hotend} TARGET={s}
        {% if s != 0 %}
            TEMPERATURE_WAIT SENSOR={hotend} MINIMUM={s-3} MAXIMUM={s+3}
        {% endif %}
    {% endif %}

[gcode_macro M141]
gcode:
    {% set s = params.S|default(0)|float %}
    {% if params.S is defined %}
        SET_HEATER_TEMPERATURE HEATER=chamber target={s|int}
    {% endif %}

[gcode_macro M190]
rename_existing: C190
gcode:
    {% set s = params.S|default(0)|float %}
    {% if params.S is defined %}
        SET_HEATER_TEMPERATURE HEATER="heater_bed" TARGET={s}
        {% if s != 0 %}
            TEMPERATURE_WAIT SENSOR="heater_bed" MINIMUM={s-3} MAXIMUM={s+3}
        {% endif %}
    {% endif %}

[gcode_macro M191]
gcode:
    {% set s = params.S|default(0)|float %}
    {% if params.S is defined %}
        M141 S{s}
        {% if s != 0 %}
            TEMPERATURE_WAIT SENSOR="heater_generic chamber" MINIMUM={s-3} MAXIMUM={s+3}
        {% endif %}
    {% endif %}

[gcode_macro M84]
rename_existing: C84
gcode:
    {% set z_offset = printer.gcode_move.homing_origin[2]|default(0)|float %}
    C84
    SET_STEPPER_ENABLE STEPPER=stepper_z enable=1
    SET_GCODE_OFFSET Z_ADJUST={z_offset} MOVE=0

########################################
# CANCEL_PRINT/PAUSE/RESUME/
########################################

[gcode_macro _CLIENT_VARIABLE]
variable_use_custom_pos   : True
variable_custom_park_x    : 300.0
variable_custom_park_y    : 200.0
variable_custom_park_dz   : 20.0
variable_retract          : 2.0
variable_cancel_retract   : 10.0
variable_speed_retract    : 60.0
variable_unretract        : 20.0
variable_speed_unretract  : 6.0
variable_speed_hop        : 5.0
variable_speed_move       : 100.0
variable_park_at_cancel   : False
variable_park_at_cancel_x : None
variable_park_at_cancel_y : None
variable_use_fw_retract   : False
variable_idle_timeout     : 600
variable_runout_sensor    : ""
variable_filament_sensor  : "filament_switch_sensor extruder"
variable_filament_sensor1 : "filament_switch_sensor extruder1"
variable_user_temp_macro  : "_USER_TEMP_RESUME"
variable_user_pause_macro : "_USER_PAUSE"
variable_user_resume_macro: ""
variable_user_cancel_macro: "_USER_CANCEL"
gcode:
 # Nothing

[gcode_macro _USER_PAUSE]
gcode:
    {% set extruderTools = [('extruder', 'last_extruder_temp'),
                        ('extruder1', 'last_extruder1_temp')] %}
    {% set act = printer.gcode_move.gcode_position %}
    SAVE_VARIABLE VARIABLE=power_resume_z VALUE={act.z}
    {% for extruder_name, name in extruderTools %}
        {% set temp = printer[extruder_name].target if extruder_name in printer else 0 %}
        {% set restore = False if printer[extruder_name] == ''
                else True if params.RESTORE|default(1)|int == 1 else False %}
        SET_GCODE_VARIABLE MACRO=RESUME VARIABLE={name} VALUE="{{'restore': restore, 'temp': temp}}"
    {% endfor %}
    SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=resume_extruder VALUE="'{printer.toolhead.extruder}'"

[gcode_macro _RESUME_EXTRUDER]
gcode:
    {% set client = printer['gcode_macro RESUME']|default({}) %}
    {% set autoshift_on = params.AUTOSHIFT|default(False)|lower %}
    {% set toolchange = client.change_runout|lower|default("") %}
    {% set extruder_filament = client.filament_state.extruder %}
    {% set extruder1_filament = client.filament_state.extruder1 %}
    {% set resume_extruder = client.resume_extruder|default("extruder") %}

    {% if autoshift_on == 'true' %}
        {% if extruder_filament and extruder1_filament %}
            {% if toolchange == "t0" %}
                {% set resume_extruder = "extruder" %}
            {% elif toolchange == "t1" %}
                {% set resume_extruder = "extruder1" %}
            {% endif %}
        {% else %}
            {% if extruder_filament %}
                {% set resume_extruder = "extruder" %}
            {% elif extruder1_filament %}
                {% set resume_extruder = "extruder1" %}
            {% endif %}
        {% endif %}
    {% endif %}
    {% if printer.toolhead.extruder != resume_extruder %}
        T{0 if resume_extruder|default("extruder") == "extruder" else 1 }
    {% endif %}
    _FILAMENT_UPDATE

[gcode_macro _EXTRUDER_TEMPERATURE_HANDLE]
gcode:
    {% set client = printer['gcode_macro RESUME']|default({}) %}
    {% set last_extruder_temp = client.last_extruder_temp %}
    {% set last_extruder1_temp = client.last_extruder1_temp %}
    {% set resume_extruder = client.resume_extruder|lower %}
    {% if resume_extruder != printer.toolhead.extruder %}
        SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=last_extruder_temp VALUE="{last_extruder1_temp}"
        SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=last_extruder1_temp VALUE="{last_extruder_temp}"
    {% endif %}

[gcode_macro _USER_TEMP_RESUME]
gcode:
    {% set extruder_info = [
        {'index': 0, 'name': 'last_extruder_temp'},
        {'index': 1, 'name': 'last_extruder1_temp'}] %}
    {% set temperature = "last_extruder_temp" if printer.toolhead.extruder == "extruder" else "last_extruder1_temp" %}
    {% set value = printer["gcode_macro RESUME"][temperature].temp %}
    {% if printer[printer.toolhead.extruder].temperature < value-3 %}
        {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %}
        RESPOND TYPE=echo MSG='{"Restoring %s extruder temperature, this may take some time." % msg}'
    {% endif %}
    {% for info in extruder_info %}
        {% set variable = printer["gcode_macro RESUME"][info.name] %}
        {% if variable.restore %}
            M104 T{ info.index } S{ variable.temp }
        {% endif %}
    {% endfor %}
    {% for info in extruder_info %}
        {% set variable = printer["gcode_macro RESUME"][info.name] %}
        {% if variable.restore %}
            {% set tool = "extruder" if info.index == 0 else "extruder1" %}
            {% set needwait = True if printer[tool].temperature < variable.temp else False %}
            {% if needwait %}
                M109 T{info.index} S{variable.temp}
                {% endif %}
        {% endif %}
    {% endfor %}

[gcode_macro _USER_CANCEL]
gcode:
    {% if 'z' in printer.toolhead.homed_axes %}
        G91
        G1 Z30 F600 ; lift nozzle
    {% endif %}
    M84

[gcode_macro _CLIENT_EXTRUDE]
description: Extrudes, if the extruder is hot enough
gcode:
  ##### get user parameters or use default #####
  {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %}
  {% set use_fw_retract = (client.use_fw_retract|default(false)|lower == 'true') and (printer.firmware_retraction is defined) %}
  {% set length = params.LENGTH|default(client.unretract)|default(1.0)|float %}
  {% set speed = params.SPEED|default(client.speed_unretract)|default(35) %}
  {% set absolute_extrude = printer.gcode_move.absolute_extrude %}
  ##### end of definitions #####
  {% if printer.toolhead.extruder != '' %}
    {% if printer[printer.toolhead.extruder].can_extrude %}
      {% if use_fw_retract %}
        {% if length < 0 %}
          G10
        {% else %}
          G11
        {% endif %}
      {% else %}
        M83
        G1 E{length} F{(speed|float|abs) * 60}
        {% if absolute_extrude %}
          M82
        {% endif %}
      {% endif %}
    {% endif %}
  {% endif %}

[gcode_macro RESUME]
description: Resume the actual running print
rename_existing: RESUME_BASE
variable_last_extruder_temp: {'restore': False, 'temp': 0}
variable_last_extruder1_temp: {'restore': False, 'temp': 0}
variable_restore_idle_timeout: 0
variable_idle_state: False
variable_filament_state: ""
variable_change_runout: ""
variable_resume_extruder: ""
gcode:
    ##### get user parameters or use default #####
    {% set autoshift = printer.save_variables.variables.auto_change_nozzle|default(False) %}
    {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %}
    {% set do_resume = False %}
    {% set runout = True %}
    ##### end of definitions #####
    _FILAMENT_UPDATE
    _RESUME_EXTRUDER AUTOSHIFT={autoshift}
    _EXTRUDER_TEMPERATURE_HANDLE

    {% set can_extrude = True if printer.toolhead.extruder == ''           # no extruder defined in config
                    else printer[printer.toolhead.extruder].can_extrude %} # status of active extruder

    #### Printer comming from timeout idle state ####
    {% if printer.idle_timeout.state|upper == "IDLE" or idle_state or autoshift %}
        SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=idle_state VALUE=False
        {% if last_extruder_temp.restore or last_extruder1_temp.restore %}
            # we need to use the unicode (\u00B0) for the ° as py2 env's would throw an error otherwise
            {client.user_temp_macro|default("")}
            {% set do_resume = True %}
        {% elif can_extrude %}
            {% set do_resume = True %}
        {% endif %}
    #### Printer comming out of regular PAUSE state ####
    {% elif can_extrude %}
        {% set do_resume = True %}
    {% endif %}
    _ACT_RESUME DO_RESUME={do_resume}

[gcode_macro _ACT_RESUME]
gcode:
    ##### get user parameters or use default #####
    {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %}
    {% set velocity = printer.configfile.settings.pause_resume.recover_velocity %}
    {% set auto_extruder = params.AUTO|default(False) %}
    {% set sp_move = client.speed_move|default(velocity) %}
    {% set do_resume = true if params.DO_RESUME|default(False)|lower == 'true' else false %}
    {% set filament_state = printer['gcode_macro RESUME'].filament_state.runout|default(False) %}
    {% set restore_idle_timeout = printer['gcode_macro RESUME'].restore_idle_timeout|default(0) %}
    {% set prompt_txt = [] %}
    {% if filament_state %}
        {% if do_resume or auto_extruder %}
            {% if restore_idle_timeout > 0 %} SET_IDLE_TIMEOUT TIMEOUT={restore_idle_timeout} {% endif %} # restore idle_timeout time
            {client.user_resume_macro|default("")}
            _CLIENT_EXTRUDE
            RESUME_BASE VELOCITY={params.VELOCITY|default(sp_move)}
            SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE="None"
        {% else %}
            {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %}
            {% set _d = prompt_txt.append("%s extruder not hot enough, will reheat and continue." % msg) %}
        {% endif %}
    {% else %}
        {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %}
        {% set _d = prompt_txt.append("%s extruder detects no filament, please load filament and continue." % msg) %}
    {% endif %}
    ##### Generate User Information box in case of abort #####
    {% if not (filament_state and do_resume) %}
        RESPOND TYPE=command MSG="action:prompt_begin RESUME ABORTED !"
        {% for element in prompt_txt %}
            RESPOND TYPE=command MSG='{"action:prompt_text %s" % element}'
        {% endfor %}
        RESPOND TYPE=command MSG="action:prompt_footer_button Ok|RESPOND TYPE=command MSG=action:prompt_end|info"
        RESPOND TYPE=command MSG="action:prompt_show"
    {% endif %}

########################################
# filament_runout
########################################

[gcode_macro _FILAMENT_UPDATE]
gcode:
    {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %}
    {% set runout_resume = True if client.filament_sensor|default("") == ""     # no runout
                    else True if not printer[client.filament_sensor].enabled    # sensor is disabled
                    else printer[client.filament_sensor].filament_detected %}   # sensor status
    {% set runout_resume1 = True if client.filament_sensor1|default("") == ""   # no runout
                    else True if not printer[client.filament_sensor1].enabled   # sensor1 is disabled
                    else printer[client.filament_sensor1].filament_detected %}  # sensor1 status
    ##### filament check #####
    {% if printer["dual_carriage"] is not defined %}
        {% set runout = runout_resume if printer.toolhead.extruder == "extruder" else runout_resume1 %}
    {% else %}
        {% set current_idex_mode = printer["dual_carriage"].carriage_1|lower %}
        {% if current_idex_mode == 'copy' or current_idex_mode == 'mirror' %}
            {% set runout = True if (runout_resume and runout_resume1) else false %}
        {% else %}
            {% set runout = runout_resume if printer.toolhead.extruder == "extruder" else runout_resume1 %}
        {% endif %}
    {% endif %}
    SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=filament_state VALUE="{{'runout': runout, 'extruder': runout_resume, 'extruder1': runout_resume1}}"

[gcode_macro _RUNOUT_HANDLE]
description: filament state update
gcode:
    _FILAMENT_UPDATE
    {% if printer.print_stats.state ==  "printing" %}
        _RUNOUT_PAUSE
    {% endif %}

[gcode_macro _RUNOUT_PAUSE]
gcode:
    {% set svv = printer.save_variables.variables %}
    {% set autoshift_extruder = svv.auto_change_nozzle|default(False) %}
    {% set filament_state = printer['gcode_macro RESUME'].filament_state.runout|default(False) %}
    {% set target_extruder = "extruder1" if printer.toolhead.extruder == "extruder" else "extruder" %}
    {% if not filament_state %}
        PAUSE
        {% if autoshift_extruder %}
            {% if printer["gcode_macro RESUME"].filament_state[target_extruder] %}
                RESUME
            {% else %}
                RESPOND TYPE=error MSG='{"Noting! All extruders filament has been run out."}'
            {% endif %}
        {% else %}
            {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %}
            RESPOND TYPE=error MSG='{"Noting! %s extruder filament has been run out." % msg}'
        {% endif %}
    {% endif %}

########################################
# power loss recovery
########################################

[delayed_gcode _CHECK_POWER_LOSS_RECOVERY]
initial_duration: 1
gcode:
    {% set was_interrupted = printer.save_variables.variables.was_interrupted | default(False) | string %}
    {% set enable_recovery = printer.save_variables.variables.power_loss_recovery | default(Ture) | string %}
    {% if enable_recovery != "False" and was_interrupted == "True" %}
        RESPOND TYPE=command MSG="action:prompt_begin "
        RESPOND TYPE=command MSG="action:prompt_text The last print job was not completed continue printing?"
        RESPOND TYPE=command MSG="action:prompt_footer_button Continue|_RESUME_INTERRUPTED"
        RESPOND TYPE=command MSG="action:prompt_footer_button Cancel|_ABORT_INTERRUPTED|error"
        RESPOND TYPE=command MSG="action:prompt_show"
    {% endif %}

[gcode_shell_command _CLEAR_PLR]
command: sh /home/klipper/klipper/scripts/clear_plr.sh
timeout: 5.
verbose: False

[gcode_macro _CLEAR_LAST_FILE]
gcode:
    {% set filename = '' %}
    {% set filepath = '' %}
    RUN_SHELL_COMMAND CMD=_CLEAR_PLR
    SAVE_VARIABLE VARIABLE=last_file VALUE='"{ filename }"'
    SAVE_VARIABLE VARIABLE=filepath VALUE='"{ filepath }"'
    {% set zero_vars = ['power_resume_x', 'power_resume_y', 'power_resume_z'] %}
    {% for var in zero_vars %}
    SAVE_VARIABLE VARIABLE={var} VALUE=0
    {% endfor %}
    SAVE_VARIABLE VARIABLE=was_interrupted VALUE=False

[gcode_shell_command _POWER_LOSS_RECOVERY]
command: /home/klipper/klipper/scripts/plr.sh
timeout: 420.
verbose: False

[gcode_macro _RESUME_INTERRUPTED]
gcode:
    {% set sv = printer.save_variables.variables %}
    {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %}
    {% set park_dz = client.custom_park_dz|default(2.0)|abs %}
    RESPOND TYPE=command MSG="action:prompt_end"
    SET_GCODE_OFFSET Z=0 MOVE=0
    {% set z_height = params.Z_HEIGHT|default(sv.power_resume_z)|float %}
    {% set is_paused = sv.power_loss_paused|default(False) %}
    {% set last_file = params.GCODE_FILE|default(sv.last_file)|string %}
    {% set hotend = sv.power_resume_extruder|default("extruder")%}
    {% set z_offset = sv.nozzle_z_offset_val|default(0)|float %}
    {% set z_offset_total = park_dz if is_paused else 0 %}
    {% if hotend == "extruder1" %}
        {% set z_offset_total = z_offset_total +  z_offset %}
    {% endif %}
    SET_STEPPER_ENABLE STEPPER=stepper_z ENABLE=1
    G4 P300
    M118 Recovery in progress, please wait
    RUN_SHELL_COMMAND CMD=_POWER_LOSS_RECOVERY PARAMS="{z_height} \"{last_file}\" \"{z_offset_total}\""
    SDCARD_PRINT_FILE FILENAME=.plr/"{last_file}"
    SAVE_VARIABLE VARIABLE=was_interrupted VALUE=False

[gcode_macro _ABORT_INTERRUPTED]
gcode:
    RESPOND TYPE=command MSG="action:prompt_end"
    _CLEAR_LAST_FILE

########################################
# Adaptive mesh
########################################

[gcode_macro Adaptive_Mesh]
description: This macro contains all adjustable settings for KAMP
variable_verbose_enable: True               # Set to True to enable KAMP information output when running. This is useful for debugging.
variable_mesh_margin: 5                     # Expands the mesh size in millimeters if desired. Leave at 0 to disable.
variable_fuzz_amount: 0                     # Slightly randomizes mesh points to spread out wear from nozzle-based probes. Leave at 0 to disable.

gcode: # Gcode section left intentionally blank. Do not disturb.
#   Noting

[gcode_macro _START_PRINT_BED_MESH]
gcode:
    {% set idex_mode = False %}
    {% set profiles =  printer["bed_mesh"].profiles %}
    {% set svv = printer.save_variables.variables %}
    {% set adaptive_mesh = svv.adaptive_meshing|default(false)|lower %}
    {% if printer["dual_carriage"] is defined %}
        {% set current_idex_mode = printer["dual_carriage"].carriage_1|lower %}
        {% if current_idex_mode == "copy"  or idex_mode == "mirror" %}
            {% set idex_mode = True %}
        {% endif %}
    {% endif %}

    {% if adaptive_mesh|lower == 'true' %}
        {% if printer.exclude_object.objects != [] %}
            {% if idex_mode %}
                BED_MESH_CLEAR
            {% else %}
                BED_MESH_CALIBRATE PROFILE=adaptive
            {% endif %}
        {% else %}
            {% if idex_mode %}
                BED_MESH_CLEAR
            {% else %}
                {% if 'default' in profiles %}
                    BED_MESH_PROFILE LOAD=default
                {% else %}
                    BED_MESH_CALIBRATE PROFILE=default
                    BED_MESH_PROFILE SAVE=default
                {% endif %}
            {% endif %}
        {% endif %}
    {% endif %}

[gcode_macro BED_MESH_CALIBRATE]
rename_existing: _BED_MESH_CALIBRATE
gcode:
    {% set all_points = printer.exclude_object.objects | map(attribute='polygon') | sum(start=[]) %}                                # Gather all object points
    {% set bed_mesh_min = printer.configfile.settings.bed_mesh.mesh_min %}                                                          # Get bed mesh min from printer.cfg
    {% set bed_mesh_max = printer.configfile.settings.bed_mesh.mesh_max %}                                                          # Get bed mesh max from printer.cfg
    {% set probe_count = printer.configfile.settings.bed_mesh.probe_count %}                                                        # Get probe count from printer.cfg
    {% set kamp_settings = printer["gcode_macro Adaptive_Mesh"] %}                                                                  # Pull variables from _KAMP_Settings
    {% set verbose_enable = kamp_settings.verbose_enable | abs %}                                                                   # Pull verbose setting from _KAMP_Settings
    {% set mesh_margin = kamp_settings.mesh_margin | float %}                                                                       # Pull mesh margin setting from _KAMP_Settings
    {% set fuzz_amount = kamp_settings.fuzz_amount | float %}                                                                       # Pull fuzz amount setting from _KAMP_Settings
	{% set default_profile = params.PROFILE | default("default") %}                                                                 # get default mesh profile
    {% set probe_count = probe_count if probe_count|length > 1 else probe_count * 2  %}                                             # If probe count is only a single number, convert it to 2. E.g. probe_count:7 = 7,7
    {% set max_probe_point_distance_x = ( bed_mesh_max[0] - bed_mesh_min[0] ) / (probe_count[0] - 1)  %}                            # Determine max probe point distance
    {% set max_probe_point_distance_y = ( bed_mesh_max[1] - bed_mesh_min[1] ) / (probe_count[1] - 1)  %}                            # Determine max probe point distance
    {% set x_min = all_points | map(attribute=0) | min | default(bed_mesh_min[0]) %}                                                # Set x_min from smallest object x point
    {% set y_min = all_points | map(attribute=1) | min | default(bed_mesh_min[1]) %}                                                # Set y_min from smallest object y point
    {% set x_max = all_points | map(attribute=0) | max | default(bed_mesh_max[0]) %}                                                # Set x_max from largest object x point
    {% set y_max = all_points | map(attribute=1) | max | default(bed_mesh_max[1]) %}                                                # Set y_max from largest object y point

    {% set fuzz_range = range((0) | int, (fuzz_amount * 100) | int + 1) %}                                                          # Set fuzz_range between 0 and fuzz_amount
    {% set adapted_x_min = x_min - mesh_margin - (fuzz_range | random / 100.0) %}                                                   # Adapt x_min to margin and fuzz constraints
    {% set adapted_y_min = y_min - mesh_margin - (fuzz_range | random / 100.0) %}                                                   # Adapt y_min to margin and fuzz constraints
    {% set adapted_x_max = x_max + mesh_margin + (fuzz_range | random / 100.0) %}                                                   # Adapt x_max to margin and fuzz constraints
    {% set adapted_y_max = y_max + mesh_margin + (fuzz_range | random / 100.0) %}                                                   # Adapt y_max to margin and fuzz constraints

    {% set adapted_x_min = [adapted_x_min , bed_mesh_min[0]] | max %}                                                               # Compare adjustments to defaults and choose max
    {% set adapted_y_min = [adapted_y_min , bed_mesh_min[1]] | max %}                                                               # Compare adjustments to defaults and choose max
    {% set adapted_x_max = [adapted_x_max , bed_mesh_max[0]] | min %}                                                               # Compare adjustments to defaults and choose min
    {% set adapted_y_max = [adapted_y_max , bed_mesh_max[1]] | min %}                                                               # Compare adjustments to defaults and choose min

    {% set points_x = (((adapted_x_max - adapted_x_min) / max_probe_point_distance_x) | round(method='ceil') | int) + 1 %}          # Define probe_count's x point count and round up
    {% set points_y = (((adapted_y_max - adapted_y_min) / max_probe_point_distance_y) | round(method='ceil') | int) + 1 %}          # Define probe_count's y point count and round up

    {% if (([points_x, points_y]|max) > 6) %}                                                                                       #
        {% set algorithm = "bicubic" %}                                                                                             #
        {% set min_points = 4 %}                                                                                                    #
    {% else %}                                                                                                                      # Calculate if algorithm should be bicubic or lagrange
        {% set algorithm = "lagrange" %}                                                                                            #
        {% set min_points = 3 %}                                                                                                    #
    {% endif %}                                                                                                                     #

    {% set points_x = [points_x , min_points]|max %}                                                                                # Set probe_count's x points to fit the calculated algorithm
    {% set points_y = [points_y , min_points]|max %}                                                                                # Set probe_count's y points to fit the calculated algorithm
    {% set points_x = [points_x , probe_count[0]]|min %}
    {% set points_y = [points_y , probe_count[1]]|min %}

    {% if verbose_enable == True %}                                                                                                 # If verbose is enabled, print information about KAMP's calculations
        {% if printer.exclude_object.objects != [] %}

            { action_respond_info( "Algorithm: {}.".format(
                (algorithm),
            )) }

            { action_respond_info("Default probe count: {},{}.".format(
                (probe_count[0]),
                (probe_count[1]),
            )) }

            { action_respond_info("Adapted probe count: {},{}.".format(
                (points_x),
                (points_y),
            )) }

            {action_respond_info("Default mesh bounds: {}, {}.".format(
                (bed_mesh_min[0],bed_mesh_min[1]),
                (bed_mesh_max[0],bed_mesh_max[1]),
            )) }

            {% if mesh_margin > 0 %}
                {action_respond_info("Mesh margin is {}, mesh bounds extended by {}mm.".format(
                    (mesh_margin),
                    (mesh_margin),
                )) }
            {% else %}
                {action_respond_info("Mesh margin is 0, margin not increased.")}
            {% endif %}

            {% if fuzz_amount > 0 %}
                {action_respond_info("Mesh point fuzzing enabled, points fuzzed up to {}mm.".format(
                    (fuzz_amount),
                )) }
            {% else %}
                {action_respond_info("Fuzz amount is 0, mesh points not fuzzed.")}
            {% endif %}

            { action_respond_info("Adapted mesh bounds: {}, {}.".format(
                (adapted_x_min, adapted_y_min),
                (adapted_x_max, adapted_y_max),
            )) }

            {action_respond_info("KAMP adjustments successful. Happy KAMPing!")}

        {% else %}

            {action_respond_info("No objects detected! Check your gcode and make sure that EXCLUDE_OBJECT_DEFINE is happening before BED_MESH_CALIBRATE is called. Defaulting to regular meshing.")}
            G4 P5000             # Wait 5 seconds to make error more visible
        {% endif %}

    {% endif %}

    _BED_MESH_CALIBRATE PROFILE={default_profile} mesh_min={adapted_x_min},{adapted_y_min} mesh_max={adapted_x_max},{adapted_y_max} ALGORITHM={algorithm} PROBE_COUNT={points_x},{points_y}          # End of verbose
    BED_MESH_PROFILE LOAD={default_profile}

########################################
# Nozzle Calibrate
########################################

[gcode_shell_command fetch_assets]
command: sh /home/klipper/klipper/scripts/fetch_assets.sh
timeout: 5.
verbose: False

[gcode_macro _NOZZLE_Z_OFFSET_CALIBRATE]
gcode:
    G28 X Y
    G28 Z
    G91
    G0 x-60 F6000
    SET_GCODE_OFFSET Z=0 MOVE=0
    SET_SERVO SERVO=switch_nozzle angle=225
    ACTIVATE_EXTRUDER EXTRUDER=extruder1

[gcode_macro _NOZZLE_XY_OFFSET_CALIBRATE]
gcode:
  RUN_SHELL_COMMAND CMD=fetch_assets PARAMS="\"Gcode\" \"D600Pro2HS\" \"NozzleAglin.zip\""
  SDCARD_PRINT_FILE FILENAME=".PresetModel/NozzleAglin.gcode"