Template evaluates as string

I have this template, which works when checked in dev tools and evaluates as number.

{{ states('input_number.koi_pond_capacity') | int * states('input_number.water_change_percentage') | int / 100 | int }}

However, when saving the file in vscode editor, it gets changed from this:

- platform: template
  sensors:
    water_change_amount_each_week:
      friendly_name: "Water change amount each week"
      value_template: {{ states('input_number.koi_pond_capacity') | int * states('input_number.water_change_percentage') | int / 100 | int }}

to this:

- platform: template
  sensors:
    water_change_amount_each_week:
      friendly_name: "Water change amount each week"
      value_template:
        {
          {
            states('input_number.koi_pond_capacity') | int * states('input_number.water_change_percentage') | int / 100 | int,
          },
        }

And this doesn’t pass config check, unless I wrap the template in quotes, like this:

"{{ states('input_number.koi_pond_capacity') | int * states('input_number.water_change_percentage') | int / 100 | int }}"

This causes the template to evaluate as string in dev tools.

Please can someone explain where I’m going wrong?

  1. You must surround single-line templates with double quotes (") or single quotes (').

Thank you.

I changed it to:

- platform: template
  sensors:
    water_change_amount_each_week:
      friendly_name: "Water change amount each week"
      value_template: >-
        {{ states('input_number.koi_pond_capacity') | int * states('input_number.water_change_percentage') | int / 100 | int }}
   

Everything’s good now.

I appreciate the help.

No problem, walked into that one in the beginning too.

However, it doesn’t matter if you use the single line template version with quotes or the multi-line template version with “>” the state of the sensor that is created from the template will always be a string and never be a number. (All states are always strings)

so in the end the two versions will return identical results.

Thanks for taking the time to reply. If I have this correct then, the template always return a string.

What is the reason that the dev tools report a number if the template is not in quotes?

Not necessarily. It depends on how it’s ultimately used.

the dev tools template editor will try to show you the correct return type based on all the data provided to it. But even that gets it wrong sometimes because it tries to *guess" what it is.

However, even if the template returns a number per the dev tools editor if you ultimately use that template to get the state of an entity it will always be a string.

and that’s what you are doing in the sensor above - you are using the template to set the state of the sensor. So it will always be a string.

But if you use the same template to set the value of an attribute of the sensor then it will be whatever the template editor says it should be - in your case it will be a number. Because the syatem converts all states to strings but it doesn’t do that same conversiuon on the attributes and instead uses it’s true datatype.

you can actually see this in action even in the template you are using above.

{{ states('input_number.koi_pond_capacity') | int * states('input_number.water_change_percentage') | int / 100 | int }}

the reason why you have to use the “int” filter on both of those input_number states to be able to do math with them is because states are always strings even if they look like a number.

I think you can test it using the same template you are already using for your sensor above.

try this to create the same sensor with a new “number” attribute (the name of the attribute doesn’t matter - you can call it “xyz” if you want):

- platform: template
  sensors:
    water_change_amount_each_week:
      friendly_name: "Water change amount each week"
      value_template: >-
        {{ states('input_number.koi_pond_capacity') | int * states('input_number.water_change_percentage') | int / 100 | int }}
      attribute_templates: 
        number: "{{ states('input_number.koi_pond_capacity') | int * states('input_number.water_change_percentage') | int / 100 | int }}"

then in the template editor try to use the following to test the functionality:

{{ states('sensor.water_change_amount_each_week') / 2 }}

{{ state_attr('sensor.water_change_amount_each_week', 'number') / 2 }}

the first one will fail because you are trying to do math on the state which is a string but the second will work because the attribute is a number. Even tho the template used to create both is exactly the same.

interestingly tho the dev tool editor will still try to claim that both of those results are numbers even tho one is a string and the other isn’t because the editor just looks at what the value looks like it is not what the true data type of the value is.

I hope that is helpful.

Wow! What an answer.

Helpful doesn’t begin to cover it.

Thank you.

1 Like
platform: template
  sensors:
    water_change_amount_each_week:
      friendly_name: "Water change amount each week"
      value_template: >-
        {{ states('input_number.koi_pond_capacity') | int * states('input_number.water_change_percentage') | int / 100 | int }}

The final int isn’t doing anything… Filters are evaluted before mathematical operations so it’s only being applied to the 100, which is already an integer.

Also, you should set defaults for your int's and/or set an availability for the sensor so you don’t get errors if either of your source sensors are unavailable or unknown.

1 Like

Not really necessary in this case since they are input_numbers and will never be unknown and the only way they could be unavailable is if the input_numbers used in the template are deleted.

But it won’t hurt anything either way.

Because it's only applied to the 100 before that. Put everything before that in brackets.
{{ (states('input_number.koi_pond_capacity') | int * states('input_number.water_change_percentage') | int / 100) | int }}

EDIT: I got confused by who I was replying to. Drew had it right there first time.

You could use in stead of the name property unique_id property… and then add a state_class attribute to it.
HA will interpret this new (template) sensor as a value, and show line plots, unlike in your case were there will be state-history based on text.

Here is my example in the configuration.yaml.

template:
  - sensor:
      - unique_id: indoor_vs_outdoor_temperature
        attributes:
          state_class: measurement
          friendly_name: Binnen vs buiten temperatuur
          unit_of_measurement: °C
          device_class: temperature
        state: >
          {% set binnen = states.sensor.indoor_temperature.state|float %}
          {% set buiten = states.sensor.outdoor_temperature.state|float %}
          {{ (binnen - buiten)|round(2) }}

FYI: Sensor Entity | Home Assistant Developer Docs

1 Like