Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions configuration/macros/heatsoaking.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# WARNING: DO NOT EDIT THIS FILE
# To override settings from this file, you can copy and paste the relevant
# sections into your printer.cfg and change it there.

#####
# CONFIGURATION VARIABLES
#####

[gcode_macro RatOS]
variable_bed_heat_soak_time: 0 # Fixed heat soak time for the bed in seconds (0 = no soak)
# NB: Does not apply when a beacon probe is present and beacon adaptive heatsoaking is enabled.
variable_hotend_heat_soak_time: 0 # Fixed heat soak time for the hotends in seconds (0 = no soak)
# NB: Does not apply when a beacon probe is present and beacon adaptive heatsoaking is enabled.

#####
# MACROS
#####

[gcode_macro RESET_HEATSOAK_SETTINGS]
description: Resets all heatsoak-related settings to startup defaults
gcode:
HEATSOAK_SETTINGS ACTION=reset

[gcode_macro USE_ADAPTIVE_HEATSOAK]
description: Temporarily enables adaptive bed heatsoaking (if a beacon probe is present), will reset to printer.cfg settings
when Klipper is restarted. Optionally specify QUALITY (1-5) and maximum FIRST_LAYER_DURATION (in minutes).
Startup settings will be used by default.
gcode:
{% if printer.fastconfig.settings.beacon is not defined %}
{ action_raise_error("Adaptive heatsoaking is only available when a beacon probe is configured.") }
{% endif %}
{% set settings = printer.fastconfig.settings["gcode_macro ratos"] %}
{% if settings is not defined %}
{ action_raise_error("No settings found for [gcode_macro RatOS]") }
{% endif %}
{% if params.QUALITY is defined %}
{% set quality = params.QUALITY|int %}
{% if quality < 1 or quality > 5 %}
{ action_raise_error("QUALITY must be between 1 (rough) and 5 (maximum). Use 3 (normal) if unsure.") }
{% endif %}
{% else %}
{% set quality = settings.variable_beacon_adaptive_heat_soak_layer_quality|default(3)|int %}
{% endif %}
{% if params.FIRST_LAYER_DURATION is defined %}
{% set first_layer_duration_mins = params.FIRST_LAYER_DURATION|float %}
{% if first_layer_duration_mins <= 0 %}
{ action_raise_error("FIRST_LAYER_DURATION must be a positive number specifying the maximum first layer duration in minutes.") }
{% endif %}
{% set first_layer_duration_secs = (first_layer_duration_mins * 60.0)|int %}
{% else %}
{% set first_layer_duration_secs = settings.variable_beacon_adaptive_heat_soak_maximum_first_layer_duration|default(1800)|int %}
{% set first_layer_duration_mins = (first_layer_duration_secs / 60.0)|round(2) %}
{% endif %}
HEATSOAK_SETTINGS QUIET=1 beacon_adaptive_heat_soak=True beacon_adaptive_heat_soak_layer_quality={quality} beacon_adaptive_heat_soak_maximum_first_layer_duration={first_layer_duration_secs}
RATOS_ECHO MSG="Will use adaptive bed heatsoak with quality {quality} and maximum first layer duration of {"%.2g"|format(first_layer_duration_mins)} minutes."

[gcode_macro USE_FIXED_HEATSOAK]
description: Temporarily enables fixed bed heatsoaking, will reset to printer.cfg settings when Klipper is restarted.
Optionally specify DURATION (in minutes). Startup settings will be used by default.
gcode:
{% set settings = printer.fastconfig.settings["gcode_macro ratos"] %}
{% if settings is not defined %}
{ action_raise_error("No settings found for [gcode_macro RatOS]") }
{% endif %}
{% if params.DURATION is defined %}
{% set duration_mins = params.DURATION|float %}
{% if duration_mins < 0 %}
{ action_raise_error("DURATION must be a non-negative number specifying the heatsoak duration in minutes.") }
{% endif %}
{% set duration_secs = (duration_mins * 60.0)|int %}
{% else %}
{% set duration_secs = settings.variable_bed_heat_soak_time|default(0)|int %}
{% set duration_mins = (duration_secs / 60.0)|round(2) %}
{% endif %}
{% set has_beacon = printer.fastconfig.settings.beacon is defined %}
{% if has_beacon %}
HEATSOAK_SETTINGS QUIET=1 beacon_adaptive_heat_soak=False bed_heat_soak_time={duration_secs}
{% else %}
HEATSOAK_SETTINGS QUIET=1 bed_heat_soak_time={duration_secs}
{% endif %}
{% if duration_mins < 1e-3 %}
RATOS_ECHO MSG="Will use no bed heatsoak."
{% else %}
RATOS_ECHO MSG="Will use fixed-duration bed heatsoak of {"%.2g"|format(duration_mins)} minutes."
{% endif %}

