Why doesnt this automation trigger automatically

So I try to show each run automation in the frontend, for which I have a python script (thank you @petro for rebuilding my script called after each run script), which works fine. The thing is the automation doesnt work as expected (or so i think…)

It does get triggered when I manually trigger an automation in the dev-tools, or have a switch flipped that turns on or Off an automation.

It doesn’t trigger when an automation gets triggered based on the trigger of that automation. Which is the point in the first place…

Please check with me why below automation this would be wrong (never mind the notify, which is only there now for testing purposes to see if the message itself is correctly formatted):

 ## Call Last Automation after each automation
    - alias: 'Call Service Event (Automation)'
      id: 'Call Service Event (Automation)'
      hide_entity: True
      initial_state: 'on'
      trigger:
        platform: event
        event_type: call_service
        event_data:
          domain: automation
          service: trigger
      action:
        - delay: 00:00:02
        - service: notify.notify
          data_template:
            message: "{{ trigger.event }}"
        - service: python_script.last_automation
          data_template:
            event: "{{ trigger.event }}"

and why this automation doing the same for Scripts does work perfectly:

# Call Last command after each script
- alias: 'Call Service Event (Script)'
  id: 'Call Service Event (Script)'
#  hide_entity: True
  initial_state: 'on'
  trigger:
    platform: event
    event_type: call_service
    event_data:
      domain: script
  action:
    - delay: 00:00:02
    - service: python_script.last_cmd
      data_template:
        event: "{{ trigger.event }}"

thanks,
Marius

I would think because a script is called via a service, and an automation is not.

ok that would make sense :wink:
so calling it manually accounts as a service then? or switching on/off?
Coming to think of it, that would precisely constitute the main difference between an automation and a service, it running automatically versus being called…?

is there another way to sense (‘call’) the automations being triggered then?

write a loop for domain automation which checks the last_triggered against now() building on this:?

   {% for state in states.automation -%}
  {% if loop.first %}{% elif loop.last %}
{% else %}
{% endif %}  

{%- if state.attributes.last_triggered-%}

  {{state.entity_id}}:
      last_triggered: {{ state.attributes.last_triggered }}"
      {%-endif-%}
{%- endfor -%}

When an automation runs, its state’s last_triggered attribute changes. So, for a particular automation, you could do something like this:

automation:
  - alias: Do something when a particular automation runs
    trigger:
      platform: state
      entity_id: automation.i_care_about
    condition:
      condition: template
      value_template: >
        {{ trigger.from_state.attributes.last_triggered !=
           trigger.to_state.attributes.last_triggered }}
    action:
      # Do something

The condition would differentiate between the automation having been triggered, or just being turned off or on.

Now, how you’d expand that to cover multiple automations, I leave to the interested student. :wink:

crossposting…

that seems quite the elegant value_template indeed. nice and simple. thank you!
isnt there a way to have the trigger read: any automation …?

trigger_template: {% for state in states.automation -%}

The only way I know how to do that is to list all the automations you care about in entity_id:

automation:
  - alias: Do something when a particular automation runs
    trigger:
      platform: state
      entity_id:
        - automation.i_care_about_1
        - automation.i_care_about_2
        - automation.i_care_about_3
        ...
    condition:
      condition: template
      value_template: >
        {{ trigger.from_state.attributes.last_triggered !=
           trigger.to_state.attributes.last_triggered }}
    action:
      # Do something

The nice thing is the trigger variable is also available in the action part, so you can use, e.g., trigger.entity_id, or trigger.to_state.attributes.friendly_name, etc.

Ok, I would have a separate use for that too, so thank you indeed.

I need an automation to watch all automations though…
something like:

trigger:
  platform: template
    value_template: >
      {% for state in states.automation -%}
        {{ now() == state.attributes.last_triggered }}
      {% endfor %}

would this be getting there?

