Iām not sure I can explain why, but I thought I ran across something similar at one time. I donāt think the second float is being applied the way most of us would think. I will try to find the case I had. So what I think is happening is that you are getting a float divided by a string (which is zero), it does not matter what is in states(āsensor.days_usedā) . Weird I know.
(states('sensor.days_used')|float)
might fix it.
The wording of the error might oddly be telling:
TemplateError('ZeroDivisionError: float division by zero')
I believe you should be able to test it by forcing the sensor from 1 to 0 in the states tab using āset stateā. It will get updated again to the correct value but it should pop up long enough to test.
Because all states are strings, I think you can run into problems trying to cast them to a float (or int) without some other checks. You can use a default value in the filter to identify something that is not really a number (I used an existing dark sky sensor because its state is a string that canāt be cast to a float):
{% set sensor_state = states('sensor.dark_sky_summary')|float(-999) %}
If I put this in developer/template editor, it returns the value -999 which you can easily check for. Of course, you can check for a zero in this case, too - I just always seem to default to a big negative number to tell me that it canāt be cast to a numberā¦
If I leave the default value out, as in:
{% set sensor_state = states('sensor.dark_sky_summary')|float %}
it will return a 0.0, which you can also check for.
The complete template would then look like (I also used a set statement for the numerator to make sure it isnāt something unexpected - and you need gb_per_day to be something other than 0.0 or else youāll get a division by zero error in the line starting with {% set proj_days_left =...):
value_template: >
{% set days_used = states('sensor.days_used')|float(-999) %}
{% set used_gb = states('sensor.used_gb')|float(-999) %}
{% if sensor_state > 0 and used_gb > 0 %}
{% set gb_per_day = used_gb / days_used %}
{% set remaining_gb = 500 - used_gb %}
{% set proj_days_left = remaining_gb / gb_per_day %}
{% set proj_end_date = ( as_timestamp( states('sensor.date') ) + proj_days_left * 86400 )|timestamp_custom('%-d %b %Y') %}
{{ proj_end_date }}
{% else %}
N/A
{% endif %}
The solution @Steven_Rollason proposed will provide essentially the same thing except that Iād add the check for the used_gb to prevent an error in the proj_days_left calculation (in the event used_gb is actually zero).
@tom_l
Here is the best explanation in the docs I could find. Not a great explainer, but if grok the idea of Operator Precedence, and then understand that the | filter operator comes in last it should be clear to you. Good hunting!
note
The filter operator has a pretty low priority. If you want to add fitered values you have to put them into parentheses. The same applies if you want to access attributes or return values:
correct:
{{ (foo|filter) + (bar|filter) }}
wrong:
{{ foo|filter + bar|filter }}
correct:
{{ (foo|filter).attribute }}
wrong:
{{ foo|filter.attribute }}
Just noticed your own proposed solution, @tom_l, at the end of your original post that adds and states('sensor.days_used')|int != 0 to the if statement. That will work, too. But Iād still add the check for used_gb.
Just use an availability template and refactor a bit to avoid startup errors.
value_template: >
{% set used = states('sensor.used_gb')|float %}
{% set days = states('sensor.days_used')|float %}
{% set remaining = 500 - used %}
{% if 0 not in [ used, days ] %}
{% set days_left = remaining / (used / days) %}
{{ as_timestamp( states('sensor.date') ) + days_left * 86400 ) | timestamp_custom('%-d %b %Y') }}
{% endif %}
availability_template: >
{{ 0 not in [ states('sensor.used_gb')|float, states('sensor.days_used')|float ] }}
The reason you were getting divide by zero errors is not because states('sensor.days_used') was zero. It was because states('sensor.used_gb') was zero on day 1. This caused your second line ({% set proj_days_left = remaining_gb / gb_per_day %}) to divide by zero because your gb_per_day was zero. So your first if statement passed but you didnāt check the second divisor.
Just to expand on the math on day 1:
used will equal 0. days will equal 1. remaining will equal 500.
used_gb will equal to used (0) / days (1) which equals 0.
project_days_letf will be remaining (500) / used_gb (0) <-- This is where your error is happening.
Wow - I just learned something! I didnāt know about the availability_template. Thanks, @petro! Havenāt tried it yet in my own stuff, but certainly will - so that can go in something like a condition section? The only mention I can find in the docs is for a sensor