[gcode_macro USE_NO_HEATSOAK]
description: Temporarily disables bed heatsoaking, will reset to printer.cfg settings when Klipper is restarted.
gcode:
USE_FIXED_HEATSOAK DURATION=0

[gcode_macro HEATSOAK_SETTINGS]
description: Shows or adjusts heatsoak settings
- With no arguments: shows current heatsoak settings
- With arguments: sets the specified settings. Use the full setting name without the variable_ prefix, e.g. bed_heat_soak_time=300 or beacon_adaptive_heat_soak_layer_quality=4. See printer.cfg for available settings.
gcode:
# Avoid unwanted param detection by mainsail: uses of params2 won't be noticed.
{% set params2 = params %}
{% set has_beacon = printer.fastconfig.settings.beacon is defined %}
{% if has_beacon %}
{% set vars = (
"beacon_adaptive_heat_soak",
"beacon_adaptive_heat_soak_max_wait",
"beacon_adaptive_heat_soak_extra_wait_after_completion",
"beacon_adaptive_heat_soak_layer_quality",
"beacon_adaptive_heat_soak_maximum_first_layer_duration",
"bed_heat_soak_time",
"hotend_heat_soak_time",
) %}
{% else %}
{% set vars = (
"bed_heat_soak_time",
"hotend_heat_soak_time",
) %}
{% endif %}
{% set action = "show" if params|length == 0 else params2.ACTION %}
{% if action is defined and params|length > 1 %}
{ action_raise_error("ACTION cannot be specified with other parameters.") }
{% elif action is not defined %}
{% set quiet = params2.QUIET|default(0)|int == 1 %}
{% for k, v in params2.items() %}
{% set k = k|lower %}
{% if k in vars %}
{% if not quiet %}
CONSOLE_ECHO MSG="Setting {k} to {v}"
{% endif %}
SET_GCODE_VARIABLE MACRO=RatOS VARIABLE={k} VALUE={v}
{% elif k != "quiet" %}
{ action_raise_error("Parameter '%s' is not recognised. Note that adaptive heatsoaking settings can only be set when a beacon probe is configured." % k) }
{% endif %}
{% endfor %}
{% elif action == "reset" %}
_RESET_GCODE_VARIABLES MACRO=RatOS VARIABLES={vars|join(',')} SKIP_UNDEFINED_VARIABLES=1
CONSOLE_ECHO MSG="Heatsoak settings have been reset to their original values."
{% elif action == "show" %}
CONSOLE_ECHO MSG="Current heatsoak settings:"
_SHOW_GCODE_VARIABLES MACRO=RatOS VARIABLES={vars|join(',')} SKIP_UNDEFINED_VARIABLES=1
{% else %}
{ action_raise_error("Action '%s' is not recognised" % action) }
{% endif %}
90 changes: 89 additions & 1 deletion configuration/macros/util.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -494,4 +494,92 @@ gcode:
[gcode_macro _STOP_AND_RAISE_ERROR]
gcode:
M84
_RAISE_ERROR MSG="{params.MSG}"
_RAISE_ERROR MSG="{params.MSG}"

