Template to see which automations ran in last x mins

I’m sure someone one day might find this useful. I have about 140 automations and one of them is doing something funky, but I don’t know which one. This little template helps me narrow down to see which automation just ran in the last x mins so I know which ones to look at. Just paste this into your template editor and change the set mins variable and it will output the automations that just ran within that time period.

     {% set mins = 3 %}
     {%- for state in states.automation -%}
        {%- if loop.first %}{% elif loop.last -%}
        {%- else -%}
        {%- endif -%}
        {%- if (as_timestamp(state.attributes.last_triggered)|int) > (now().strftime("%s")|int - (mins*60)) -%}
          {{state.entity_id}}: 
            last triggered: {{as_timestamp(state.attributes.last_triggered)|timestamp_custom("%H:%M") }}

        {% endif %}
      {%- endfor -%}
9 Likes

Perhaps you should change the subject to “automations” instead of “sensors”.

@nickrout Thanks Nick for catching that. :slight_smile:

thanks for this. i’m sure it can come in handy.

i’m having a hard time following the for-if-elif-else-endif logic portion.

do you mind explaining what the flow of that portion is?

Ditto. There something odd about what’s happening in that for-loop.

This example has inspired me to tackle the problem using another approach. Toss this in the Template editor to get an idea of what I have in mind.

{{ states.automation | list }}

If I put it in the template editor it obviously does work but I just don’t understand why it works.

I think the template contains ‘leftovers’ from something else and its those leftovers that are puzzling.

This works without the puzzling bits:

{% set mins = 3 %}
{%- for state in states.automation -%}
  {% set last = as_timestamp(state.attributes.last_triggered) %}
  {% set current = as_timestamp(now()) - (mins*60) %}
  {%- if (last != None) and last > current -%}
    {{state.entity_id}}: 
       last triggered: {{last|timestamp_custom("%H:%M") }}
  {% endif %}
{%- endfor -%}

EDIT
Incorporated improvement made by @klogg
Replaced:

{%- if last > current -%}

with:

{%- if (last != None) and last > current -%}
1 Like

Correct. The If, elif, else and endif in the middle was just leftovers from something else I was doing and forgot to take out.

the template doesn’t work in my setup, but I track my automations with this automation :wink:

- alias: Automation ran
  id: 'Automation ran'
#  initial_state: 'off'
  trigger:
    platform: event
    event_type: state_changed
  condition:
    condition: template
    value_template: >
      {% set skip_list = ['automation_ran', 'count_warnings', 'count_errors',
                           'activate_map_sensors_actueel', 'call_family_home',
                           'timed_python_scripts_per_20_secs'] %}
      {{ trigger.event.data.entity_id.startswith('automation.') and
         trigger.event.data.entity_id.split('.')[1] not in skip_list and
         'old_state' in trigger.event.data and 'new_state' in trigger.event.data }}
  action:
    - condition: template
      value_template: >
        {{ trigger.event.data.new_state.attributes.last_triggered !=
           trigger.event.data.old_state.attributes.last_triggered }}
    - service: notify.filed_automations
      data_template:
        message: >
         {{ as_timestamp(trigger.event.data.new_state.last_updated)|timestamp_custom('%d %b: %X') }}: {{ trigger.event.data.new_state.name }}
    - service: python_script.last_automation
      data_template:
        event: '{{ trigger.event }}'

the services in the action block are 2-fold:
the first writes the automation to a file, so I can always check the history,
the second shows a sensor in the frontend, so I can see it happening.

As a kind of double check, I’ve also got the last automation of automations file displayed in the front-end.

1 Like

There are some great people on this forum but I’m especially loving @123 lately.
This is not the first time in the last few days he/she has been ‘hooked’ by something and decided to look into a solution, apparently just for the fun of it!

This is really cool, thank you!

Just one question, can you tell me the sensor name that it creates on the front end? Also, I assume that this requires your yaml to be inserted into automations?

Thanks again…

FWIW, The original did but the second version didn’t in mine either.
I changed:

{%- if last > current -%}

to:

{%- if (last != None) and last > current -%}

and then it did.

sure, but as said there are really 2 files. One made by the python script last_automation.py, called sensor.last_automation:

############################################################################## 
# Last automation, to create a sensor for the last automation. It takes as data the trigger.event  form the automation.automation_ran
# Take note: an automation's attribute last_triggered is only set when the action part is executed (and not when the trigger gets triggered....)
# @Mariusthvdb
############################################################################## 
# Get params
event = data.get('event')
#logger.error("LAST AUTOMATION: " + str(event))
# Sample: <Event call_service[L]: domain=automation, service=trigger, service_data=entity_id=automation.call_service_event_automation, service_call_id=1972124944-486>

