Time remaining several switches

Is that correct?
I would like to display the time remaining from several switches.

      zone_wir_time_remaining:
        friendly_name: 'Zone wir Time Remaining'
        value_template: >
          {% set update = states('sensor.time') %}
          {% if is_state('switch.zone_5', 'on') %}
          {% elif is_state('switch.zone_6', 'on') %}
          {% elif is_state('switch.zone_7', 'on') %}
          {% elif is_state('switch.zone_8', 'on') %}
          {% elif is_state('switch.zone_9', 'on') %}
            {{ [ (states('input_number.zone_5_run_time')|int - (as_timestamp(now()) - as_timestamp(states.switch.zone_5.last_changed))/60)|round(0) ,0 ] | max }}
            {{ [ (states('input_number.zone_6_run_time')|int - (as_timestamp(now()) - as_timestamp(states.switch.zone_6.last_changed))/60)|round(0) ,0 ] | max }}
            {{ [ (states('input_number.zone_7_run_time')|int - (as_timestamp(now()) - as_timestamp(states.switch.zone_7.last_changed))/60)|round(0) ,0 ] | max }}
            {{ [ (states('input_number.zone_8_run_time')|int - (as_timestamp(now()) - as_timestamp(states.switch.zone_8.last_changed))/60)|round(0) ,0 ] | max }}
            {{ [ (states('input_number.zone_9_run_time')|int - (as_timestamp(now()) - as_timestamp(states.switch.zone_9.last_changed))/60)|round(0) ,0 ] | max }}
          {% else %}
            0
          {% endif %} 
        unit_of_measurement: "min"

Here are two variations you can experiment with:

      zone_wir_time_remaining:
        friendly_name: 'Zone wir Time Remaining'
        value_template: >
          {% set update = states('sensor.time') %}
          {% if is_state('switch.zone_5', 'on') and is_state('switch.zone_6', 'on') and is_state('switch.zone_7', 'on') and
                is_state('switch.zone_8', 'on') and is_state('switch.zone_9', 'on') %}
            {{ [ (states('input_number.zone_5_run_time')|int - (now().timestamp() - states.switch.zone_5.last_changed.timestamp())/60)|round(0), 0 ] | max }},
            {{ [ (states('input_number.zone_6_run_time')|int - (now().timestamp() - states.switch.zone_6.last_changed.timestamp())/60)|round(0), 0 ] | max }},
            {{ [ (states('input_number.zone_7_run_time')|int - (now().timestamp() - states.switch.zone_7.last_changed.timestamp())/60)|round(0), 0 ] | max }},
            {{ [ (states('input_number.zone_8_run_time')|int - (now().timestamp() - states.switch.zone_8.last_changed.timestamp())/60)|round(0), 0 ] | max }},
            {{ [ (states('input_number.zone_9_run_time')|int - (now().timestamp() - states.switch.zone_9.last_changed.timestamp())/60)|round(0), 0 ] | max }}
          {% else %}
            0
          {% endif %} 
        unit_of_measurement: "min"
      zone_wir_time_remaining:
        friendly_name: 'Zone wir Time Remaining'
        value_template: >
          {% set update = states('sensor.time') %}
          {% if is_state('switch.zone_5', 'on') and is_state('switch.zone_6', 'on') and is_state('switch.zone_7', 'on') and
                is_state('switch.zone_8', 'on') and is_state('switch.zone_9', 'on') %}
            {% set ns = namespace(x = []) %}
            {% for i in range(5, 10) %}
              {% set ns.x = ns.x + ( [ (states('input_number.zone_'~i~'_run_time')|int - (now().timestamp() - 'states.switch.zone_'~i~'.last_changed.timestamp()')/60)|round(0), 0 ] | max) %}
            {% endfor %}
            {{ ns.x | join(',') }}
          {% else %}
            0
          {% endif %} 
        unit_of_measurement: "min"

I thank you

what is the difference between the two variants?

Compare their templates. They use different techniques to produce the same result.

the second variant does not work.
I switched the switch.zone_9 on for 3 minutes via input_number.zone_9_run_time.
Didn’t show me anything.
Value 0

I try the first varian.

  zone_wir_time_remaining:
    friendly_name: 'Zone wir Time Remaining'
    value_template: >
      {% set update = states('sensor.time') %}
      {% if is_state('switch.zone_5', 'on') and is_state('switch.zone_6', 'on') and is_state('switch.zone_7', 'on') and
            is_state('switch.zone_8', 'on') and is_state('switch.zone_9', 'on') %}
        {% set ns = namespace(x = []) %}
        {% for i in range(5, 10) %}
          {% set ns.x = ns.x + ( [ (states('input_number.zone_'~i~'_run_time')|int - (now().timestamp() - 'states.switch.zone_'~i~'.last_changed.timestamp()')/60)|round(0), 0 ] | max) %}
        {% endfor %}
        {{ ns.x | join(',') }}
      {% else %}
        0
      {% endif %} 
    unit_of_measurement: "min"

Seems like there’s a language barrier issue here and you actually want to sum all time times together?

Yeah, verbleibende zeit means remaining time.

Here is part of your original code:

          {% if is_state('switch.zone_5', 'on') %}
          {% elif is_state('switch.zone_6', 'on') %}
          {% elif is_state('switch.zone_7', 'on') %}
          {% elif is_state('switch.zone_8', 'on') %}
          {% elif is_state('switch.zone_9', 'on') %}

It only works if zone_9 is on and all others are off. If any of the other zones is on, the template returns nothing (not even 0).

You can prove that for yourself by pasting this simple example into the Template Editor:

{% set z1 = 1 %}
{% set z2 = 1 %}
{% set z3 = 1 %}
{% set z4 = 1 %}
{% set z5 = 1 %}

{% if z1 == 1 %}
{% elif z2 == 1 %}
{% elif z3 == 1 %}
{% elif z4 == 1 %}
{% elif z5 == 1 %}
  Yes
{% else %}
  No
{% endif %} 

Notice that the template reports nothing (neither Yes or No).
Screenshot from 2020-10-08 14-51-06

What I did in my examples was ensure all zones must be on. Perhaps you want it to work when one or more zones are on?

Well hell, then that’s not the way to sum the times …

1 Like

I’m thinking he just wants a summation if they are on. @klogg does the same thing with his irrigation system. The template shouldn’t be all too hard

  zone_wir_time_remaining:
    value_template: >
      {% set update = states('sensor.time') %}
      {% set ns = namespace(values=[]) %}
      {% for i in range(5, 10) if is_state('switch.zone_'~i, 'on') %}
        {% set ns.values = ns.values + [ states('input_number.zone_'~i~'_run_time')|int ] %}
      {% endfor %}
      {{ ns.values | sum if ns.values > 0 else 0 }}
    unit_of_measurement: "min"
1 Like

That ought to do it.

EDIT

Hold on, where’s the part that calculates the elapsed time for each zone?

With the elapsed time calculation for each zone:

  zone_wir_time_remaining:
    value_template: >
      {% set update = states('sensor.time') %}
      {% set ns = namespace(values=[]) %}
      {% for i in range(5, 10) if is_state('switch.zone_'~i, 'on') %}
        {% set t = [ (states('input_number.zone_'~i~'_run_time')|int - 
           (now().timestamp() - 'states.switch.zone_'~i~'.last_changed.timestamp()')/60)
           | round(0), 0 ] | max %}
        {% set ns.values = ns.values + [ t ] %}
      {% endfor %}
      {{ ns.values | sum }}
    unit_of_measurement: "min"

Is this what you want? The sum of remaining time for all zones?

Or do you want to see the remaining time for each zone separately?


EDIT

If you want to see remaining time for each zone separately, this will report them as a comma-delimited string:

  zone_wir_time_remaining:
    value_template: >
      {% set update = states('sensor.time') %}
      {% set ns = namespace(values=[]) %}
      {% for i in range(5, 10) %}
        {% set t = [ (states('input_number.zone_'~i~'_run_time')|int - 
           (now().timestamp() - 'states.switch.zone_'~i~'.last_changed.timestamp()')/60)
           | round(0), 0 ] | max  if is_state('switch.zone_'~i, 'on') else 0 %}
        {% set ns.values = ns.values + [ t ] %}
      {% endfor %}
      {{ ns.values | join(', ') }}
    unit_of_measurement: "min"

For example, if zones 5 and 7 have remaining time and the other zones have none, the result will look something like this:
12, 0, 10, 0, 0

