Writing a resume GCODE script using last_temperature

What is the problem?
Good day Guys,

I was wondering if anyone could assist me with understanding how to write a script for the Resume GCODE function that uses the 'last_temperature' template variable.

Reading the 'Context' section of the GCODE Scripts docs page, I attempted the following GCODE, however this is not working.

{% if last_temperature[0]['target'] is not none %}
M109 S{{last_temperature[0]['target']}}
{% endif %}

{% if last_temperature[b]['target'] is not none %}
M190 S{{last_temperature[b]['target']}}
{% endif %}

As I am new to OctoPrint, GCODE and 3D Printing any assistance would be greatly appreciated.

OctoPrint Version : 1.3.6
OctoPi Version : 0.14
Printer : Creality-CR10

Also, please note that this is what I got when tailing the octoprint.log

2018-03-26 22:28:08,500 - octoprint.plugins.filamentreload - INFO - Out of filament!
2018-03-26 22:28:08,502 - octoprint.plugins.filamentreload - INFO - Pausing print.
2018-03-26 22:28:40,771 - octoprint.plugins.filamentreload - INFO - Filament detected!
2018-03-26 22:30:39,178 - octoprint.plugins.filamentreload - INFO - PrintResumed: Enabling filament sensor.
2018-03-26 22:30:39,277 - octoprint.settings - ERROR - Exception while trying to render script gcode:beforePrintResumed
Traceback (most recent call last):
  File "/home/pi/oprint/local/lib/python2.7/site-packages/OctoPrint-1.3.6-py2.7.egg/octoprint/settings.py", line 1398, in loadScript
    script = template.render(**context)
  File "/home/pi/oprint/local/lib/python2.7/site-packages/Jinja2-2.8.1-py2.7.egg/jinja2/environment.py", line 989, in render
    return self.environment.handle_exception(exc_info, True)
  File "/home/pi/oprint/local/lib/python2.7/site-packages/Jinja2-2.8.1-py2.7.egg/jinja2/environment.py", line 754, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/pi/.octoprint/scripts/gcode/beforePrintResumed", line 5, in top-level template code
    {% if last_temperature[b]['target'] is not none %}
  File "/home/pi/oprint/local/lib/python2.7/site-packages/Jinja2-2.8.1-py2.7.egg/jinja2/environment.py", line 389, in getitem
    return obj[argument]
UndefinedError: dict object has no element Undefined
2018-03-26 22:31:13,034 - octoprint.plugins.filamentreload - INFO - PrintCancelled: Disabling filament sensor.
2018-03-26 22:31:13,137 - octoprint.plugins.filamentreload - INFO - PrintFailed: Disabling filament sensor.

I have tried converting the GCODE to the following, but all that happens now is that the print starts immediately without pre heating either the extruder or the heated bed.

{% if last_temperature[0]['target'] is not none %}
M109 S{{last_temperature[0]['target']}}
{% else %}
M109 S205
{% endif %}

{% if last_temperature['b']['target'] is not none %}
M190 S{{last_temperature['b']['target']}}
{% else %}
M190 S60
{% endif %}

It would make sense to share what is actually generated and going over the line to your printer (see the Terminal tab).

This works for me:

{% if pause_temperature[0] and pause_temperature[0]['target'] is not none %}
    M109 S{{ pause_temperature[0]['target'] }}
{% else %}
    M104 S0
{% endif %}

{% if pause_temperature['b'] and pause_temperature['b']['target'] is not none %}
    M190 S{{ pause_temperature['b']['target'] }}
{% else %}
    M140 S0
{% endif %}

A more complex example that also takes care of ensuring to iterate over all defined tools and send the corresponding T parameter with the temperature command (but only if there are more than one extruders defined) would be this:

{% for tool in range(printer_profile.extruder.count) %}
    {% if pause_temperature[tool] and pause_temperature[tool]['target'] is not none %}
        {% if tool == 0 and printer_profile.extruder.count == 1 %}
            M109 T{{ tool }} S{{ pause_temperature[tool]['target'] }}
        {% else %}
            M109 S{{ pause_temperature[tool]['target'] }}
        {% endif %}
    {% else %}
        {% if tool == 0 and printer_profile.extruder.count == 1 %}
            M104 T{{ tool }} S0
        {% else %}
            M104 S0
        {% endif %}
    {% endif %}
{% endfor %}

{% if printer_profile.heatedBed %}
    {% if pause_temperature['b'] and pause_temperature['b']['target'] is not none %}
        M190 S{{ pause_temperature['b']['target'] }}
    {% else %}
        M140 S0
    {% endif %}
{% endif %}

Note that in both cases I use pause_temperature instead of last_temperature. last_temperature is always the last temperature reported by your printer (hence the name), so if you use that, you are basically doing a non operation (e.g. the last temperature of the hotend reported by your printer was 24Β°C because you shut off the heater after pausing, now you issue a M109 S24.0 which does nothing). pause_temperature on the other hand is recorded when you pause the print (as is cancel_temperature when you cancel the print), so is probably rather what you want.

