Updating Templates with the new default values in 2021.10.x

I keep seeing the same question about the new default argument for the templating. This post will cover all possible ways to define default.

All the methods that were changed:

  • acos
  • as_timestamp
  • asin
  • atan
  • atan2
  • cos
  • float
  • log
  • round
  • sin
  • sqrt
  • strptime
  • tan
  • timestamp_custom
  • timestamp_local
  • timestamp_utc

Each of them have the exact same default functionality but a different number of arguments. There are multiple ways to use these functions, and this is where all the confusion lies.

Understanding arguments on filters and functions.

Letā€™s take for example a fake function called my_fake_function. The documentation spells out the function as:

my_fake_function as a function

my_fake_function(value, mode="a", flag=False)
                 \   /  \     /   \       /
                  \ /    \   /     \     /
                   |      \ /       \   /
   required arugment       |         \ /
                           |          |
    optional keyword argument     optional keyword argument

my_fake_function as a filter

value | my_fake_function(mode="a", flag=False)
\   /                    \     /   \       /
 \ /                      \   /     \     /
  |                        \ /       \   /
required arugment           |         \ /
                            |          |
       optional keyword argument     optional keyword argument

From this documentation line, I know the following information:

  • my_fake_function has 3 arguments: value, mode, and flag.

  • value is a required argument. You can tell because it does not have a value set on it. mode and flag are optional arguments. This means you donā€™t need to provide the argument to my_fake_function in order for it to work.

  • mode is an optional argument because it has a value attached to it already. You can also call out mode by name when passing in the information. This is because it has a default value which makes it a keyword argument. If you donā€™t provide mode, my_fake_function will use 'a' as mode.

  • flag is an optional argument because it has a value attached to it already. You can also call out flag by name when passing in the information. This is because it has a default value which makes it a keyword argument. If you donā€™t provide flag, my_fake_function will use False for flag.

Example 1

In this example we will use value of 4, mode of "a" and flag of True. Because mode is omitted, my_fake_function will use "a" because the documentation said so.

{{ my_fake_function(4, flag=True) }}

This is also valid, instead of naming flag=True, you can simply provide all 3 arguments.

{{ my_fake_function(4, "a", True) }}

You can also name all optional arguments.

{{ my_fake_function(4, mode="a", flag=True) }}

Example 2

In this example will use value of 7, mode of "b" and flag of False. Keep in mind that we can omit flag because itā€™s False, but you can also provide it if you want. This gives us 4 options on how to write this out.

{{ my_fake_function(7, "b") }}
{{ my_fake_function(7, "b", False) }}
{{ my_fake_function(7, mode="b") }}
{{ my_fake_function(7, mode="b", flag=False) }}

Example 3

This will use value of 9, mode of ā€œcā€ and flag of True. Because we are changing all 3 arguments, we have to provide all 3. Leaving us with the only 2 valid ways of writing it.

{{ my_fake_function(7, "c", True) }}
{{ my_fake_function(7, mode="c", flag=True) }}

Notes

  • You cannot use the argument name when specifying a required argument. In this example, that means you cannot use value=4 when specifying the required arugment value.
  • Not all functions are filters. The documentation will tell you what is a filter and what is a function.
  • Not all filters are functions. The documentation will tell you what is a filter and what is a function.

Using them as a function.

2 arguments

breakdown

{{ function(value_for_argument1, value_for_argument2) }}

examples

# returns acos of 1, if fails returns 0
{{ acos(1, 0) }}

# returns as_timestamp of 1, if fails returns 0
{{ as_timestamp(1, 0) }}

# returns asin of 1, if fails returns 0
{{ asin(1, 0) }}

# returns atan of 1, if fails returns 0
{{ atan(1, 0) }}

# returns cos of 1, if fails returns 0
{{ cos(1, 0) }}

# returns 1.0, if fails returns 0
{{ float('1', 0) }}

# returns sin of 1, if fails returns 0
{{ sin(1, 0) }}

# returns sqrt of 1, if fails returns 0
{{ sqrt(1, 0) }}

# returns tan of 1, if fails returns 0
{{ tan(1, 0) }}

3 arguments

breakdown

{{ function(value_for_argument1, value_for_argument2, value_for_argument3) }}

examples

# returns time @ 10 am, if fails returns 0
{{ strptime("10:00", "%H:%M", 0) }}

# returns log of 1 with base 10, if fails returns 0
{{ log(1, 10, 0) }}

# returns atan2 of 1 at 2, if fails returns 0
{{ atan2(1, 2, 0) }}

# returns rounds 1.23 down precision of 0, if fails returns 0
{{ round(1.43, "floor", 0) }}

3 arguments but omitting the 2nd argument

breakdown

{{ function(value_for_argument1, argument3 = value_for_argument3) }}

examples

# returns log of 1 with base e because base (2nd argument) defaults to e, if fails returns 0
{{ log(1, default = 0) }}

# returns rounds 1.43 to even with a precision of 0 
# because function (2nd argument) defaults to round-to-even, if fails returns 0
{{ round(1.43, default = 0) }}

Using them as filters

2 arguments

breakdown

