diff --git a/configuration/macros/heatsoaking.cfg b/configuration/macros/heatsoaking.cfg new file mode 100644 index 000000000..f705a3907 --- /dev/null +++ b/configuration/macros/heatsoaking.cfg @@ -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 %} diff --git a/configuration/macros/util.cfg b/configuration/macros/util.cfg index e57404a7a..100ca321d 100644 --- a/configuration/macros/util.cfg +++ b/configuration/macros/util.cfg @@ -494,4 +494,92 @@ gcode: [gcode_macro _STOP_AND_RAISE_ERROR] gcode: M84 - _RAISE_ERROR MSG="{params.MSG}" \ No newline at end of file + _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 %}