Need help creating a template sensor for my new pool level sensors

I’ve tricked up my pool controller and added 3 x non-contact water level sensors. I’ve added them all as MQTT binary sensors and they now report water detection. However, I need a global template sensor using else/if statements as the following would be true.

Low sensor on, normal sensor and high sensor off = pool level low
Low sensor on, normal sensor on, high sensor off = pool level normal
Low sensor on, normal sensor on, high sensor on = pool level high.

Can anyone assist with a value_template to achieve that? In addition, may need to define an on time (~5s) so that if the high sensor get splashed with water for a second or two, it doesn’t cause a false trigger.

Your template…

{% if is_state('binary_sensor.low','on') and is_state('binary_sensor.normal','off') and is_state('binary_sensor.high','off') %}
  Low
{% elif is_state('binary_sensor.low','on') and is_state('binary_sensor.normal','on') and is_state('binary_sensor.high','off') %}
  Normal
{% elif is_state('binary_sensor.low','on') and is_state('binary_sensor.normal','on') and is_state('binary_sensor.high','on') %}
  High
{% else %}
  Error
{% endif %}

As for your splashy problem, if you’ve set your sensors up using the template binary_sensor integration you can use the delay_on: variable.

2 Likes

Legend, thank you! That’s saved me about 5hrs of frustration I’m sure.

1 Like

Seems there might be a bit of an error somewhere?? When I pop the code into the developer tools, it states that “This template listens for the following state changed events”: Entity: binary_sensor.pool_sensor_low (and no other entities) and the template sensor always reports as error.

UPDATE: Disregard. Typo in sensor name. Update shortly.

When you spell your entities correctly, it works a dream!!! Thank you.

  - platform: template
    sensors:
      aggregate_pool_level:
        friendly_name: "Aggregate Pool Level"
        value_template: >-
          {% if is_state('binary_sensor.pool_level_low','on') and is_state('binary_sensor.pool_level_normal','off') and is_state('binary_sensor.pool_level_high','off') %}
            Low
          {% elif is_state('binary_sensor.pool_level_low','on') and is_state('binary_sensor.pool_level_normal','on') and is_state('binary_sensor.pool_level_high','off') %}
            Normal
          {% elif is_state('binary_sensor.pool_level_low','on') and is_state('binary_sensor.pool_level_normal','on') and is_state('binary_sensor.pool_level_high','on') %}
            High
          {% else %}
            Error
          {% endif %}

Do you know if I can create a template binary sensor using the payload from a MQTT topic so I can utilize the delay_on variable you speak off (without creating another three sensors)?

  - platform: mqtt
    name: "Pool Level High"
    unique_id: pool_level_high    
    state_topic: "tele/wemos_pool/level/high"
    payload_off: "1"    
    #force_update: true  
    payload_on: "0"
    qos: 0
    device_class: moisture 

Hmmmm… I’m honestly not sure.

What is the level sensor connected to ?

A tasmotized Wemos mini pushing MQTT. I’ve found a workaround as Tasmota does spit out JSON with the switch states included and this updates as defined by the ‘teleperiod’ setting. So if I set the teleperiod to 10, the switch state json messages will update every 10 seconds. That should be OK. I’ll just switch the MQTT binary sensors to use the json instead of the payload in the topic.

Are you familiar with ESPhome at all ?

It has its own Home Assistant add-on, is configured with yaml, entities are auto discovered if using the inbuilt API, and more importantly for you, has delayed_on: as a variable for binary_sensors.

I’ve used it once before so it might be time to take another look. Thanks for the tip.

Alternative way:

  - platform: template
    sensors:
      aggregate_pool_level:
        friendly_name: "Aggregate Pool Level"
        value_template: >-
          {% set x = [states.binary_sensor.pool_level_low, states.binary_sensor.pool_level_normal, states.binary_sensor.pool_level_high]
                     | selectattr('state', 'eq', 'on') | map(attribute='object_id') | list %}
          {{ x[0].split('_')[2] | title if x | count == 1 else 'Error' }}

Crikey @123 That’s a whole lot a science right there! Could you possibly explain the expression at the end just in case I need to tweak anything?

Sure.

It’s an inline if statement.

If this is true: x | count == 1
then it will do this: x[0].split('_')[2] | title
otherwise it will report this: 'Error'

This statement x[0].split('_')[2] | title
takes the first item in the list and splits it at every instance of _.
The result is another list.
It takes the third item from that list (which is [2] because the first item is indexed as zero)
and applies the title filter to capitalize the first letter.

In other words, pool_level_normal is split into [ 'pool', 'level', 'normal'] and the third item is selected and its first letter is capitalized to produce: Normal

Another way to produce “Normal” would be:

x[0].replace('pool_level_', '') | title
1 Like