Heating the pool to a target temperature at a target time

Now that my pool is automated, in that I can control everything remotely and set schedules in Node-RED, I’d like to be able to enter a date and time in Lovelace, as well as a target temperature, and then have Node-RED start heating the pool at the appropriate time. Right now, I’m just using historical data to figure out what that time is, ignoring ambient temperature, UV index, etc… but maybe down the road I can figure those in.

For now, I’m just trying to get the syntax for my template entities right. I don’t code, so I’m trying to adapt syntax from other template entities I’ve seen online. Here’s my approach:

input_number.pool_target_temp is the temperature I want to set the pool to, and
input_datetime.pool_target_temp_time is the time I want to hit that temperature.

I’ve also added an input_boolean to “enable” this schedule; that will kick off my Node-RED flow.

Based on a little bit of data, I figure the heater can heat the pool 15 degrees over 6 hours, so to figure out the hours required to get from the current temperature to the target temperature, I need to multiply the temp delta by 0.4.

Here are the template entities I’ve added to configuration.yaml:

      pool_heating_interval:
        value_template: >
          {% set currenttemp = states('sensor.pool_thermostat_water_temperature') | int %}
          {% set newtemp = states('input_number.pool_target_temp') | int %}
          {% set tempdelta = (newtemp - currenttemp) | int %}
          {% set timeinterval = (tempdelta * 0.4) | float %}
          {{ '%2i'%(timeinterval) }}
#      pool_heater_start_time:
#        value_template: >
#          {{ as_timestamp(states('input_datetime.pool_target_temp_time')) - as_timestamp(states('sensor.pool_heating_interval')) }}

pool_heater_start_time is commented out thusfar, because I realize that sensor.pool_heating_interval is just going to give me an hour count; it’s not a timestamp. I need help with the date math. However, pool_heating_interval doesn’t even work, and because I don’t know what I’m doing… I’m not sure why. Can anyone check my work?

EDIT: I got the interval correct! It’s working in HA. The corrected YAML is above. The current temp is 77, the target is 70, and sensor.pool_heating_interval is equal to -2… which is technically correct, but maybe I should figure out how to only set that template entity to positive values…

Now that I can get the hours needed to heat the pool, I just need some help with my date math for pool_heater_start_time.

EDIT 2: OK… this works from a syntax perspective, but my pool_heater_start_time is unavailable:

      pool_heater_start_time:
        value_template: >
          {% set hoursneeded = states('pool_heating_interval') | float %}
          {{ as_timestamp(states('input_datetime.pool_target_temp_time')) - timedelta(hours = hoursneeded) }}

Where am I going wrong?

This doesn’t work; it results in an error checking config:

      pool_heater_start_time:
        value_template: >
          {% set hoursneeded = states('pool_heating_interval') | float %}
          {% targettime = states('input_datetime.pool_target_temp_time') | float %}
          {% set starttime = (targettime - timedelta(hours = hoursneeded)) | float %}
          {{ as_timestamp(starttime) }}