# Find the automation name
#** pos_start = event.find('entity_id=')+10
pos_start = event.find('entity_id=')+21
pos_end = event.find(',', pos_start)

# Get the entity_id
#** entity_id = event[pos_start:pos_end]
entity_id = 'automation.' + event[pos_start:pos_end]

# get the state object
state = hass.states.get(entity_id)

# Make a time string in 24 hour format
#time_string = datetime.datetime.now().strftime('%I:%M')
dt = datetime.datetime.now() #state.attributes.get('last_triggered') #
time = "%02d:%02d:%02d" % (dt.hour, dt.minute, dt.second)
# try to get the automation friendly name
msg = []

try:
    msg = state.name
except:
    msg = None

if msg:
   if not msg.startswith('Set '):
       # Sensor update
       hass.states.set('sensor.last_automation', msg, {
#            'custom_ui_state_card': 'state-card-value_only',
#            'text': sensor_message,
            'unit_of_measurement': 'Aut',
            'friendly_name': time,
            'entity_picture': '/local/buttons/play-mode-repeat.png' })

and the one made by the notify service:

notify:
  - name: filed_automations
    platform: file
    filename: filed_automations.txt

and the platform file:

sensor:
  - platform: file
    file_path: /config/filed_automations.txt
    name: Filed automations

to give you an idea, this is the contents of the notify file:

29 Mar: 16:48:10: Life360 connected
29 Mar: 16:48:31: Update Last Motion
29 Mar: 16:48:36: Update Last Motion
29 Mar: 16:48:37: Sense Active change
29 Mar: 16:48:38: Sense Device trackers media change
29 Mar: 16:48:47: Sense Active change
29 Mar: 16:48:48: Life360 connected
29 Mar: 16:49:26: Life360 connected
29 Mar: 16:50:00: Low light - Hallway motion sensors
29 Mar: 16:50:00: Average indoor temp
29 Mar: 16:50:05: Sense Device trackers media change
29 Mar: 16:50:27: Sense Lights change
29 Mar: 16:50:39: Sense Lights change
29 Mar: 16:50:40: Sense Lights change
29 Mar: 16:52:00: Low light - Hallway motion sensors
29 Mar: 16:53:23: Sense Lights change
29 Mar: 16:54:00: Low light - Hallway motion sensors

the sensor looks like (top one):

29

and

39

put the automation in the group also, so I can quickly turn on/off if necessary.

2 Likes

Thanks very much! / Baie Dankie :slight_smile:

It’s definitely for the fun of it, certainly not for the Likes which seem to be issued randomly.

There have been cases where I’ve provided almost the entire solution … and get no Likes (zero appreciation). Better yet, the person who requested assistance tags their own post as the ‘solution’. :man_shrugging:

So, yeah, for the fun of it, definitely not for the Likes.

5 Likes

It didn’t work for me as you have it in that post.

This does work though:

{% set mins = 3 %}
{%- for state in states.automation -%}
  {% set last = as_timestamp(state.attributes.last_triggered)|int %}
  {% set current = as_timestamp(now()) - (mins*60) %}
  {%- if last > current -%}
    {{state.entity_id}}: 
       last triggered: {{last|timestamp_custom("%H:%M") }}
  {% endif %}
{%- endfor -%}

I needed to convert the attribute in the “last” line to an “int”.

1 Like

I’m not experiencing the need to cast it with int so I wonder why it works differently for me?

Here’s a screenshot of the template, slightly modified to show the values of the timestamps (L=last, C=current).


Simply casting last to integer can’t be the whole story because current remains as floating point.

I do need Klogg’s enhancement (to test last for None) because, when I ran the template today, the data set included an instance where last is None.


EDIT
Or is the result of as_timestamp a string? In which case last > current is a string comparison?? That could lead to unexpected results.

I just saw your edit and tried it that way and it also works for me too.

So, to recap, it wouldn’t work as originally posted,

then I added " |int" and it worked.

then added the “…last != None…” and that also worked with or without the “|int” added.

I almost absolutely sure it’s not. I’ve never seen that behavior.

I think I realize what’s going on…

if the last_triggered is a null value then the template returns an unknown value for “last” then it errors out trying to compare an unknown (or None?) to a float.

if you force the last result to an int then the null becomes a 0 and everything works as expected.

I think…