# Macro Creation Tutorial

**URL:** <https://klipper.discourse.group/t/macro-creation-tutorial/30>\
**Category:** Macros\
**Created:** [March 22, 2021, 3:00pm UTC](https://klipper.discourse.group/t/macro-creation-tutorial/30 "2021-03-22T15:00:59Z")\
**Posts on this page:** 1\
**Showing post:** 6

<div class="post-metadata">

**Author:** ![mental](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/mental/32/11_2.png) [@mental](https://klipper.discourse.group/u/mental)\
**Post date:** [April 16, 2021, 4:59pm UTC](https://klipper.discourse.group/t/macro-creation-tutorial/30/6 "2021-04-16T16:59:52Z")

</div>

**Part 5: Data Types, Assignments, Casting, and Scope**

**Data Types**

Previously we have discussed variables and objects and “types” have been  
mentioned. In the world of programming, everything that has a value has  
a type. The type refers to how that value is stored in memory and how it  
is used within the program. Individual characters and words are called  
`strings`. By default, any parameters being passed into a macro are created  
as strings. Many values accessed within a macro are also `string` types.

When using a `string` in a comparison or assignment, the value _must_ be  
encapsulated in quotes. Single or double quotes are allowable to be used  
as long as the beginning quote matches the end quote. So

```auto
	{% if printer.homed_axes != 'XYZ' %}

```

and

```auto
	{% if printer.homed_axes != "XYZ" %}

```

are both valid, but

```auto
	{% if printer.homed_axes != "XYZ' %}

```

is not. String comparisons are _always_ case-sensitive, meaning

```auto
	'My Value' is not equal to 'my value'

```

In addition to `string`, there are also `float`, and `int` types (plus many  
more, but that is another topic).

A `float` is any numerical value that is not a whole number (has a decimal point).  
It is called `float` as shorthand for “floating point”. Floating point means  
that the number of digits before and after the decimal point varies.  
This is really important for the program but not so much for us. All we  
should concern ourselves with is that it is not a whole number.

If we need only need whole numbers we can use an `int` data type.

**Assignments**

Sometimes it may be necessary to create a variable inside of our macro  
that is not being supplied by a parameter, or if a parameter is supplied  
and we want to access it as particular type for the scope of our macro.

To create a new variable, we use the Jinja2 `set` expression. So if we  
wanted to create a variable called “toolTemp” and have it be the value of  
the parameter ‘TOOL\_TEMP’ we would do

```auto
	{% set toolTemp = params.TOOL_TEMP %}

```

This would create a a variable called `toolTemp` and it would be equal  
to the value of the TOOL\_TEMP parameter _at the time_ the `set` operation  
was performed. As previously mentioned, parameters are always a `string`,  
so before we can do any math or comparisions on it, we need to make it  
into something a bit more numeric.

**Casting**

Casting refers to changing one type to another. Going from an `int` to a  
`float` is fine. An `int` value of 42 cast as a `float` would yield  
`42.000..`. Going from a `float` to an `int`, however, “truncates” the  
digits after the decimal point, so `42.9999` would become `42` in many  
cases you will want to round the number up to the nearest whole number  
_before_ casting.

So how do we cast types? Jinja2 has what are called filters. Filters  
are applied by supplying a `|` (pipe) followed by the filter type. So  
to cast our TOOL\_TEMP parameter `string` as an `int`, we would do

```auto
	params.TOOL_TEMP|int

```

in order to round a `float` to the nearest whole number in order to cast  
it as an `int` we need to apply the `round` filter the round filter takes  
a parameter that specifies how many digits after the decimal point to  
round the number to. So to get the variable `a` rounded to the nearest  
whole number and cast it to `int`, the filters would look like this

```auto
	a|round(0)|int

```

Why are types important? Say in our start print macro we want to preheat  
our bed and hotend at the same time but we want to add a sort of wait timer  
at the end so the bed temperature has time to “soak in” to the entire bed.

We want this time to be calculated based on the temperature the bed was  
when the start print macro was called vs the target temperature of the  
print. If we do something like

```auto
	{% set dwell = params.BED_TEMP * 3 %} 

```

If our BED\_TEMP parameter is `10` then `BED_TEMP * 3` would be `101010`  
because the `*` operator when applied to a string value duplicates that  
string value a number of times. So to multiply bed temp by 3, we have to  
first cast it as an `int`.

```auto
	{% set dwell = params.BED_TEMP|int * 3 %} 

```

**Scope**

Any variable we create within a macro only exists within that macro and  
can only be accessed within that macro. This is called scope. There are  
some cases where a variable can only be accessed from within a control  
structure (such a for loop) and those will be discussed later.

**Bringing it together**

So let us apply the delay to our macro. If my starting bed temperature  
is already at the target temperature because we have been preheating things,  
we can say that we only want to “soak it” for 1 minute.

If the bed temperature at the start of the macro execution is less than  
20 degrees below the target, we want to “soak it” for 5 minutes.

```auto
	{% set target = params.BED_TEMP|int %}
	{% set current = printer.heater_bed.temperature %}
	
	{% if current < target - 20 %}
		G4 P{ 5 * 60 * 1000 } #Milliseconds to dwell
	{% else %}
		G4 P{ 1 * 60 * 1000 }
	{% endif %}

```

---

_[View the full topic](https://klipper.discourse.group/t/macro-creation-tutorial/30)._