Referencing this thread, I tried this:

      pool_heating_interval_seconds:
        value_template: >
          {% set currenttemp = states('sensor.pool_thermostat_water_temperature') | float %}
          {% set newtemp = states('input_number.pool_target_temp') | float %}
          {% set tempdelta = (newtemp - currenttemp) | float %}
          {% set timeinterval = ({(tempdelta * 0.4) // 3600) | float %}
          {{ '%2i'%(timeinterval) }}
      pool_heater_start_time:
        value_template: >
          {{ ((state_attr('input_datetime.pool_target_temp_time', 'timestamp') - 'sensor.pool_heating_interval_seconds') | timestamp) }}

…to convert my interval to seconds and subtract that from the target time; but that’s also resulting in an error.

This is likely very simple for those versed in this stuff. I was hoping to get at least some sort of response… 40 views, and… nothing?

That’s vague.

Are you debugging your templates in the template debugger?
That will give more insight on what’s wrong, and allow others to help you if it’s not obvious.

I’ve been using only “Check Configuration” - Configuration validation under Server Controls. I’ve never used the template debugger; is that under the Template header on the Developer Tools page? I’ve just dropped the code above in, and I’m getting this:

TemplateSyntaxError: unexpected '}', expected ')'

I’m not seeing anywhere where I’m using } where I should have a ), but again… I’m new to this.

See, it helps :wink:
You cannot expect even “those versed in this stuff” to see this (nor expect them to do the debugging for you :wink: )

Remove that bracket.
“( { (tempdelta * 0.4)”

And iterate until you get your expected result…

Ah, yes, that makes sense. That bracket must have made its way into that sensor sometime after it was working, and is definitely not in my operating configuration.yaml. Unfortunately, that sensor is not the one I’m having issues with, it’s the one below it.

However, knowing about this tool definitely would have saved me a lot of effort, long before I started working on this automation. THANKS!

Still no luck on the pool_heater_start_time syntax, though. I’m trying to work through this thread and this one to see if I can extract anything I can use.

I’m currently here:

      pool_heater_start_time:
        value_template: > 
          {% set swim_time = states.input_datetime.pool_target_temp_time | float %}
          {% set offset = states.sensor.pool_heating_interval * 3600 %}
          {% set start_time = (swim_time - offset) | float %}
          {{ (start_time) }}

…and getting this: TypeError: unsupported operand type(s) for *: 'TemplateState' and 'int', but I really didn’t expect that to work without more tweaking.

EDIT: this:

      pool_heater_start_time:
        value_template: > 
          {% set swim_time = states.input_datetime.pool_target_temp_time | float %}
          {% set offset = states.sensor.pool_heating_interval | float %}
          {% set start_time = (swim_time - (offset * 3600)) | float %}
          {{ (start_time) }}

passes muster in the template debugger, but returns 0.0 and this message:

This template does not listen for any events and will not update automatically.

…which is weird. I’m looking for a timestamp to be returned, and I expected the template to update when input_datetime.pool_target_temp_time changes.

You need to add “.state” to the end of your sensors in the template.

and the “state” of an input_datetime is a string with characters that can’t be converted to a float. So the conversion to a float will result in a 0.0.

try this:

pool_heater_start_time:
  value_template: > 
    {% set swim_time = states.input_datetime.pool_target_temp_time.attributes.timestamp | float %}
    {% set offset = states.sensor.pool_heating_interval.state | float %}
    {% set start_time = (swim_time - (offset * 3600)) | float %}
      {{ (start_time) }}

but I don’t know what the format of your pool_heating_interval sensor is. Is it a string or a number?

if it’s a string that can’t be converted to a float you will get the same 0.0 result as above.

I implemented your code… and I have a result! Not a timestamp, but something, at least. Here it is, with the previous sensor shown, with your code above. It is a float:

      pool_heating_interval:
        value_template: >
          {% set current_temp = states('sensor.pool_thermostat_water_temperature') | float %}
          {% set new_temp = states('input_number.pool_target_temp') | float %}
          {% set temp_delta = (new_temp - current_temp) | float %}
          {% set time_interval = (temp_delta * 0.4) | float %}
          {{ '%2i'%(time_interval) }}
      pool_heater_start_time:
        value_template: > 
          {% set swim_time = states.input_datetime.pool_target_temp_time.attributes.timestamp | float %}
          {% set offset = states.sensor.pool_heating_interval.state | float %}
          {% set start_time = (swim_time - (offset * 3600)) | float %}
          {{ (start_time) }}

pool_heater_start_time resolves to 1621854000.0. I assume I can convert that to a timestamp somehow? I tried this to no avail:

      {{ as_timestamp(start_time) }}

Thank you.

Actually it already is a timestamp.

Well, it’s at least in timestamp format. whether the timestamp makes any sense in the context you want to use it is something else. I haven’t really gone thru all the posts above enough to know what you are going to be doing with the result.

what format do you want the start_time to be in?

you can use timestamp_custom to convert it to a datetime string.

Great. I’m just using it in Node-RED to kick off a flow using a “Time” node (beta)… but it doesn’t like the format: “invalid date.”

I’ll see if I can convert that to yyyy-MM-dd HH:mm:ss.

EDIT: This works, 100% as expected:

      pool_heating_interval:
        value_template: >
          {% set current_temp = states('sensor.pool_thermostat_water_temperature') | float %}
          {% set new_temp = states('input_number.pool_target_temp') | float %}
          {% set temp_delta = (new_temp - current_temp) | float %}
          {% set time_interval = (temp_delta * 0.4) | float %}
          {{ '%2i'%(time_interval) }}
      pool_heater_start_time:
        value_template: > 
          {% set swim_time = states.input_datetime.pool_target_temp_time.attributes.timestamp | float %}
          {% set offset = states.sensor.pool_heating_interval.state | float %}
          {% set start_time = (swim_time - (offset * 3600)) | float %}
          {{ (start_time) | timestamp_custom }}

Thanks @koying for shedding light on the template debugger and @finity for correcting my template. It’s been an educational few hours.

looks like it’s a valid timestamp to me:

EDIT:

Sorry I didn’t see your last edit.

but I’m surprised that works. I didn’t think there was a default timestamp_custom format. I thought you always had to provide a format directive in the function.

That’s something we both learned today. I just dumped it in there (using the new-to-me debugger) to see what it would output.

1 Like