{{ value_for_argument1 | function(value_for_argument2) }}

examples

# returns as_timestamp of 1, if fails returns 0
{{ 1 | as_timestamp(0) }}

# returns 1.0, if fails returns 0
{{ '1' | float(0) }}

# returns fully formatted time string 1 second past 
# midnight January 1st 1970, if fails returns 0
{{ 1 | timestamp_local(0) }}

# returns fully formatted time string 1 second past 
# midnight January 1st 1970, if fails returns 0
{{ 1 | timestamp_utc(0) }}

3 arguments

breakdown

{{ value_for_argument1 | function(value_for_argument2, value_for_argument3) }}

examples

# returns time @ 10 am, if fails returns 0
{{ "10:00" | strptime("%H:%M", 0) }}

# returns rounds 1.23 down precision of 0, if fails returns 0
{{ 1.43 | round("floor", 0) }}

3 arguments but omitting the 2nd argument

breakdown

{{ value_for_argument1 | function(argument3 = value_for_argument3) }}

examples

# returns rounds 1.23 down precision of 0, if fails returns 0
{{ 1.43 | round(default=0) }}

4 arguments

breakdown

{{ value_for_argument1 | function(value_for_argument2, value_for_argument3, value_for_argument4) }}

examples

# returns "00:00:01", which is 1 second past 
# midnight January 1st 1970 in local time, if fails returns 0
{{ 1 | timestamp_custom("%H:%M:%S", True, 0) }}

4 arguments omitting the 3rd argument

breakdown

{{ value_for_argument1 | function(value_for_argument2, value_for_argument3, value_for_argument4) }}

examples

# returns "00:00:01", which is 1 second past 
# midnight January 1st 1970 in local time (local_time defaults to True), if fails returns 0
{{ 1 | timestamp_custom("%H:%M:%S", default = 0) }}

Hopefully, you can see there are many ways to define default for all the functionand filters. Everything covered in this post is valid. Keep in mind that some functions are not filters and some filters are not functions. All of this is covered in the documentation. This post does not mix and match filters. Everything in the filter section is a filter, anything that is missing is not a filter. Same goes for the function section.

51 Likes

Can I substitute the string ā€˜unknownā€™ for 0 in all those defaults so I know when there is an issue?

1 Like

Yes, you can place anything in the default. none should also make the sensor unavailable.

1 Like

Iā€™m having trouble finding an example for a template binary sensor. The error says float returns 0, I understood this to evaluate to true or false. So Iā€™m not sure where or what I am establishing a default value for.

template:
  - binary_sensor:
      - name: "furnace"
        device_class: heat
        state: >
          {{ states('sensor.boiler_amps')|float > 1 }}

Check out the float example in the 2 argument filter section

1 Like

So if I understand correctly, right now it returns off on the template sensor since float returns 0. If I use

{{ states('sensor.boiler_amps')|float("unavailable") > 1 }}

Then the template comes back as unavailable or NaN?

Comes back as unavailable > 1 which will error. Use zero and it will be false

Then I wonā€™t know if there is a problem as I donā€™t watch the other sensor.

Use an availability template to catch unavailable states for binary sensors

I use nodered so the entity is a trigger for both the notification and a counter. It doesnā€™t really matter as I am just realizing this is not returning anything but on or off.

Iā€™m confused to why a template wouldnā€™t automatically return unavailable if any of the parts were in that state.

I just need to use templates for triggers rather than template sensors.

Itā€™s code, it has order of operations, if the float returns unavailable the unavailable is compared against > 1 and will error out. If you donā€™t want to use 0, then youā€™ll have to use an if statement to check what the float returns before executing the > 1 operation

Just so Iā€™m clear this only happens with a filter? These two post confuse me since it seems to be what I want to do.

again, that only changes what the filter returns. The filter is not the entire template. Itā€™s just the filter. In your case, itā€™s what float returns. Everything you do after the filter follows normal jinja code.

Take for example this equation:

(1 + 1) * 2

you add 1 + 1 prior to multiplying by 2.

Code has similar order of operations.

This is your first operation.

states('sensor.boiler_amps')|float("unavailable")

this is your second operation

> 1

So, does 'unavailable' > 1 make sense? No

Yes it does.

What I was getting at is that this does work, just not when comparing against something else. Like if I needed a sensor from a numeric attribute of another sensor, float("unavailable") would work in that scenario.

Please, explain to me how the word ā€˜unavailableā€™ is greater than or less than 1.

FYI, before you reply, you can see that this does not work.

No no Iā€™m terrible at code and Iā€™m sure Iā€™m using the wrong terminology. My thermostat has temp attributes besides the state. If I wanted to pull that to have as a template sensor I could use

{{ state_attr('sensor.my_therm', 'outside_temp') | float("unavailable") }}

Then if the thermostat was unavailable, so would the template sensor.

Well, attributes are a different story. They already have the correct type associated with them and state_attr by default returns None, so you donā€™t even need to convert that. It will simply work with just:

{{ state_attr('sensor.my_therm', 'outside_temp') }}

because None translates to unavailable when the template is resolved

1 Like

Like I said, Iā€™m terrible at coding lol.