Templating changes in 2021.10.0

I just checked and I have ‘float’ used in 895 places in my HA config. some are in custom integrations but most aren’t.

that’s just one function I looked at. then add all the other functions that got their defaults removed and it gets pretty much of a burden pretty quickly.

I still don’t know if every function now needs a default value added or just the ones that are causing warnings/errors?

I’m in a similar situation. I’m only updating the ones I get warnings for. After a couple of days I only had to do three. There may be more in future.

1 Like

Surely stating the obvious, but float in custom integrations are not affected. Those are pure python ones, not template.

PS: I just realized that int is not affected, because that one uses the builtin jinja filter, which doesn’t enforce a default :rofl:

But do you think it is normal that we have to try every time? this is fine, this is not … this in jinja docmentation is fine, but in HA no … If I put default = value it is fine for float but not for example with other filters … Not to mention warnings, you have to find where are they, in lovelace, in a script, in an automation, and which one :0)
In short, it is a big job.

Also, there are so many warnings that the log fails to show them all :0)

Good job everyone :0) :rofl:

If you have so many warnings, you had a pretty big issue in the first place, so that’s rather a pro of implementing the defaults :wink:

1 Like

Yes, sorry, so many errors that are not yet shown in the log or that have not yet been “found” … I meant…
the filters that I knew how to manage the defaults are ok, but now there is still a lot of confusion, as I said before :sweat_smile: :sweat_smile:

can someone help to check if this template is done correctly?

solar_net_usage:
        friendly_name: Solar Self usage
        unit_of_measurement: "%"
        value_template: >-
          {% if (states('sensor.net_usage') | float(0) > 0) %}
             {{ (( states('sensor.net_usage')|float(0) / states('sensor.pv_energy_generation')|float(0)) *100) | round(2) |float(0)}}
           {% else %}
             0
           {% endif %} 

there’s a lot of redundancy in it and it has a possible divide by zero. I’d use this instead:

          {% set usage = states('sensor.net_usage') | float(0) %}
          {% set energy = states('sensor.pv_energy_generation') | float(0) %}
          {% if usage > 0 and energy %}
            {{ (100 * usage / energy) | round(2) }}
          {% else %}
            0
          {% endif %} 

Meanwhile, I’m sitting here waiting for a warning to pop up. I’ve been running the dev 2021.10 for a month. I know I have them in my templates, they just aren’t producing warnings. :man_shrugging:

Nobody comments on

{{ True | is_numeric }} - will render as True
{{ False | is_numeric }} - will render as True

Imo is_numeric(boolean) should be evaluated to false.
I can understand that boolean can be casted to integer but is_numeric function should not assume such conversion. Boolean is not numeric (its representation might be but it’s particular language implementation detail, and might differ between languages, thus some languages doesn’t allow implicit cast between those datatypes while others don’t allow even explicit ones)

That’s because python interprets True as 1 and False as 0. In python land, those are true statements.

1 Like

I understand, but system behaviour should be as much as possible independent from language specific features it is written in.

It’s not Python HA. It’s just HA

Also, just so you know. These are also interpreted as True / False:

True, 1, 1.0, "anything", [ 'filled'], {'populated:0}
False, 0, 0.0, "", [], {}, None

Jinja (what renders the templates) is an extension of python. This is how jinja behaves.

For what it’s worth, changing the method to capture booleans would be pretty simple. I’ll put in a PR to see if it makes it through.

EDIT: But this won’t change if statements. It will only change the is_number test. Which, isn’t a test. So that should probably be added too so that it can be used in selectattr, etc.

1 Like

Just to be clear I am in favour of the principle that defaults should be provided in many cases but, it seems to me that:

Enforcing a coded default e.g. float(0) has the unintended consequence of the template always returning a valid result even if that valid result isn’t the intended one i.e. the number zero is used if the template is passed a non-numeric resulting in perhaps unexpected but not wrong behaviour.

Whereas not demanding a default would mean that if the template is passed a non-numeric it will cause an error which can be debugged. And of course in many cases the fix will be to provide a default. But not always, there might be something underlying wrong with the template.

It seems to me that requiring a default will mask many issues. Surely it is better practise to ensure your template can never receive bad inputs in the first place, or deals with them if it does. Defaults don’t seem to me to always be the solution, sometimes they could be the problem.

I’m more than happy to be shown the error in my thinking…

1 Like

use float(none) then and check for it in the next line var is not none. Also, fyi previously just using float would result in 0 with anything that failed to convert. So adding it is just making the template the same as before.

The added benefit of having a default with float now allows us to make simple template sensors without having things like the energy drop to zero on startup, causing huge spikes in energy consumption. I.e. users can now do this:

 {{ (some math) | float(none) }}

which will result in a sensor that is unavailable. This will not cause a huge spike when using the energy integration, where

 {{ (some math) | float }}

would have caused a huge spike.

6 Likes

Ok, so I didn’t know you could do that :man_facepalming:
Thanks.

And yes I realised I chose a bad example using float as pressed the button to post but the principle still stands.

Yeah, well the change may not be welcome to many people, but it certainly will let you be more explicit with the system.

To me, I can see this change eliminating the need for an availability template on sensors because you can catch things like this now.

I’m also 75% sure that this was added specifically to catch unknown with float on energy sensors. One of the most asked questions about energy is “why does my template sensor add huge energy spikes”. And it all boils down to not being able to differentiate 0 from invalid data.