This was working great for me until I updated Klipper the other day. Now the “delayed gcode” portion is not working properly and throws the following error in klippy.log:
Error evaluating ‘delayed_gcode heat_soaker:gcode’: jinja2.exceptions.UndefinedError: ‘params’ is undefined
I’ve been tinkering with it for a few days and have been stumped.
Full error:
Error evaluating 'delayed_gcode heat_soaker:gcode': jinja2.exceptions.UndefinedError: 'params' is undefined
Traceback (most recent call last):
File "/home/pi/klipper/klippy/extras/gcode_macro.py", line 61, in render
return str(self.template.render(context))
File "/home/pi/klippy-env/lib/python3.9/site-packages/jinja2/environment.py", line 1090, in render
self.environment.handle_exception()
File "/home/pi/klippy-env/lib/python3.9/site-packages/jinja2/environment.py", line 832, in handle_exception
reraise(*rewrite_traceback_stack(source=source))
File "/home/pi/klippy-env/lib/python3.9/site-packages/jinja2/_compat.py", line 28, in reraise
raise value.with_traceback(tb)
File "<template>", line 2, in top-level template code
File "/home/pi/klippy-env/lib/python3.9/site-packages/jinja2/environment.py", line 471, in getattr
return getattr(obj, attribute)
jinja2.exceptions.UndefinedError: 'params' is undefined
Script running error
Traceback (most recent call last):
File "/home/pi/klipper/klippy/extras/gcode_macro.py", line 61, in render
return str(self.template.render(context))
File "/home/pi/klippy-env/lib/python3.9/site-packages/jinja2/environment.py", line 1090, in render
self.environment.handle_exception()
File "/home/pi/klippy-env/lib/python3.9/site-packages/jinja2/environment.py", line 832, in handle_exception
reraise(*rewrite_traceback_stack(source=source))
File "/home/pi/klippy-env/lib/python3.9/site-packages/jinja2/_compat.py", line 28, in reraise
raise value.with_traceback(tb)
File "<template>", line 2, in top-level template code
File "/home/pi/klippy-env/lib/python3.9/site-packages/jinja2/environment.py", line 471, in getattr
return getattr(obj, attribute)
jinja2.exceptions.UndefinedError: 'params' is undefined
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/pi/klipper/klippy/extras/delayed_gcode.py", line 34, in _gcode_timer_event
self.gcode.run_script(self.timer_gcode.render())
File "/home/pi/klipper/klippy/extras/gcode_macro.py", line 66, in render
raise self.gcode.error(msg)
gcode.CommandError: Error evaluating 'delayed_gcode heat_soaker:gcode': jinja2.exceptions.UndefinedError: 'params' is undefined
Full set of macros:
[gcode_macro HEAT_SOAK]
description: heats the bed for a while
variable_target_temp: 0
variable_stage: None ## heating -> soaking -> done -> None
## in seconds
variable_check_interval: 10
variable_soak_time_remaining: 0
variable_total_time_elapsed: 0
gcode:
{% set TARGET = params.TARGET | default(0) | float %}
{% set DURATION = (params.DURATION | default(5) | int) * 60 %} ## minutes to seconds
SET_GCODE_VARIABLE MACRO=HEAT_SOAK VARIABLE=target_temp VALUE={ TARGET }
SET_GCODE_VARIABLE MACRO=HEAT_SOAK VARIABLE=stage VALUE="'heating'"
SET_GCODE_VARIABLE MACRO=HEAT_SOAK VARIABLE=soak_time_remaining VALUE={ DURATION }
SET_GCODE_VARIABLE MACRO=HEAT_SOAK VARIABLE=total_time_elapsed VALUE=0
;; fire up the heater
SET_HEATER_TEMPERATURE HEATER=heater_bed TARGET={ TARGET }
;; run the fan to circulate air
_SET_FAN_SPEED PERCENT=50
;; put the bed and nozzle where they're a safe distance apart
G28
CENTER
M84 ;; turn off steppers
UPDATE_DELAYED_GCODE ID=heat_soaker DURATION={ check_interval }
[gcode_macro CANCEL_HEAT_SOAK]
description: cancels an in-progress HEAT_SOAK cycle
gcode:
SET_GCODE_VARIABLE MACRO=HEAT_SOAK VARIABLE=stage VALUE="'cancel'"
UPDATE_DELAYED_GCODE ID=heat_soaker DURATION=1
[delayed_gcode heat_soaker]
gcode:
## debug
;{ action_respond_info( printer['gcode_macro HEAT_SOAK'] | tojson )}
{% set heat_soak = printer["gcode_macro HEAT_SOAK"] %}
## update total time elapsed
{% set total_time_elapsed = heat_soak.total_time_elapsed + heat_soak.check_interval %}
SET_GCODE_VARIABLE MACRO=HEAT_SOAK VARIABLE=total_time_elapsed VALUE={ total_time_elapsed }
{% set stage = heat_soak.stage %}
{% if stage == "heating" and printer.heater_bed.temperature >= heat_soak.target_temp %}
{% set stage = "soaking" %}
{% endif %}
{% if stage == "soaking" %}
## update soak countdown
{% set soak_time_remaining = [heat_soak.soak_time_remaining - heat_soak.check_interval, 0] | max %}
SET_GCODE_VARIABLE MACRO=HEAT_SOAK VARIABLE=soak_time_remaining VALUE={ soak_time_remaining }
{% if soak_time_remaining == 0 %}
{% set stage = "done" %}
{% endif %}
{% endif %}
SET_GCODE_VARIABLE MACRO=HEAT_SOAK VARIABLE=stage VALUE="'{ stage }'"
{% if stage in ("done", "cancel") %}
{% if stage == "cancel" %}
{% set stage = "done" %}
TURN_OFF_HEATERS
M107 ; turn off fan
M117 { "soak cancelled after ~%.1fm" | format(total_time_elapsed / 60.0) }
{% else %}
M117 { "soak complete after %.1fm" | format(total_time_elapsed / 60.0) }
{% endif %}
## reset all state vars, except stage, which may be queried via the api
SET_GCODE_VARIABLE MACRO=HEAT_SOAK VARIABLE=target_temp VALUE=0
SET_GCODE_VARIABLE MACRO=HEAT_SOAK VARIABLE=soak_time_remaining VALUE=0
SET_GCODE_VARIABLE MACRO=HEAT_SOAK VARIABLE=total_time_elapsed VALUE=0
{% else %}
{% if total_time_elapsed % 90 == 0 %}
## output status periodically
{% if stage == "heating" %}
M117 { "heating -- %.1fm elapsed" | format(total_time_elapsed / 60.0) }
{% elif stage == "soaking" %}
M117 { "soaking -- %.1fm remaining" | format(soak_time_remaining / 60.0) }
{% endif %}
{% endif %}
## trigger ourselves again
UPDATE_DELAYED_GCODE ID=heat_soaker DURATION={ heat_soak.check_interval }
## dwell for 1ms to prevent from going idle
G4 P1
{% endif %}
[gcode_macro _SET_FAN_SPEED]
gcode:
M106 S{ (params.PERCENT | float) * 255 / 100 }
[gcode_macro CENTER]
gcode:
G90
G0 X{ printer.toolhead.axis_maximum.x/2 } Y{ printer.toolhead.axis_maximum.y/2 } Z{ printer.toolhead.axis_maximum.z/2 } F7200
