Creating a differential temperature sensor with hysteresis

I have two sensors; one in my pool and one in my solar panel. The solar panel has a small pump that is soon to be upgraded.

I currently have an automation based on this sensor that turns on the solar pump when the solar panel is 1°C warmer than the pool and off otherwise.

- platform: template
  sensors:
    temp_diff:
      friendly_name: Temperature Difference
      value_template: "{{((states.sensor.solar_temperature.state | float ) - (states.sensor.pool_temperature.state | float)) > 1}}`

- id: ID12
  alias: 'Pump hot water if hotter than pool'
  initial_state: 'on'
  trigger:
    - platform: state
      entity_id: binary_sensor.temp_diff
      to: 'on'
  action:
   - service: switch.turn_on
     entity_id: switch.solar_pump

- id: ID13
  alias: 'Stop solar pump if colder than pool'
  initial_state: 'on'
  trigger:
    - platform: state
      entity_id: binary_sensor.temp_diff
      to: 'off'
  action:
   - service: switch.turn_off
     entity_id: switch.solar_pump

As I’m going to increase the flow rate from 360l/hr to 5200l/hr, I need to allow a short time (unknown) for the water to heat inside the solar panel so I want the pump to start when the solar panel is say 4 °C above the pool temp (possibly using an input_number slider), then off when the difference drops to say 0.5°C

Anyone know the best way to create that automation?

How’s about changing the binary sensor to a sensor, and doing something like this…

input_number:
  pump_on_offset:
    name: Pump ON offset
    min: 0
    max: 10
    step: 0.5

  pump_off_offset
    name: Pump OFF offset
    min: 0
    max: 10
    step: 0.5

sensor:
  - platform: template
    sensors:
      temp_diff:
        friendly_name: Temperature Difference
        value_template: >
          {% if ((states.sensor.solar_temperature.state | float ) - (states.sensor.pool_temperature.state | float))
            > (states.input_number.pump_on_offset.state | float ) %} pump_on
          {% elif ((states.sensor.solar_temperature.state | float ) - (states.sensor.pool_temperature.state | float))
            < (states.input_number.pump_off_offset.state | float ) %} pump_off
          {% else %} pending {% endif %}

automation:
  - id: ID12
    alias: 'Pump hot water if hotter than pool - stop if not'
    initial_state: 'on'
    trigger:
      platform: state
      entity_id: sensor.temp_diff
    condition:
      condition: template
      value_template: "{{ not is_state ('sensor.temp_diff' , 'pending') }}"
    action:
      entity_id: switch.solar_pump
      service_template: >
        {% if is_state ('sensor.temp_diff' , 'pump_on') %} switch.turn_on
        {% else %} switch.turn_off {% endif %}

PS - the forum says I’ve edited that once, but it was actually about 6 times to get the formatting right (and it still might not be!!) so don’t copy it from the email you got!

@anon43302295 Wow, that was fast and awesome. I’m always in awe of you coding guys that can bang out stuff like that effortlessly. Wish I could do that.

0124 in the morning here in NZ so I’ll give that a try when the sun comes up! Thank you.

No worries :+1:

Just beware that it might need a bit of tweaking to make sure that the pump doesn’t end up on when you don’t want it to be, it’s hard to run through the permutations when you’re not looking at the system and imagining it running.

Also, as it is there, you could potentially set the OFF offset higher than the ON offset and so on, which could lead to it never coming on, or getting stuck on or whatever. So once you’ve got it working the code might need refining slightly to prevent errrors creeping in.

Sweet dreams! :laughing:

Got this working tonight and seems to be behaving exactly as I wanted so thank you. Not withstanding that the cooked pump I had took out my PWM controlled MOSFET so had to rip out my solar controller and replace that too!

1 Like

Seems something is not quite right. With the solar pump off and the on_offset set to 2 and the off_offset set to 0.5, the pump starts when the 2 degrees differential hits and then turns off when it get to just below 0.5 degrees which is great. However, it seems to turn back on when the differential gets above 0.5 even though the temp_diff sensor states ‘pending’.

Here is the as-built automation:

