Help with jinja2 if statement comparing two epoch times

Pulling my hair out over this one. I’m very new to Jinja2 so trying to get my head around things. I have a bunch of motion sensors placed into groups based on the room they are in. I am trying to get a template to figure out which group was most recently changed, but my results are weird probably due to my IF statement not comparing the two epoch times correctly.

Here’s what I’ve written so far:

{% set currentTime = as_timestamp(now()) %}
Current epoch seconds are  {{ currentTime }}
{% set presence = [ states.group.living_presence,
                    states.group.office_presence,
                    states.group.kitchen_presence,
                    states.group.bedroom_presence,
                    states.group.dining_presence] %} 
                    
{% set last_changed = as_timestamp(presence[0].last_changed) %}                    
{% set difference = currentTime - last_changed %}
{% set most_recent = difference %}
Starting with {{presence[0].entity_id}}, it was last changed {{difference}} seconds ago. It is now the most recently changed.
{% for p in presence %}
  {% set last_changed = as_timestamp(p.last_changed) %}
  {% set difference = currentTime - last_changed %}
  When comparing {{p.entity_id}}, which was last changed {{difference}} seconds ago, 
  {% if ( difference < most_recent ) %}
    {% set most_recent = difference %}
    {{p.entity_id}} was more recently changed, therefore {{p.entity_id}} is now the most recent.
  {% else %}
  It was not more recenty changed and so stays the most recently changed.
  {% endif %}
{% endfor %}

The results are:

Current epoch seconds are  1576316187.837726
 
                    
                    


Starting with group.living_presence, it was last changed 9325.64158821106 seconds ago. It is now the most recently changed.

  
  
  When comparing group.living_presence, which was last changed 9325.64158821106 seconds ago, 
  
  It was not more recenty changed and so stays the most recently changed.
  

  
  
  When comparing group.office_presence, which was last changed 414.2968921661377 seconds ago, 
  
    
    group.office_presence was more recently changed, therefore group.office_presence is now the most recent.
  

  
  
  When comparing group.kitchen_presence, which was last changed 289.0434319972992 seconds ago, 
  
    
    group.kitchen_presence was more recently changed, therefore group.kitchen_presence is now the most recent.
  

  
  
  When comparing group.bedroom_presence, which was last changed 3208.34237909317 seconds ago, 
  
    
    group.bedroom_presence was more recently changed, therefore group.bedroom_presence is now the most recent.
  

  
  
  When comparing group.dining_presence, which was last changed 9321.240389108658 seconds ago, 
  
    
    group.dining_presence was more recently changed, therefore group.dining_presence is now the most recent.

Please excuse the very ugly ‘english’ output, which I am using to make the results more human readable.

As you can see the most recently changed group ends up as group.dining_presence, which was changed 9321 seconds ago. The true result should be group.kitchen_presence. For some reason the comparison of {% if ( difference < most_recent ) %} is not evaluating correctly.

Any ideas much appreciated!

See Scoping Behavior under Jinja Assignments

1 Like

Here’s another potential way to achieve your goal. It uses the max filter to find the latest time.

Sorry about its use of the word sensors for the list. I copy-pasted it from an existing example that monitored binary_sensors. Feel free to modify it as you see fit.

  - platform: template
    sensors:
      last_activated:
        friendly_name: 'Last Activated'
        value_template: >
          {% set sensors = [states.group.living_presence,
                            states.group.office_presence,
                            states.group.kitchen_presence,
                            states.group.bedroom_presence,
                            states.group.dining_presence] %}
          {% set time = sensors | map(attribute='last_changed') | max %}
          {% set sensor = (sensors | selectattr('last_changed','eq', time) | list)[0] %}
          {{sensor.name}} {{sensor.state}} {{sensor.last_changed.timestamp() | timestamp_custom('%b-%d %-H:%M')}} 
3 Likes

That’s a good idea. I had thought of using the max filter, but I hadn’t thought about how to use the result of that to find the group that matched it. :slightly_smiling_face:

Anyway, as an example of how to do it with a loop, using a namespace (if for no other reason than future reference):

{% set presence = [ states.group.living_presence,
                    states.group.office_presence,
                    states.group.kitchen_presence,
                    states.group.bedroom_presence,
                    states.group.dining_presence] %} 
{% set ns = namespace(latest=presence[0]) %}
{% for p in presence[1:] %}
  {% if p.last_changed > ns.latest.last_changed %}
    {% set ns.latest = p %}
  {% endif %}
{% endfor %}
{{ ns.latest.entity_id }}
2 Likes

Thanks. I did read it, and was aware about the scoping behaviour following advice I received last week from @Taras. However I was under the impression that the variable were only wiped after a loop was completed. In this case the variable ‘last_changed’ is being updated from within the for loop so I assumed it would stick. Is this not the case? I find those jinja docs a little hard to comprehend at times. If so, then yes your namespace solution would fix this.

Wow that’s a lot cleaner, thank you once again Taras. For my own personal learning curve, is there a way to isolate only the sensors that are ‘on’? Perhaps a filter for state in the line {% set time = sensors | map(attribute='last_changed') | max %} ? Edit: Figured it out. Added a new line after the sensors declaration - {% set sensors = sensors | selectattr("state", "equalto", "on")|list %}

Also, can anyone recommend a good source of free tutorials for Jinja2. It has such potential, but I think the entry curve into understanding is extremely high and I’d love to be able to harness its power for HA purposes.

I’m not aware of tutorials but I’ve found examples elsewhere, for example, on StackOverflow. I’ve also used the official Jinja2 documentation (and various python references) as well as Home Assistant’s documentation. However, this community forum contains the most relevant examples for Home Assistant. Everything I know about Jinja2 has been learned by studying (and emulating) other people’s work posted on this forum.

1 Like

Thanks Taras. I will bumble my way through as I do with most learning curves!

I must say your help in the past week has been exceptional. Thanks to you I now have 1 lighting automation to rule them all :slight_smile: I am using this sensor to inform the automation which room is the most active/inactive, which triggers the lights in the room in question. So this evening I will be deleting around 10 automations :slight_smile:

1 Like