[gcode_macro _RESET_GCODE_VARIABLES]
description: Reset specified [gcode_macro ...] variables to their original values from configuration when Klipper started.
- MACRO: Name of the GCODE macro containing the variables to reset.
- VARIABLES: Comma-separated list of variable names to reset (do not include the "variable_" prefix).
- SKIP_UNDEFINED_VARIABLES: (optional) If true, skips variables that are not defined in the macro without raising an error. Default is false.
- QUIET: (optional) If true, suppresses console echo messages for each reset variable. Default is false.
gcode:
{% set macro = params.MACRO|trim() %}
{% set vars = params.VARIABLES.split(",") %}
{% set skip_undefined_vars = params.SKIP_UNDEFINED_VARIABLES|default("false")|lower in ("true", "1", "yes") %}
{% set quiet = params.QUIET|default("false")|lower in ("true", "1", "yes") %}
{% set obj_name = "gcode_macro %s" % macro %}
{% set obj = printer[ obj_name ] %}
{% if obj is not defined %}
{ action_raise_error("[gcode_macro %s] is not defined" % macro) }
{% endif %}
{% set settings = printer.fastconfig.settings[obj_name|lower] %}
{% if settings is not defined %}
{ action_raise_error("No settings found for [gcode_macro %s]" % macro) }
{% endif %}
# Check that all the variables exist before resetting any of them
{% for var in vars %}
{% if obj[var] is defined %}
{% if settings["variable_%s" % var] is not defined %}
{ action_raise_error("Variable '%s' is not defined in settings for [gcode_macro %s]" % (var, macro)) }
{% endif %}
{% else %}
{% if not skip_undefined_vars %}
{ action_raise_error("Variable '%s' is not defined in [gcode_macro %s]" % (var, macro)) }
{% endif %}
{% endif %}
{% endfor %}
# Reset
{% for var in vars %}
{% set var_value = obj[var] %}
{% if var_value is defined %}
{% set v = settings["variable_%s" % var] %}
{% if v != var_value|string %}
{% if var_value is string %}
{% set v = '"\'' ~ v|replace('"', '\\"')|replace("'", "\\'") ~ '\'"' %}
{% endif %}
SET_GCODE_VARIABLE MACRO={macro} VARIABLE={var} VALUE={v}
{% if not quiet %}
CONSOLE_ECHO MSG="Reset {macro} variable {var} to original value: {v} (was {obj[var]})"
{% endif %}
{% endif %}
{% endif %}
{% endfor %}

[gcode_macro _SHOW_GCODE_VARIABLES]
description: Show current values of specified [gcode_macro ...] variables.
- MACRO: Name of the GCODE macro containing the variables to show.
- VARIABLES: Comma-separated list of variable names to show (do not include the "variable_" prefix).
- SKIP_UNDEFINED_VARIABLES: (optional) If true, skips variables that are not defined in the macro without raising an error. Default is false.
- PAD: (optional) If defined, provide a single character to use for padding variable names to align values in a tabular format in the console output. Default is no padding.
gcode:
{% set macro = params.MACRO|trim() %}
{% set vars = params.VARIABLES.split(",") %}
{% set skip_undefined_vars = params.SKIP_UNDEFINED_VARIABLES|default("false")|lower in ("true", "1", "yes") %}
{% set pad = params.PAD|default("") %}
{% set obj_name = "gcode_macro %s" % macro %}
{% set obj = printer[ obj_name ] %}
{% if obj is not defined %}
{ action_raise_error("[gcode_macro %s] is not defined" % macro) }
{% endif %}
# Check that all the variables exist, determine max length.
{% set ns = namespace() %}
{% set ns.max_len = 0 %}
{% for var in vars %}
{% if obj[var] is defined %}
{% set ns.max_len = (ns.max_len, var|length)|max %}
{% else %}
{% if not skip_undefined_vars %}
{ action_raise_error("Variable '%s' is not defined in [gcode_macro %s]" % (var, macro)) }
{% endif %}
{% endif %}
{% endfor %}
{% for var in vars %}
{% if obj[var] is defined %}
{% if pad %}
{% set padding = pad * (ns.max_len - var|length) %}
CONSOLE_ECHO MSG="{var}{padding} {obj[var]}"
{% else %}
CONSOLE_ECHO MSG="{var}: {obj[var]}"
{% endif %}
{% endif %}
{% endfor %}