1 Like

yep missed that

Hi
thanks for the great suggestions.
I want the sum of the remaining time for all zones…

Try the first of the two examples in my previous post. It reports the sum of the remaining time for all zones.

somehow that doesn’t work.
This is a part of my current configuration.

time remaining for each zone work for me.
sum of the remaining time for all zones does not work.
Am I doing something wrong?

switch.zone_9 and input_number.zone_9_run_time ist Hecke

      zone_9_time_remaining:
        friendly_name: 'Time Remaining'
        value_template: >
          {% set update = states('sensor.time') %}
          {% if is_state('switch.zone_9', 'on') %}
            {{ [ (states('input_number.zone_9_run_time')|int - (as_timestamp(now()) - as_timestamp(states.switch.zone_9.last_changed))/60)|round(0) ,0 ] | max }}
          {% else %}
            0
          {% endif %} 
        unit_of_measurement: "min"   
              
      
################  SUMME ZEIT  ZONE WIR   ################ 

      gesamtzeit_wir:
        value_template: "{{ states('input_number.zone_5_run_time')|int + states('input_number.zone_6_run_time')|int + states('input_number.zone_7_run_time')|int + states('input_number.zone_8_run_time')|int + states('input_number.zone_9_run_time')|int }}"
        friendly_name: 'gesamtzeit'
        
    
         
      zone_wir_time_remaining:
        value_template: >
          {% set update = states('sensor.time') %}
          {% set ns = namespace(values=[]) %}
          {% for i in range(5, 10) if is_state('switch.zone_'~i, 'on') %}
            {% set t = [ (states('input_number.zone_'~i~'_run_time')|int - 
               (now().timestamp() - 'states.switch.zone_'~i~'.last_changed.timestamp()')/60)
               | round(0), 0 ] | max %}
            {% set ns.values = ns.values + [ t ] %}
          {% endfor %}
          {{ ns.values | sum }}
        unit_of_measurement: "min

paste the template into the template editor and take a screenshot of your screen & results.

I think I know what prevents this from working.

I created appropriate entities to test the template. Here’s the error message:

TypeError: unsupported operand type(s) for -: ‘float’ and ‘str’

It’s complaining about this subtraction:

now().timestamp() - 'states.switch.zone_'~i~'.last_changed.timestamp()'

Upon evaluation, the first term is a float but the second one is a string.

I’m expecting the second term to be evaluated like this:

  • Concatenate the two strings with the variable and then evaluate the resulting expression to get the timestamp (which would be a float).

What’s happening is:

  • Concatenate the two strings with the variable and nothing more. The result is a string.

One would need to force evaluation of the resulting string using something like an eval function but it’s not available:

now().timestamp() - eval('states.switch.zone_'~i~'.last_changed.timestamp()')

I don’t know of a workaround because last_changed is not an attribute so it cannot be referenced using state_attr().

You can see the behavior I’ve described in this screenshot. I’m using input_boolean instead of switch but that’s immaterial.


EDIT

It seems to me that the solution is to iterate a generator containing the switch entities. That would allow for accessing each item’s last_updated without resorting to string concatenation. I’ll give this a go later (after lunch). :sandwich:

seems like PEDMAS needs to add tilda

I got it to work.

Create a group containing the zone switches:

#group:
  sprinkler_zones:
    - switch.zone_5
    - switch.zone_6
    - switch.zone_7
    - switch.zone_8
    - switch.zone_9

Here’s the revised Template Sensor that uses the group.

  zone_wir_time_remaining:
    value_template: >
      {% set update = states('sensor.time') %}
      {% set ns = namespace(values=[]) %}
      {% for i in expand('group.sprinkler_zones') | selectattr('state', 'eq', 'on') | list %}
        {% set t = [ (states('input_number.'~i.object_id~'_run_time')|int - 
           (now().timestamp() - i.last_changed.timestamp())/60) | round(0), 0 ] | max %}
        {% set ns.values = ns.values + [ t ] %}
      {% endfor %}
      {{ ns.values | sum }}
    unit_of_measurement: "min"

Screenshot showing the sum of the remaining time. Currently, two of the five zones are on and have been running for a few minutes.

UPDATE: Still correctly showing the decreasing time remaining:

Screenshot from 2020-10-09 12-38-59