Hi!
Here is part 4 of the YAML and Jinja templating course in Home Assistant. Today we are going to talk about Scoping Behavior and Literals. Let’s dive in!
โญโญโญ NOTE: โญโญโญ
This article accompanies a YouTube video. I wrote it for people who would rather read than watch a video. To keep doing this, I want to ask you to check out the video, leave a comment under the video, give the video a thumbs up, and subscribe to my YouTube channel. This means that the video is offered more often to new visitors so that they also stay informed of the latest Home Assistant tutorials.
Thank you for your support!
Ed
This episode assumes you have watched the previous episodes first. If you haven’t seen the previous episodes, go to this playlist to watch them first.
In the previous episode, we talked about If-Then Statements and For-loops. In it, I showed how you can use a for-loop to loop through lists or run a particular function multiple times.
Scoping Behavior
Perhaps you have already worked with for-loops and encountered the following problem. If you define a variable within a for-loop, then you cannot simply call the value of that variable outside the for-loop. A variable is always defined within a scope and cannot be used outside it.
I’ll show you in the following example:
- Go to the Developer Tools and click on the Template tab.
- Check out this code:
{% set total = 0 %}
{% for i in range(8) %}
{% set total = total + i %}
{% endfor %}
The total is: {{ total }}
I first defined a variable “total” here. Then I iterate through a range from 0 to 7. At each iteration, I add the value of i to the variable total. So you would expect the final value of “total” to equal 28. But, if I now query the value of “total” outside the for-loop, you will see that the value is 0.
So this is because the variable “total” within the for-loop does not retain its value. When I just started programming in Jinja, this took me hours to figure out what was happening. But, it happens quite often that you want to perform a calculation on values in a list, and then you want to use the result of that calculation outside the loop again to process further. You can solve this by using namespace objects. Using namespace objects, you can use values across multiple scopes.
You define a namespace as follows:
set ns = namespace(<variabele>=<startvalue>)
I will show how to apply a namespace in the following example:
{% set ns = namespace(total = 0) %}
{% for i in range(8) %}
{% set ns.total = ns.total + i %}
{% endfor %}
The total is: {{ ns.total }}
As you can see, I first defined a namespace object containing the variable total. Within the for loop I add the value of i to the variable total that exists within the namespace object. I can call that variable by first naming the namespace object and then adding the variable separated by a dot. So: ns.total in this case.
You can now see that when I query the variable total outside the for-loop, it has the value 28.
Literals
If you want to start using values in Jinja and YAML, you can use different types. These are called literals. There are several literals you can use.
Strings
The simplest is a string. This is a value enclosed between single or double quotes. See this example:
My text is: {{ "Subscribe to my channel" }}
And my text can also be: {{ 'Thank you for subscribing' }}
You can see that in the first line I put the string between double quotes. In the second line, I put the text between single quotes. In both cases, the text is printed neatly.
Integers
If you want to work with numbers, you can choose to use Integers or Floats. Integers are whole numbers without a decimal part. For example, an integer looks like this:
{% set my_integer = 10 %}
This is an integer: {{ my_integer }}
You can see that the number 10 is now printed.
Floats
So far it’s all fairly simple. Decimal numbers are not called integers, they are called floats. In many cases, you will work with floats in calculations. The simplest float is written down as follows:
{% set my_float = 10.99 %}
This is a float: {{ my_float }}
Note that a float is a decimal number. A float can also be written in scientific notation with an upper or lower case ‘e’ to indicate the exponent part, as you can see here:
{% set my_float = 0.1099e2 -%}
This is also a float: {{ my_float }}
In some cases, you may want to round a float. You can do that using filters. If you want to know how filters work, watch episode 1 of this course first. The link is in the description of the video.
If I want to round a float then I can use the filter “round”. See this example:
This is a rounded float: {{ my_float | round }}
Here, the value 10.99 is converted to 11. But, you can also round to a predetermined number of decimal places. For example, if I want to round to 2 decimal places, I can do it as follows:
{% set my_float = 10.1256 %}
This is a rounded float with two decimals: {{ my_float | round(2) }}
Here you can see that the result is 10.13. The float is rounded to two decimal places because I put a 2 in parentheses after the “round” filter.
What else you can do is convert a string to a float. See this example:
{% set my_string = "12.95" -%}
This is a string converted to a float: {{ my_string | float(0) }}
You can see that the string value 12.95 is now converted to a float. This is important to know because sensor values in Home Assistant are always returned as a string. So if you want to start calculating with those values, you always have to convert them to a float. I explain this later in the episode where I explain calculations.
Lists
In the previous episode, I showed an example of a List. A List stores a list of values that you can then walk through. Some sensors in Home Assistant sometimes have a list of values in an attribute of that sensor. For example, in this Nordpool sensor you can see a list of prices for today and tomorrow. In this video, I created a template where I convert that list to a graph that shows the dynamic energy prices for today and tomorrow. You can find the link to that video in the description of this video.
A list is noted as follows:
{% set my_list = ['Ed', 'Smart Home Junkie', 'Joe', 'Jane'] -%}
This is the first value in my list: {{ my_list[0] }}
This is the second value in my list: {{ my_list[1] }}
You can see that this list consists of 4 names. You can retrieve the items in the list by calling the list, specifying the index number of the list. As you can see, a list always starts with 0, so in this case the values are under index number 0 to 3. So, at index value 0, Ed is returned and at index value 1, Smart Home Junkie, and so on.
You can also expand a list with new values. If I want to add Frenck to the list, I do it as follows:
{% set my_list = ['Ed', 'Smart Home Junkie', 'Joe', 'Jane'] -%}
This is the first value in my list: {{ my_list[0] }}
This is the second value in my list: {{ my_list[1] }}
{% set my_list = my_list + ['Frenck'] -%}
This is the new list: {{ my_list }}
You can see that I have added a new list containing the name “Frenck” to the list now. And so I can also add multiple items to the list at once:
{% set my_list = my_list + ['Madelena','Missy'] -%}
This is the new list: {{ my_list }}
Now Madelena and Missy have been added to the list at once.
You can also replace a value in the list. You do that as follows:
{% set modified_list = my_list[:2] + ['Paulus'] + my_list[3:] -%}
This is the modified list: {{ modified_list }}
I defined a new list and replaced the third index with “Paul”. Then I added the rest of the list starting from the fourth index.
And then there is also the option to remove an item from a list. You do that as follows:
{% set filtered_list = modified_list | reject('equalto', 'Jane') | list %}
This is the filtered list: {{ filtered_list }}
You can now see that I created another new list where I filtered out the name Jane from the previous list. You do that with the filter “reject” and in doing so you specify which value you want to exclude. In this case, it is the value “Jane”. Instead of “equalto” you can also use a double equal sign.
Tuples
In addition to lists, you can also use tuples. Tuples are basically the same as lists, only you cannot change the values within a tuple. I have never used them, but you can define them as follows:
{% set my_tuple = (('Ed', 'Smart Home Junkie', 'Joe', 'Jane')) %}
This is the third value in my tuple: {{ my_tuple[2] }}
This is the fourth value in my tuple: {{ my_tuple[3] }}
As you can see, you define a tuple almost the same way as a list. Instead of block brackets, however, you use ordinary parentheses around the list.
Dicts
In addition to Lists and Tuples, you can also use Dicts. A dict is a structure that combines keys and values. Keys must be unique and always have exactly one value. This is especially useful if you want to read structured data such as XML.
A dict is defined as follows:
{% set my_dict = dict(name="Smart Home Junkie", url="www.smarthomejunkie.net") %}
My dict name is: {{ my_dict.name }}
My dict url is: {{ my_dict.url }}
As you see, you always define a key and a value. If you want to retrieve the value later, first call the dict followed by the key separated by a dot. So if I call my_dict.name, I get back the value Smart Home Junkie in this case.
BooleanS
And then finally we have the boolean. A boolean can have the value true or false and is defined as follows:
{% set my_boolean = true %}
My Boolean is: {{ my_boolean }}
Here I have given the variable my_boolean the value true, and you can see that I also get that value back when I query it. Booleans are used a lot in If-Then statements.
So, now you know what the literals are that you can use in calculations. In the next episode, I’ll go into that in more detail.
The code I use in this course can be downloaded for a small fee from the link in the description. That saves you time because you don’t have to type the code from the screen. In addition, you get lifetime upgrades, so with each new episode, you can download the newly added code for free.
Thanks for watching. I especially want to thank these wonderful people for sponsoring me monthly with a small amount. Without your help, I cannot continue to do this work because the income from YouTube alone is too little to live on. If you find my tutorials valuable, please help me too and become my sponsor. For a small amount per month, you will make sure I can keep sharing my knowledge with you. The links to Patreon, Ko-Fi, and how to join my channel can be found in the description of this video.
And, don’t forget to give this video a thumbs up and join my channel if you haven’t already. It also helps to post a comment below this video. That way, YouTube will show this video to more people.
See you soon in my next video!
Bye Bye!