Example of this in action:

Changing monitoring state from "Pausing" to "Paused"
Recv: ok N1011
Recv: T:210.00 /210.00 B:21.30 /0.00 @:64
Send: N1012 M104 S0*87
Recv: ok N1012
Recv: T:208.41 /0.00 B:21.30 /0.00 @:64
Send: N1013 M140 S0*86
Recv: ok N1013
[...]
Changing monitoring state from "Paused" to "Printing"
Send: N1014 M109 T0 S210.0*5
Recv: T:106.86
Recv: T:116.88
Recv: T:116.88 /210.00 B:21.30 /0.00 @:64
Recv: T:126.88
Recv: echo:busy: processing
Recv: T:136.89
Recv: T:136.89 /210.00 B:21.30 /0.00 @:64
Recv: T:146.89
Recv: echo:busy: processing
Recv: T:156.90
Recv: T:156.90 /210.00 B:21.30 /0.00 @:64
Recv: T:166.90
Recv: echo:busy: processing
Recv: T:176.90
Recv: T:176.90 /210.00 B:21.30 /0.00 @:64
Recv: T:186.91
Recv: echo:busy: processing
Recv: T:196.91
Recv: T:196.91 /210.00 B:21.30 /0.00 @:64
Recv: T:206.91
Recv: echo:busy: processing
Recv: T:210.00
Recv: T:210.00 /210.00 B:21.30 /0.00 @:64
Recv: ok N1014
Send: N1015 M190 S0.0*67
Recv: ok N1015
Send: N1016 G1 X113.872 Y150.720 E4.8138*109
Recv: ok N1016
3 Likes

Thank you for the information and for the code.

I can see that I was using the wrong template variables, however I could only find a small amount of variables available thus I wasn't aware of the pause_temperature variable. If I may ask, where could I find a list of all available variables, currently I am looking at the following URL

http://docs.octoprint.org/en/master/features/gcode_scripts.html#predefined-scripts

With that said, I surely would still have had issues writing the above procedure, so I must truly thank you for the assistance that you have given me.

If I may ask, the code itself feels very 'blade' templatish. Is this the case?

I will make sure to share the terminal information in future, thanks for the heads up.

Kind Regards
Lionel

Scroll down just a tiny bit further to "Context".

The template syntax is Jinja2. I have to admit I've never heard of blade.

Sorry to revive this ancient topic, but I just stumbled onto it trying to improve my Octoprint pause functionality. Looking at the code below from the post by foosel, I have two questions.

{% for tool in range(printer_profile.extruder.count) %} 
   {% if pause_temperature[tool] and pause_temperature[tool]['target'] is not none %} 
      {% if tool == 0 and printer_profile.extruder.count == 1 %} 
         M109 T{{ tool }} S{{ pause_temperature[tool]['target'] }}
      {% else %} 
         M109 S{{ pause_temperature[tool]['target'] }} 
      {% endif %} 
   {% else %} 
      {% if tool == 0 and printer_profile.extruder.count == 1 %} 
         M104 T{{ tool }} S0 
      {% else %} 
         M104 S0 
      {% endif %} 
   {% endif %}
 {% endfor %} 
{% if printer_profile.heatedBed %} 
   {% if pause_temperature['b'] and pause_temperature['b']['target'] is not none %} 
        M190 S{{ pause_temperature['b']['target'] }}
   {% else %} 
       M140 S0 
   {% endif %} 
{% endif %}

First, unless I'm mistaken, the "if" statements checking for the number of extruders are backwards - i.e. I think it should be like below? i.e. if there's only one extruder, don't use the "T" in the M109 statement.

{% if tool == 0 and printer_profile.extruder.count == 1 %}
      M109 S{{ pause_temperature[tool]['target'] }}
{% else %}
      M109 T{{ tool }} S{{ pause_temperature[tool]['target'] }}
{% endif %}

Second question is whether there is a concept of global variables in GCODE script. The current script would not re-set the fan speed to its prior value after resume if I turn it off at pause (which I'd like to do). Is there a clever way to extract the fan speed via a plug-in and store in a global variable that could be used in the resume script?

Thanks in advance for any assistance.

You are right.

Welcome to the nightmare that is 3d printer communication. Believe it or not, the fan speed is a "write-only" value. I have absolutely no way to extract it from the printer again. Same goes for the current tool and feedrate btw, and for the feedrate and flowrate modifier. So if I want to be able to track the current value I'll have to do it myself and pray to the deities that the user doesn't fiddle around with the controller on the printer and modifies it outside of my control or knowledge. Which is what is done for the current tool and the feedrate, but currently not for anything else because frankly it is just messy.

In a nutshell: nope, currently not. Could be changed, though I'm not completely sure if I want to open that can of worms.