How to Add Confirmation for Cancel_Print Only When Commanded from the UI

Basic Information:

Printer Model: Custom
MCU / Printerboard: Manta M8P
Host / SBC CB1
klippy.log -

Describe your issue:

Hi everyone,

The other day, I accidentally canceled a large print from the UI, so I had to generate a recovery file and restart the print from the failed point. To avoid this, I modified the CANCEL_PRINT macro to include a confirmation prompt.

Here’s the code I initially wrote:


 [gcode_macro CANCEL_PRINT]
rename_existing: CANCEL_PRINT_BASE
gcode:

    RESPOND TYPE=command MSG="action:prompt_end"
    RESPOND TYPE=command MSG="action:prompt_begin CANCELAR IMPRESION"
    RESPOND TYPE=command MSG="action:prompt_text ¿Está seguro de que quiere cancelar la impresión?"
    RESPOND TYPE=command MSG="action:prompt_button Si, CANCELAR|CANCEL|error"
    RESPOND TYPE=command MSG="action:prompt_button No, SEGUIR IMPRIMIENDO|RESPOND TYPE=command MSG=\"action:prompt_end\"|primary"
    RESPOND TYPE=command MSG="action:prompt_show"

[gcode_macro CANCEL]
description: Cancel the actual running print
gcode:
  ##### get user parameters or use default #####
  {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %}
  {% set allow_park = client.park_at_cancel|default(false)|lower == 'true' %}
  {% set retract = client.cancel_retract|default(5.0)|abs %}
  ##### define park position #####
  {% set park_x = "" if (client.park_at_cancel_x|default(none) is none)
            else "X=" ~ client.park_at_cancel_x %}
  {% set park_y = "" if (client.park_at_cancel_y|default(none) is none)
            else "Y=" ~ client.park_at_cancel_y %}
  {% set custom_park = park_x|length > 0 or park_y|length > 0 %}
  ##### end of definitions #####
  # restore idle_timeout time if needed
  {% if printer['gcode_macro RESUME'].restore_idle_timeout > 0 %}
    SET_IDLE_TIMEOUT TIMEOUT={printer['gcode_macro RESUME'].restore_idle_timeout}
  {% endif %}
  {% if (custom_park or not printer.pause_resume.is_paused) and allow_park %} _TOOLHEAD_PARK_PAUSE_CANCEL {park_x} {park_y} {% endif %}
  _CLIENT_RETRACT LENGTH={retract}
  TURN_OFF_HEATERS
  M106 S0
  {client.user_cancel_macro|default("")}
  SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=idle_state VALUE=False
  # clear pause_next_layer and pause_at_layer as preparation for next print
  SET_PAUSE_NEXT_LAYER ENABLE=0
  SET_PAUSE_AT_LAYER ENABLE=0 LAYER=0
  CANCEL_PRINT_BASE

However, this solution is far from ideal. Some safety systems in my printer need to issue a CANCEL_PRINT command automatically when something unusual happens. Currently, these commands also trigger the confirmation prompt, which is not what I want. I need the confirmation prompt to appear only when the cancel command is issued from the UI.

I asked ChatGPT for a solution and it came with this:

[gcode_macro CANCEL_PRINT]
rename_existing: CANCEL_PRINT_BASE
gcode:
    {% if printer['webhooks'].state|default('') == 'operational' %}
        RESPOND TYPE=command MSG="action:prompt_end"
        RESPOND TYPE=command MSG="action:prompt_begin CANCELAR IMPRESION"
        RESPOND TYPE=command MSG="action:prompt_text ¿Está seguro de que quiere cancelar la impresión?"
        RESPOND TYPE=command MSG="action:prompt_button Si, CANCELAR|CANCEL|error"
        RESPOND TYPE=command MSG="action:prompt_button No, SEGUIR IMPRIMIENDO|RESPOND TYPE=command MSG=\"action:prompt_end\"|primary"
        RESPOND TYPE=command MSG="action:prompt_show"
    {% else %}
        CANCEL
    {% endif %}

This code , according to ChatGPT, checks if the command originates from an operational interface (like the UI) and only prompts for confirmation in that case. Otherwise, it directly executes the cancel operation, ensuring that critical safety systems can function without interruption.

I imagine this is a common issue. Has anyone else encountered this and implemented a better or more efficient solution? Is there perhaps a built-in method in Klipper to handle this use case that I’m not aware of?

Any help or feedback would be greatly appreciated! :blush: