How to read temp sensor during execution of print start macro

Hi,

I’m trying to read a chamber temp sensors value during the execution of my print start macro.

My macro looks something like this:

[gcode_macro PRINT_START]
gcode:
  {% set TEMP_BED = params.BED|default(100)|int %}
  {% set TEMP_EXTRUDER = params.EXTRUDER|default(240)|int %}
  {% set TEMP_CHAMBER = params.CHAMBER|default(40)|int %}
  {% set TEMP_CHAMBER_CURRENT = ( printer["temperature_sensor chamber"].temperature )|float %}

  SET_GCODE_OFFSET Z=0.0 ; reset offset

  M117 Homing...
  BED_MESH_CLEAR ; clear bed mesh
  G28 HIDE=0 ; home all axies and don't hide the probe
  G1 X{ MAX_X_POS / 2 } Y{ MAX_Y_POS / 2 } F4800 ; go to the center of the bed
  G90 ; absolute positioning

  M117 Heatup...
  TEMPERATURE_WAIT SENSOR=heater_bed MINIMUM={ ( TEMP_BED - 3 )|int } ; wait for bed temp
  SET_HEATER_TEMPERATURE HEATER=extruder TARGET=180 ; set hot end temp and continue
  TEMPERATURE_WAIT SENSOR=heater_bed MINIMUM={ ( TEMP_BED )|int } MAXIMUM={ ( TEMP_BED + 5 )|int } ; wait for bed temp
  TEMPERATURE_WAIT SENSOR=extruder MINIMUM={ ( 180 - 1 )|int } MAXIMUM={ ( 180 + 3 )|int } ; wait for hot end temp
  TEMPERATURE_WAIT SENSOR="temperature_sensor chamber" MINIMUM={ ( TEMP_CHAMBER + 1 )|int } ; wait for chamber temp

  M117 Meshing...
  PROBE_GET ; pobieramy sonde
  BED_MESH_CALIBRATE ; tworzymy siatke stolu
  PROBE_HIDE ; chowamy sonde

  G0 X{ MIN_X_POS } Y{ MAX_Y_POS - 20 } F3000 ; move the head
  G0 Z0.25 F3000 ; move the bed
  M117 Heatup...
  SET_HEATER_TEMPERATURE HEATER=extruder TARGET={ ( TEMP_EXTRUDER )|int } ; set hot end temp and continue
  TEMPERATURE_WAIT SENSOR=extruder MINIMUM={ ( TEMP_EXTRUDER - 1 )|int } MAXIMUM={ ( TEMP_EXTRUDER + 3 )|int } ; wait for hot end temp
  M107 ; turn off the print fan after heatup

  M117 Nozzle cleaning...
  NOZZLE_CLEAN ; clean the nozzle on the silicone brush  

  M117 Printing...
  {% set TEMP_CHAMBER_CURRENT = ( printer["temperature_sensor chamber"].temperature )|float %}
  SET_GCODE_OFFSET Z={ ( ( ( TEMP_CHAMBER_CURRENT )|float * 0.01 ) * ( -1 ) )|float } ; set offset based on current chamber temp

and according to this:

Important! Macros are first evaluated in entirety and only then are the resulting commands executed. If a macro issues a command that alters the state of the printer, the results of that state change will not be visible during the evaluation of the macro.

the bit after “M117 Printing…” will not ever work properly.

I would be very greatfull if any one of the macro gurus here would explain to me how can I read that chamber sensor and put it’s value in a variable in any place in the above print start macro.

Thank you in advance for any help.

If you want to read the updated chamber temperature, either you’ll have to put the code that reads the chamber temperature in a separate macro, or use something like DynamicMacros.

Are these the only 2 options?
After putting the code that reads the chamber in a separate macro that temp still won’t be accessible from print start macro?

@Szafran I think I did something similar to what you’re looking for. I don’t use it anymore, because I found a different solution for what I was trying to achieve.

I am not completely confident this worked as expected, but I think it’s worth a shot:

; Waits up to "pre_heat_max_wait_seconds" for the hotend temp to reach "pre_heat_temp"
{% for _ in range(pre_heat_max_wait_seconds) %}
    {% if printer.extruder.temperature < pre_heat_temp|float %}
        G4 P1000 
    {% endif %}
{% endfor %}

I don’t think you need to store it in a variable, you can do it in a one-liner to get to achieve what you want. If you’re sure you’re accessing the temperature correctly, then just put it inside the interpolation. I would simply do this:

SET_GCODE_OFFSET Z={ ( ( printer["temperature_sensor chamber"].temperature)|float * 0.01 ) * ( -1 ) )|float } ; set offset based on current chamber temp

If not, maybe you want to use this macro to find the variable:

[gcode_macro SEARCH_VARS]
gcode:
    {% set search = params.S|lower %}
    {% set ns = namespace() %}
    {% for item in printer  %}
        {% if ' ' in item %}
            {% set ns.path = ['printer', "['%s']" % (item), ''] %}
        {% else %}
            {% set ns.path = ['printer.', item, ''] %}   
        {% endif %} 

        {% if search in ns.path|lower %}
            { action_respond_info(ns.path|join) }
        {% endif %} 

        {% if printer[item].items() %}
            {% for childkey, child in printer[item].items() recursive %}
                {% set ns.path = ns.path[:loop.depth|int + 1] %}

                {% if ' ' in childkey %}
                    {% set null = ns.path.append("['%s']" % (childkey)) %}
                {% else %}
                    {% set null = ns.path.append(".%s" % (childkey)) %}
                {% endif %} 

                {% if child is mapping  %}
                    { loop(child.items()) }
                {% else %}
                    {% if search in ns.path|lower %}
                        { action_respond_info("%s : %s" % (ns.path|join, child)) }
                    {% else %}
                        {% if search in child|lower %}
                            { action_respond_info("%s : %s" % (ns.path|join, child)) } 
                        {% endif %} 
                    {% endif %} 
                {% endif %} 
                
            {% endfor %}
        {% endif %} 
    {% endfor %}

I don’t think this applies to your situation. What this statement is saying is that if you tried to get that offset you are altering, to influence the end macro result, that will not work, as during evaluation, is when a for loop gets expanded into repeated statements. If you used a state change to influence how many iterations that loop would have, it would fail to achieve the desired result.

You can think of a macro in a similar way that you have source code compiled into native code. A macro does not work like a script, and control statements such as for/if and etc, are expanded (or compiled) before execution. It works more like a template than a script.

That’s why something like this pseudo code would not work:

Move X to X+50
If X > 50, then X = 50

When the macro is evaluated and expanded that if will disappear. Suppose X = 3 before print start. Then:

During evaluation the macro will be expanded to

Move X to X+50
;X = 50 this line will not be in the macro during execution. It would only be there if X was > 50 already before the print start.

During evaluation, the movement command will not have executed yet so X will not be > 50 (will still be 3), so the expansion will happen before the expected 53 realizes, therefore the “compiled” if will issue an empty statement.

During execution the X will finally become 53, but by this time the condition was already interpreted as false.

Your command to set the offset will work because it’s not conditional and will simply apply an offset based on a reading. So if that is not working it’s likely because there is a problem with accessing the temperature with the variable you’re reading. Try to print the output of that to confirm.

And now thinking of my example, it’s exactly an example of what would NOT work due to this flow I hope I helped explain. As by the time it’s evaluated the nozzle would not have started heating yet and the for would simply issue wait commands equal to the maximum waiting time as the condition would never be reached to falsify the statement that adds the wait command.

@tinkerman thank you for your input, but I’ve spent about 2 days before coming here for help on trying to solve this thing, and I’ve allready tried what you’re suggesting. That statement is completelly true - it’s all evaluated before g-codes are executed - you can try it - everything is evaluated and then just executed with the set_gcode_offset like this:

SET_GCODE_OFFSET Z=0.234

so I always got the offset calculated from the chamber temp read at the begginig of the print start macro.

You can test it simply by adding to your print start macro a few temperature reads followed by action responds. Place them in different places. After executing the print start macro you’ll see all the responds in console almost immediately with the same temp readings.

EDIT: I’ll try with the for loop tomorrow - maybe it’ll help some things.

I did not say the statement is false, I tried to explain what it means and why I suggested may not be applicable to your case. Have you tried to search variables?

Either way, now that I think of it, setting the heating chamber temperature is part of a “state change”, meaning it is the same problem I explained. The for loop will not work.

What you can do though is use the parameter that sets the temperature, instead of trying to read it. It’s like reading the parameter that sets the bed temperature. You can similarly use the same wait logic to wait for the set temperature to be reached.

If you mean this, then as I wrote earlier I’ve allready tried that (and a lot of other combinations of that). In fact the exact above was my first version - so it most certainly does not work. The right side of the equal sign is evaluated in whole at the start of the macro and then used when SET_GCODE_OFFSET appears in the gcode.

What I mean in the latest message is that you need to use this variable ‘TEMP_CHAMBER’

You will have that from the start. Why do you need to read the sensor output, if you already know what temperature it is going to reach?

After that I’m doing a lot of other things, so at the moment of SET_GCODE_OFFSET the temp will never be TEMP_CHAMBER. That is just the minimum temp (+1) at which I start soing stuff. I’d have to time the stuff that is done after temp wait - and time it all over again after I change the procedure, and so on - that is just not the way to go.

But we are “a bit” away from my main Q.

Let’s get back to it… are the 2 ways proposed by @3dcoded the only 2 ways to get to the updated chamber temp during macro execution? I’ve allready implemented the separate small macro that reads the temp and updates the gcode offset - it works fine, but I’d like to know if there are other ways of doing this?

Got it, had a similar situation which led me to that for loop that didn’t really work for the same reason as yours.

Honestly I think his suggestion is your best bet. The only other way I see of doing this is by writing your own plugin/python module, given the nature of Jinja templates and call that from the macro, which I am not sure would be any better than calling another macro.

One more thing that occurred to me, not sure it will be useful for you or not.

You can call SET_GCODE_VARIABLE and that will persist between macro calls. So, for example, if you want to read the variable during layer change.

Similarly, if you call a macro from PRINT_START that sets the variable, that then can be read by PRINT_START. This way, you replace that line before setting the offset, by this call.

From what I’ve seen that sets the variable, but the new value will be available at next macro execution, not current - so using it in print_start makes no sense.

Do you need the temperature just for observation?

Yeah I haven’t tested that, but I do use this in several macros. Is quite handy. Anyways good luck

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.