Hi! This is episode five of YAML and Jinja templating course in Home Assistant. This time we are going to dive into Math and how you can calculate in Jinja. Next to that, I will explain how you can work with Date and Time. Let’s do this!
โญโญโญ 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
So, we have already arrived at episode 5 of the YAML & Jinja Templating Course. Today I’m going to tell you a bit about calculations, and dates, and times in Jinja2. When you start creating your custom sensors, you often use calculations. For example, I have a calculation that determines the actual net power by subtracting the power production from the power consumption. But, there are many other types of calculations to think of. I assume that you have also watched episodes 1 through 4 before starting this episode. If not, go to this playlist and watch the previous episodes first.
Oh, and you can download the code I use in the episodes of this course for a small sponsorship fee through the link in the description. That saves you a lot of time retyping the code from the screen, and in doing so, you support me and make it possible for me to continue making these videos for you. You get lifetime upgrades with it, so with each new episode, you can download the extra code for free.
Now let’s take a quick look at which math operators you can all use.
Adding values
We start with the plus sign. This allows you to add two numbers together. See this example:
{{ 1 + 1 }}
Here two integers are added together, but of course, you can also do that with a float as you see in this example:
{{ 1.15 + 2.13 }}
Subtracting values
In addition to adding, you can of course subtract numbers from each other by using the minus sign. See this example:
{{ 5 - 1 }}
{{ 5.25 - 2.13 }}
Here you see that I subtract two integers from each other and I subtract two floats from each other. But, of course, you can also subtract a float from an integer or an integer from a float as you see here:
{{ 5 - 1.25 }}
Dividing values
If you want to divide numbers by each other, use the forward slash as in this example:
{{ 7 / 2 }}
And, of course, you can do that again with floats:
{{ 7.5 / 4.3 }}
If you use two forward slashes, the number is divided but the truncated result is shown:
{{ 7 // 2 }}
Seven divided by two is three and a half, but the truncated part of this is 3. I’ve never used this myself before, but maybe you know of an application for this. Let me know in the comments!
Another option is that you want to calculate the remainder of a division. You can do that with the percent sign:
{{ 7 % 2 }}
What you see here is that the outcome is 1. Two goes three times in seven. The total is 6. And that leaves 1. But maybe this example is easier to understand:
{{ 10 % 7 }}
7 Fits 1 time into 10. What remains is 3 and so that is the result. A remainder calculation can be useful, for example, to see how many small packages fit into a large package.
Multiplying values
If you want to multiply numbers by each other, use the asterisk as in this example:
{{ 5 * 2 }}
You can see that five times two gives the result 10. That works with floats, of course, but it even works with strings. Huh? Why with strings, you might think. Well, you can repeat a string several times. See this example:
{{ "=" * 10 }}
Here you can see that the equal sign is repeated 10 times.
You can also calculate numbers to a certain power. In this example, I calculate what 2 to raised to the power of 3 is:
{{ 2 ** 3 }}
In this case, the outcome is 8, because 2 raised to the power of 3 is 2 times 2 times 2, which equals 8.
You can combine calculations with comparisons and logic which I discussed in episode 3, only there I did not discuss NOT. You can use “not” to check that a statement is not true. For example, as follows:
{% set x = true %}
{% if not(x) %}
x is false
{% else %}
x is true
{% endif %}
This is a bit of a crazy example, but I’m trying to show you that you can use “NOT” to reverse a statement. In some cases, it can be useful to test if a statement is not true so you can start taking action on it.
Examples in Home Assistant
Let’s look at a calculation example in Home Assistant. To do this, you first need to know how to retrieve the value of a sensor in Home Assistant. I’ve used this before, but I’ll explain it again now.
A sensor in Home Assistant always has a status. You can retrieve this status as follows:
{{ states('sensor.yoursensor') }}
Now of course I don’t know what sensors you all have in your house, so I’ll show you an example of a few sensors in my house. You can then replace those with your sensors.
I mentioned at the beginning of this video that I determine actual net power by subtracting power production from power consumption.
So I have one sensor in my system that reflects the power production of my solar panels and one sensor that reflects the power consumption of my entire house. I get those readings from my smart meter.
So you can see that I can pick up power consumption and power production from the following sensors:
{{ states('sensor.smartmeter_power_consumption') | int(0) }}
{{ states('sensor.smartmeter_power_production') | int(0) }}
The power consumption is currently 0 Watts and the power production is currently 150 Watts. The power consumption is 0 Watts because more power is being generated than I am currently consuming.
Now if I want to retrieve the net value, I can subtract both numbers from each other using this formula:
{{ states('sensor.smartmeter_power_consumption') | int(0) - states('sensor.smartmeter_power_production') | int(0) }}
And in this way, you can do many more calculations.
Date & Time
In addition to calculations, you will probably start using date and time values to determine, for example, how many days are between two dates.
NOW
To retrieve the current date and time, you can use the now() function:
{{ now() }}
You can see that the current date and time is now displayed, but it is not really readable. If you want to view the date only, you can use the function strftime. See these examples:
{{ now().strftime('%Y-%m-%d') }}
{{ now().strftime('%d/%m/%Y') }}
{{ now().strftime('%D') }}
{{ now().strftime('%d-%m-%y') }}
Here you see that with percent uppercase Y I can display the year. With percent lowercase m I can represent the month and with percent lowercase d I can represent the day. Thus, I can determine the order and the separators. If I only use percent uppercase D, then the full date is displayed according to my server’s settings, but that’s not always what I want. And if I use percent lowercase y, then the short notation of the year is shown.
You can also retrieve the individual day, month, year, etecetra so you can use them later in a calculation. You do this as follows:
{{ now().day }}
{{ now().month }}
{{ now().year }}
{{ now().hour }}
{{ now().minute }}
{{ now().second }}
{{ now().microsecond }}
{{ now().weekday() }}
{{ now().isoweekday() }}
Here you can see that I have requested the day, month, and year. In addition, I can also query the hour, minute, second, and even microsecond as you see here. And I can also query the weekday and isoweekday.
And you can also retrieve the time, month and weekday in this way:
{{ now().strftime('%d/%m/%Y - %H:%M:%S') }}
{{ now().strftime('%h') }}
{{ now().strftime('%a') }}
{{ now().strftime('%A') }}
With the capital letters H, M, and S, I can retrieve the hours, minutes, and seconds.
With the lowercase “h” I can retrieve the month as text. With the lowercase “a” I can retrieve the short notation of the weekday and with the uppercase “A” I can retrieve the long notation of the weekday.
Pay attention: Using now() will cause templates to be refreshed at the start of every new minute.
UTCNOW
In addition to NOW, I can also use UTCNOW. Sometimes it is convenient to calculate everything in UTC and later convert that time to the user’s time zone.
As you can see here, the UTC time is different from the local time with me:
{{ now().hour }}
{{ utcnow().hour }}
Calculating with Date and Time
If you want to calculate with date and time, there are several ways to do that.
TODAY_AT
For starters, you can compare times by using the today_at function.
{{ now().strftime('%d/%m/%Y - %H:%M:%S') }}
{{ now() > today_at("10:15") }}
You can see here that the value True is returned. And that’s right because it’s now later than 10:15.
Time_SINCE
You can also see how much time has elapsed since some other time. For example, this could be a time stored somewhere in a sensor. For this, you use the time_since function. See this example:
{{ time_since(strptime("15/5/2024 - 10:15","%d/%m/%Y - %H:%M"),1) }}
{{ time_since(strptime("15/5/2024 - 10:15","%d/%m/%Y - %H:%M"),2) }}
{{ time_since(strptime("15/5/2024 - 10:15","%d/%m/%Y - %H:%M"),3) }}
{{ time_since(strptime("15/5/2022","%d/%m/%Y"),3) }}
{{ time_since(as_datetime(states('sensor.last_boot')), 2) }}
Within time_since you first specify the date in the past. In the first three examples, I used the strptime function for this. This function converts a string to date format. Then you specify a precision. In the first example, it is 1, so only hours are returned. In the second example, it is 2, which also returns minutes, and in the third example, it is 3, which also returns seconds.
In the fourth example, I set the date back 2 years, so you can see that with a precision of 2 the years and days are shown.
In the fifth example, I requested the value of a sensor that returns when I last rebooted Home Assistant. I convert that value to the datetime type and I want to see how many days and minutes it has been since this happened. For that, I use precision 2.
time_until
Just as you can retrieve the time elapsed, you can also retrieve the time to a certain point in time. You do that with the time_until function. See these examples:
{{ time_until(strptime("16/5/2024 - 10:15","%d/%m/%Y - %H:%M"),1) }}
{% set newyearsday = (now().year + 1) ~ "-01-01" -%}
{{ time_until(as_datetime(newyearsday),5) }}
{{ time_until(as_datetime(strptime(states('sensor.afvalwijzer_restafval'),"%d-%m-%Y")), 1) }}
In the first example, I query how many hours it is until the entered time. In the second example, I query how long it is until New Year’s Day. And in the last example, I query how many days it will take until the garbage will be picked up.
timedelta
The timedelta function allows you to retrieve the time it is when you subtract, for example, some minutes from, or add to the current time. See these examples:
{{ now() }}
{{ now() - timedelta( days = 2, hours = 1, minutes = 10 ) }}
{{ now() + timedelta( hours = 5, minutes = 22 ) }}
I first query what the time is right now. Then I queried what the time was 2 days, 1 hour, and 10 minutes ago.
And in the second example, I ask what the time will be in 5 hours and 22 minutes.
as_timedelta
There is also another function as_timedelta that can translate a string to a delta object. Now imagine you have a sensor that returns a delay in a string containing hours, minutes, and seconds. Using the function as_timedelta, you can then convert this delay to a delta object and simply add it to the current time. Take a look at this example:
{% set delay = "2:10:25" %}
The time is: {{ now().strftime('%H:%M:%S') }}
The delay will end at {{ (now() + as_timedelta(delay)).strftime('%H:%M:%S') }}
Here you see that I convert a string to a timedelta object and then add it to the current time. it’s just a simple example, but I think you now understand what you can do with it.
timestamps
With the help of these functions, you can do all calculations with time, but you can also use timestamps. A timestamp is the number of seconds since January 1, 1970 midnight UTC. You can use timestamps to subtract or add dates and times because you are simply working with seconds. But timestamps also have quite a big disadvantage within Home Assistant. If you use the as_timestamp function, you lose the timezone unless you know what you are doing. That’s why it’s better to use the as_datetime function. Then you can be sure that the time is always correct. And if you don’t know the timezone, you can always convert a time to your timezone by using the as_local function.
Consider the following examples:
{{ now().time() }}
{{ utcnow().time() }}
Current timestamp:
{{ as_timestamp(now()) }}
{{ as_timestamp(utcnow()) }}
Use local timezone:
{{ as_timestamp(now()) | timestamp_custom('%H:%M:%S') }}
{{ as_timestamp(utcnow()) | timestamp_custom('%H:%M:%S') }}
Use UTC:
{{ as_timestamp(utcnow()) | timestamp_custom('%H:%M:%S', false) }}
As you can see, there is a two hours difference between now() and utcnow(). Now() takes into account the timezone and utcnow() does not. But, if I query the timestamp of now() and utcnow(), you can see that both return the same timestamp. So, here in both cases, the local timezone is not taken into account. Well, there is a slight difference between them in milliseconds, but that’s because calling the function takes a few milliseconds.
If I then use the timestamp_custom function on the now() or utcnow() function, you can see that in both cases I get to see the local time again.
If I then add the parameter “false” to the timestamp_custom function, you will see that I get to see the utc time.
As you can see, this is quite complex and you are very likely to make wrong calculations if you start working with timestamps. So it’s better to use the datetime functions I showed you above. Then it just always works correctly.
So much for episode 5 of the Yaml and Jinja course. I hope by now you have a better understanding of how to work with calculations, and dates and times. Thanks for watching. If you find my videos valuable and they save you time, I would like to ask you to become my sponsor, just like these people are. Thanks to you guys, I can keep this channel going. Otherwise, I would have had to stop a long time ago. Thank you so much. You can find the links to sponsor me in the description of the video. And don’t forget to give this video a thumbs up and subscribe to my channel. See you soon in my next video!
Bye Bye.