# Copyright (C) 2023 Justin Schuh # # This file may be distributed under the terms of the GNU GPLv3 license. [gcode_macro _km_print_status] variable_last_status: 'none' variable_status_stack: [] variable_command_list: {} variable_status_list: [ 'ready', # Printer is ready to receive a job 'filament_load', # Loading filament 'filament_unload', # Unloading filament 'bed_heating', # Waiting for the bed to reach target 'chamber_heating', # Waiting for the chamber to reach target 'homing', # Homing any axis 'leveling_gantry', # Performing quad gantry-leveling 'calibrating_z', # Performing z-tilt adjustment 'meshing', # Calibrating a bed mesh 'extruder_heating', # Waiting for the extruder to reach target 'purging', # Printing purge line 'printing', # Actively printing 'pausing', # Print is paused 'cancelling', # Print is being cancelled 'completing', # Print completed ] gcode: {% set ACTION = params.ACTION|trim|upper %} {% set STATUS = params.STATUS|default("")|trim|lower %} # Add a status handler. {% if ACTION == "ADD_EVENT" %} {% set COMMAND = params.COMMAND %} {% set ARGS = params.ARGS|default(0)|int != 0 %} {% set TYPE = params.TYPE|default('ENTER')|trim|upper %} {% set WHEN = params.WHEN|default('PRINTING')|trim|upper %} {% set FILTER_ENTER = (params.FILTER_ENTER|default("")|trim|lower).split(',')| select()|unique|list %} {% set FILTER_LEAVE = (params.FILTER_LEAVE|default("")|trim|lower).split(',')| select()|unique|list %} {% set STATUSES = STATUS.split(',')|map('trim')|list %} {% for s in (STATUSES if STATUSES[0] != 'all' else status_list) %} {% if not s in command_list %} {% set dummy = command_list.__setitem__(s,[]) %} {% endif %} {% set dummy = command_list[s].append({'cmd':COMMAND, 'args':ARGS, 'type':TYPE, 'when':WHEN, 'filt_e':FILTER_ENTER, 'filt_l':FILTER_LEAVE}) %} {% endfor %} # Change the current status. {% elif ACTION == "CHANGE" %} {% if params.RESET_STACK|default(0)|int %} {% for dummy in range(status_stack|length) %} {% set dummy = status_stack.pop() %} {% endfor %} # TODO: Once python 3 is required, switch the for loop above to this: #{% set dummy = status_stack.clear() %} {% elif STATUS == "pop_status" %} {% set STATUS = (status_stack|default(['ready'], True)).pop() %} {% endif %} {% if STATUS not in status_list %} {action_raise_error("Status '%s' not valid."|format(STATUS))} {% endif %} {% if STATUS != last_status %} {% set is_printing = printer["gcode_macro print_start_set"].print.PRINT_START_PHASE| default("")|length != 0 %} {% set print_states = ('ALWAYS', 'PRINTING' if is_printing else 'IDLE') %} # Process commands for the state we're leaving first. {% for c in command_list[last_status]|default([]) %} {% if c.type in ('BOTH','LEAVE') and c.when in print_states and (not c.filt_l or STATUS in c.filt_l) %} M400 {c.cmd}{% if c.args %} TYPE=LEAVE WHEN={print_states[1] } LAST_STATUS={last_status} NEXT_STATUS={STATUS}{% endif %} {% endif %} {% endfor %} # Process commands for the state we're entering last. {% for c in command_list[STATUS]|default([]) %} {% if c.type in ('BOTH','ENTER') and c.when in print_states and (not c.filt_e or STATUS in c.filt_e) %} M400 {c.cmd}{% if c.args %} TYPE=ENTER WHEN={print_states[1] } LAST_STATUS={last_status} NEXT_STATUS={STATUS}{% endif %} {% endif %} {% endfor %} SET_GCODE_VARIABLE MACRO=_km_print_status VARIABLE=last_status VALUE="'{ STATUS}'" {% endif %} # Push the current status onto the stack. {% elif ACTION == "PUSH_STATUS" %} {% set dummy = status_stack.append(last_status) %} # Illegal operation. {% else %} {action_raise_error("Action '%s' not valid."|format(ACTION))} {% endif %} [gcode_macro gcode_on_print_status] description: Adds a gcode command for a status event. Usage: GCODE_ON_PRINT_STATUS STATUS= COMMAND= [ARGS=<1|0>] [WHEN=] [TYPE=] [FILTER_ENTER=] [FILTER_LEAVE=] gcode: {% set STATUS = (params.STATUS|lower).split(',')|map('trim')|list %} {% set TYPE = params.TYPE|default('ENTER')|trim|upper %} {% set WHEN = params.WHEN|default('PRINTING')|trim|upper %} {% set FILTER_ENTER = (params.FILTER_ENTER|default("")|trim|lower).split(',')|select()|list %} {% set FILTER_LEAVE = (params.FILTER_LEAVE|default("")|trim|lower).split(',')|select()|list %} # Error checking {% set status_list = printer["gcode_macro _km_print_status"].status_list %} {% for s in STATUS %} {% if not (s in status_list or s == 'all' and STATUS|length == 1) %} {action_raise_error("STATUS parameter '%s' not valid."|format(s))} {% endif %} {% endfor %} {% if TYPE not in ('ENTER', 'LEAVE', 'BOTH') %} {action_raise_error("TYPE paramater '%s' not valid."|format(TYPE))} {% elif WHEN not in ('PRINTING', 'IDLE', 'ALWAYS') %} {action_raise_error("WHEN parameter '%s' not valid."|format(WHEN))} {% elif TYPE == 'ENTER' and FILTER_LEAVE %} {action_raise_error("FILTER_LEAVE not valid with TYPE=ENTER.")} {% elif TYPE == 'LEAVE' and FILTER_ENTER %} {action_raise_error("FILTER_ENTER not valid with TYPE=LEAVE.")} {% endif %} {% for f in FILTER_ENTER %} {% if f not in status_list %} {action_raise_error("FILTER_ENTER parameter '%s' not valid."|format(f))} {% endif %} {% endfor %} {% for f in FILTER_LEAVE %} {% if f not in status_list %} {action_raise_error("FILTER_LEAVE parameter '%s' not valid."|format(f))} {% endif %} {% endfor %} # Run the command. _KM_PRINT_STATUS ACTION=ADD_EVENT {rawparams}