{% macro automation() %}      
{% for state in states.automation -%}
  {% if  now() == state.attributes.last_triggered  %}{{state.attributes.friendly_name}}
  {%endif%}
{% endfor %}
{% endmacro%}

{% if automation() | trim != "" %}
  {{ automation() }}
{% else %}
 No automation triggered
{% endif %}

or

{%- for state in states.automation -%}
{%- if state.attributes.last_triggered -%}
{{state.attributes.friendly_name.ljust(45)}}: {{as_timestamp(state.attributes.last_triggered )|timestamp_custom("%H:%M:%S")}}
{{- '\n' -}}
{%-endif%}
{%-endfor%}   

if only I would be able to change the if statement here (it now checks if it is not None, and shows all automations last_triggered’s) into a check for being triggered in the last second or so.

{% if as_timestamp(now()) - as_timestamp(state.attributes.last_triggered) <1 %} or even {% if as_timestamp(now()) - as_timestamp(state.attributes.last_triggered) <10 %} doesn’t error out, but doesnt show anything either…

getting back to this one more time, please have a look with me if it would be an option to check for the event state_changed on the attribute last_triggered?

these are the available events:

16

and last_triggered would account for a state change.

trigger:
    platform: event
    event_type: state_changed
    event_data:
      domain: automation
      attributes: last_changed

not sure about the attributes: last_changed of course since that isnt documented. But maybe it isnt necessary, for a triggered automation has its state changed…?

Interesting idea. Hadn’t thought of that.

FYI, the state_changed event is documented here.

Using that, this might work for you:

- alias: Automation ran
  trigger:
    platform: event
    event_type: state_changed
  condition:
    - condition: template
      value_template: >
        {{ trigger.event.data.entity_id.startswith('automation.') and
           trigger.event.data.entity_id != 'automation.automation_ran' and
           trigger.event.data.old_state is not none and
           trigger.event.data.new_state is not none }}
  action:
    - condition: template
      value_template: >
        {{ trigger.event.data.new_state.attributes.last_triggered !=
           trigger.event.data.old_state.attributes.last_triggered }}
    - ...

The reason I split the condition into two parts, one in the automation’s condition section, and the other in the automation’s action section, is that it’s possible for either trigger.event.data.old_state or trigger.event.data.new_state to be omitted None. Since the automation’s condition will always be evaluated, I wanted to avoid referencing something that might not exist (i.e., attributes...).

So, the first condition tests that the event is from the automation domain, and that it’s not from this automation itself. It also makes sure that both old_state and new_state exist are not None. Assuming all this is true, then the actions start to run.

The first action is a condition that decides if the new last_triggered is different from the old last_triggered. If so, then the automation must have just run. If not, then the rest of the automation actions don’t run.

I haven’t tested any of this, but based on my experience so far with HA, I think this might do what you want.

EDIT: This extremely old post has been brought back to haunt me. I’ve adjusted accordingly.

Nice, rebooting as i write… thx!

why wouldn’t we use the domain in the trigger directly? Wouldn’t that make it even more secure and processor friendly?

  trigger:
    platform: event
    event_type: state_changed
    event_data:
      domain: automation

can confirm the above doesnt work…

this though does:

- alias: Automation ran
  trigger:
    platform: event
    event_type: state_changed
  condition:
    - condition: template
      value_template: >
        {{ trigger.event.data.entity_id.startswith('automation.') and
           trigger.event.data.entity_id != 'automation.automation_ran' 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_automation_triggered
      data_template:
        message: "{{ trigger.event }}"
    - service: python_script.last_automation
      data_template:
        event: "{{ trigger.event }}"

got an automatic file creation with all notifications listed nicely, and the python script creates a sensor with the last automation in the frontend!

Magic, thank you very much!

1 Like

If you can figure out how to do that, then yes, that would be better. But I didn’t see that domain was one of the pieces of data in the event. Again, see here.

Where would you put the automation.count_warnings and automation.count_errors in these 2 to exclude them?

in the action template or in the condition?

If you mean you don’t want this automation to run when those two automations run, then in the automation condition part:

  condition:
    - condition: template
      value_template: >
        {% set skip_list = ['automation_ran', 'count_warnings', 'count_errors'] %}
        {{ 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 }}

no, the other way around…
I don’t want these two automations to be taken into account by the automation.automation_ran…but I think your skip list does just that? skip these automations from being a valid condition for the action?

other thing: right now, the {{trigger.event}} has this as a result per trigger:

2018-07-20T18:06:52.209329+00:00 <Event state_changed[L]: entity_id=automation.count_warnings, old_state=<state automation.count_warnings=on; last_triggered=2018-07-20T20:05:04.392134+02:00, id=Count warnings, friendly_name=Count warnings, custom_ui_state_card=state-card-custom-ui @

before, with my original automation, the event was:

2018-07-16T12:53:28.909974+00:00 2018-07-16 12:53:15.116120+00:00: automation Call Service Event (Script) was triggered

can i somehow change the {{trigger.event}} safely into
{{trigger.to_state.attributes.last_triggered}}: {{trigger.to_state.attributes.friendly_name}}

so it shortens the message somewhat?

Yes, that’s what I meant.

Not quite. Try:

{{ trigger.event.data.new_state.attributes.last_triggered }}
{{ trigger.event.data.new_state.attributes.friendly_name }}

But given that we’ve already checked that last_triggered just changed, and the state object has a name attribute that is the same as attributes.friendly_name (if there is one), you can shorten to:

{{ trigger.event.data.new_state.last_updated }}
{{ trigger.event.data.new_state.name }}
1 Like

thanks!
its really a lot of fun playing with these templates and scripts like this. My python script results in a much shorter message, based on the same {{trigger.event}}:

47

which is what I am trying to see in the notify log too.

for completeness sake this is the python:

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' })

much better! see before and after:

2018-07-20T21:12:49.847403+00:00 <Event state_changed[L]: entity_id=automation.update_last_motion, old_state=<state automation.update_last_motion=on; last_triggered=2018-07-20T23:12:47.772661+02:00, id=Update Last Motion, friendly_name=Update Last Motion, custom_ui_state_card=state-card-custom-ui @ 2018-07-20T20:25:02.643627+02:00>, new_state=<state automation.update_last_motion=on; last_triggered=2018-07-20T23:12:49.745384+02:00, id=Update Last Motion, friendly_name=Update Last Motion, custom_ui_state_card=state-card-custom-ui @ 2018-07-20T20:25:02.643627+02:00>>

2018-07-20T21:17:13.304607+00:00 2018-07-20 21:17:05.231622+00:00: Startup HA
2018-07-20T21:17:13.363184+00:00 2018-07-20 21:17:05.326261+00:00: Average indoor temp
2018-07-20T21:17:15.953688+00:00 2018-07-20 21:17:07.568440+00:00: Sense Switches change

time is 2 hours off though…and could be formatted more user friendly, as in the python. Would you know how to realize that final touch of finesse?

Where do you see this? I see these times:

2018-07-20T21:12:49.847403+00:00
2018-07-20T23:12:49.745384+02:00

They are (approximately) the same. It’s just that the first one is shown in UTC, whereas the second one is shown in local time. (I presume your local timezone is +02:00.)

in the screenshot i posted… There’s twice the time in etc, not local time??
2018-07-20T21:17:15.953688+00:00 2018-07-20 21:17:07.568440+00:00: Sense Switches change

this is what im getting back from the template, and yes, we are +2 hours from etc…

The log timestamps (the date/times at the beginning of each line) do look like they’re printed in UTC. I see the same in my log file. However, if the output of a template is showing a time in UTC (+00:00) and you’d rather show it in local time (+02:00), you can definitely do that. But exactly how you do that depends on what type the data really is (i.e., string or Python datetime), which may not be obvious. But what usually works is:

{{ as_timestamp(whatever)|timestamp_local }}