- id: ID12
  alias: 'Pump hot water if hotter than pool - stop if not'
  initial_state: 'on'
  trigger:
      platform: state
      entity_id: sensor.temp_diff
  condition:
      condition: template
      value_template: "{{ not is_state ('sensor.temp_diff' , 'pending') }}"
  action:
      entity_id: switch.solar_pump
      service_template: >
        {% if is_state ('sensor.temp_diff' , 'pump_on') %} switch.turn_on
        {% else %} switch.turn_off {% endif %}

Must be being switched on from somewhere else, that automation won’t fire if the sensor is pending. That’s the reason I introduced the pending state so I could add the condition.

Also, even if it did skip the condition somehow, unless the sensor is ‘pump_on’ then the result will be to switch off the pump.

So, if we’re happy it definitely was ‘pending’ it was switched on by some other means. If it was on pump_on I’ll need to have another look at the template.

Can you check the logbook and see which is the case?

Seems switching on and off OK, just not off when state is pending? There are no other automations pertaining to the solar_pump. Could the broker retain message be doing anything?

Hmm, OK, try this for the sensor…

sensor:
  - platform: template
    sensors:
      temp_diff:
        friendly_name: Temperature Difference
        value_template: >
          {% if ((states.sensor.solar_temperature.state | float ) - (states.sensor.pool_temperature.state | float))
            < (states.input_number.pump_off_offset.state | float ) %} pump_off
          {% elif ((states.sensor.solar_temperature.state | float ) - (states.sensor.pool_temperature.state | float))
            > (states.input_number.pump_on_offset.state | float ) %} pump_on
          {% else %} pending {% endif %}

And this for the automation…

automation:
  - id: ID12
    alias: 'Pump hot water if hotter than pool - stop if not'
    initial_state: 'on'
    trigger:
      platform: state
      entity_id: sensor.temp_diff
    action:
      entity_id: switch.solar_pump
      service_template: >
        {% if is_state ('sensor.temp_diff' , 'pump_on') %} switch.turn_on
        {% else %} switch.turn_off {% endif %}

I’ve just reordered the template to make sure it double checks if it should be off before it checks if it should be on, which will hopefully get rid of any false positives (should’ve done that in the first place, sorry!)

Then I’ve removed the condition to ensure that any state change that isn’t ‘pump_on’ switches it off. The automation will fire a little more frequently, but should ensure that the pump is always off when it should be.

Let me know :+1:

Seems you may have nailed it! Thank you so much.

1 Like

No worries :+1:

@anon43302295 My template sensors have died after 0.66 so my ‘Pool Pump Hours Running’ just shows 0 all the time. You see that too?

Everything is fine here, what’s the code for the hours running one?

Seems this one might be the problem?

- platform: history_stats
  name: Pool Pump running today
  entity_id: sensor.pool_pump_status
  state: 'Running'
  type: time
  start: '{{ now().replace(hour=0).replace(minute=0).replace(second=0) }}'
  end: '{{ now() }}'

Here is all three sensors. Nothing changed with those.

## Pool pump status sensor as switch is hidden:
- platform: template
  sensors:
    pool_pump_status:
      value_template: '{% if is_state("switch.pool_pump", "on") %}Running{% else %}Stopped{% endif %}'
      friendly_name: 'Pool Pump Status'

## Creates a history sensor based on how long the pool pump has been in a
## status of 'running' defined in the aboved value template:
- platform: history_stats
  name: Pool Pump running today
  entity_id: sensor.pool_pump_status
  state: 'Running'
  type: time
  start: '{{ now().replace(hour=0).replace(minute=0).replace(second=0) }}'
  end: '{{ now() }}'

## Look for the attribute named 'value' from the above sensor to create
## a new sensor using that attribute:
- platform: template
  sensors:
    pool_pump_time_on:
      value_template: '{{ states.sensor.pool_pump_running_today.attributes.value }}'
      friendly_name: 'Pool Pump Hours Running'

Ummm, off the top of my head I’m stumped there tbh.

Let me have a head scratch and come back to you :+1:

Thanks, appreciated :+1:

1 Like

@anon43302295 Sorted! History Graph not working after 0.66.x

1 Like