Adapt python script to also show automations

Using this python script for showing the last command (script in this setting),
10

id like to also show it the automations being triggered.

How would this script have to be adapted to do that:

# Get params
event = data.get('event')
# logger.error("LAST CMD: " + str(event))
# Sample: <Event call_service[L]: service_data=, service_call_id=78356624-86, service=mp_playpause, domain=script>

# Find the script name.
pos_start = event.find('service=')+8
pos_end = event.find(',', pos_start)

# Get the state object (script) from the name
entity_id = 'script.' + event[pos_start:pos_end]
state = hass.states.get(entity_id)
dt = datetime.datetime.now() #state.attributes.get('last_triggered') #
time = "%02d:%02d" % (dt.hour, dt.minute)
msg = []

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

if (msg is None):
    msg = ''

# Ignore some names
# msg = state.name
if (msg == 'None') or (msg.startswith('Set ')):
    msg = ''

if (msg != '') :
    # Sensor update
    hass.states.set('sensor.last_command', '{}'.format( msg), {
#        'custom_ui_state_card': 'state-card-value_only',
#        'text': sensor_message,
        'unit_of_measurement': 'Cmd',
        'friendly_name': time,
        'entity_picture': '/local/buttons/command.png'
    })

the automation passing the script its data is as follows:

- 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 }}"

Could i simply add another trigger here:

  trigger:
    - platform: event
      event_type: call_service
      event_data:
        domain: script
   -  platform: event
      event_type: call_service
      event_data:
        domain: automation

if so, the entity_id = 'script.' + event[pos_start:pos_end] would still have to be adapted to include the automation, and have the state include these and show the msg

Please have a quick look?

Cheers,

Marius

I think you’d just need to modify all the lines that call out script. You may need to see what the automation event data looks like. The line

pos_start = event.find('service=')+8

may need to be adjusted to account for finding the correct item to get the entity_id. I’d wager it would need to change to

pos_start = event.find('entity_id=')+10

You could also change your sample line to help you figure out the parsing.

# Get params
event = data.get('event')
# logger.error("LAST CMD: " + str(event))
# Sample: <Event call_service[L]: service_data=, service_call_id=78356624-86, service=mp_playpause, domain=script>

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

# Get the state object (script) from the name
entity_id = 'automation.' + event[pos_start:pos_end]
state = hass.states.get(entity_id)
dt = datetime.datetime.now() #state.attributes.get('last_triggered') #
time = "%02d:%02d" % (dt.hour, dt.minute)
msg = []

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

if (msg is None):
    msg = ''

# Ignore some names
# msg = state.name
if (msg == 'None') or (msg.startswith('Set ')):
    msg = ''

if (msg != '') :
    # Sensor update
    hass.states.set('automation.last_command', '{}'.format( msg), {
#        'custom_ui_state_card': 'state-card-value_only',
#        'text': sensor_message,
        'unit_of_measurement': 'Cmd',
        'friendly_name': time,
        'entity_picture': '/local/buttons/command.png'
    })

thanks @petro
getting back to this, Im setting up as another python script, so I can use them both. Couldn’t find a quick way to have the one script see to both scripts, and automations…

why would i need to change ‘service’ into ‘entity_id’ , instead of ‘automation’? and then of course position 11…

ive added the service to the domain in the automation, but still nothing is displayed, nor the sensor created:

- 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: python_script.last_automation
      data_template:
        event: "{{ trigger.event }}"

Looking back, I have no clue where I was going with that line, should have been

event.find('automation=')+12

EDIT: I mean it does depend on what an automation event looks like. I have no clue because I haven’t looked before.

lol :wink:

so now I have this python:

# Get params
event = data.get('event')
logger.error("LAST AUTOMATION: " + str(event))
# Sample: <Event call_service[L]: service_data=, service_call_id=78356624-86, service=mp_playpause, domain=script>

# Find the script name.
pos_start = event.find('automation=')+12
pos_end = event.find(',', pos_start)

# Get the state object (script) from the name
entity_id = 'automation.' + event[pos_start:pos_end]
state = hass.states.get(entity_id)
dt = datetime.datetime.now() #state.attributes.get('last_triggered') #
time = "%02d:%02d" % (dt.hour, dt.minute)
msg = []

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

if (msg is None):
    msg = ''

# Ignore some names
# msg = state.name
if (msg == 'None') or (msg.startswith('Set ')):
    msg = ''

if (msg != '') :
    # Sensor update
    hass.states.set('sensor.last_automation', '{}'.format( 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 this automation:

# 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 }}"

Nothing happening and no sensor.last_automation is created…

if I trigger the automation manually this is the response, but I a m afraid it rather useless for now:

<Event call_service[L]: domain=automation, service=trigger, service_data=entity_id=automation.call_service_event_automation, service_call_id=1972124944-486>

btw, shouldn’t it be pos_start = event.find('service=')+12 ? since i want it to find the service following after the first 11 characters of automation.xxx

ah ok, then yes . I was half right. You need +10 for the length of entity_id=, and then +11 for the length of automation..

pos_start = event.find('entity_id=')+21
>>> event = "<Event call_service[L]: domain=automation, service=trigger, service_data=entity_id=automation.call_service_event_automation, service_call_id=1972124944-486>"
>>> pos_start = event.find('entity_id=')+21
>>> pos_end = event.find(',', pos_start)
>>> event[pos_start:pos_end]
'call_service_event_automation' 

getting closer, leaving out the service: trigger in the automation, I can get the action:notify to be executed when i switch an automation on or off. (not yet get the sensor created, but at least I am certain now the service event is the right one)
doesn’t execute when an automation is triggered though, which is what i am after.

not sure abut this code: >>> means what? these aren’t comments are they, this is the full python code? (havent had that is the code before, so please forgive my asking)

So I have no idea what your end goal is. From reading the code it looks like it:

finds automation that just ran and makes the entity_id for it.
gets the state for said automation (which should be off, unless it’s still running)
finds the time it last triggered (which should be now)
makes a message with the name of the automation.
Updates a sensor named ‘last_automation’ and does nothing else.

that’s python in idle. I used it to debug the code I was giving you. >>> is code I input. lines without it are what are returned.

my end goal is to show which was the last automation to have been triggered and show that with the sensor., just as I do that with the Last-command script, showing the last run script. Both to check whether the internal logic of automations is correct, and make it a little bit easier to check, rather than having to check the logs.

compare last command:


30

the notify is only there now to check whether the automation runs, and where it goes wrong… Right now I could see it running (got a notification,) but not creating the sensor yet, so nothing in the frontend. Which is my goal. to see each triggered automation with the time it was triggered.

This should work.

# 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_end = event.find(',', pos_start)

# Get the entity_id
entity_id = 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')

# try to get the automation friendly name
try:
    msg = state.name
except:
    msg = None


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

thanks!, but no it doesnt , yet… sorry

btw the 2 lines aren’t necessary here, only for when using the custom-ui on a larger text card

'custom_ui_state_card': 'state-card-value_only',
 'text': sensor_message,

then hass is probably not getting the object.

write a bunch of debug statements in there looking at each object and find out which one is causing msg to be None.

well something is happening, this automation got triggered:

Fri Jul 13 2018 15:53:11 GMT+0200 (CEST)

LAST AUTOMATION: <Event call_service[L]: domain=automation, service=trigger, service_data=entity_id=automation.call_summary, service_call_id=1971637392-1888>

but immediately above that is this:

Fri Jul 13 2018 15:53:11 GMT+0200 (CEST)

Error executing script: '__import__'
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/homeassistant/components/python_script.py", line 166, in execute
    exec(compiled.code, restricted_globals, local)
  File "last_automation.py", line 17, in <module>
KeyError: '__import__'

line 17 being: time_string = datetime.datetime.now().strftime('%I:%M')

must be the old time issue we had before…so,

ive changed that back into this:

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" % (dt.hour, dt.minute)
# try to get the automation friendly name
try:
    msg = state.name
except:
    msg = None


if msg:
   if not msg.startswith('Set '):
       # Sensor update
       hass.states.set('sensor.last_automation', '{}'.format( 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, lo and behold:

12

progress! now lets see why this is not displayed too when being triggered manually…:wink:
thanks @petro, much appreciated, as ever!

next up investigate why this works, and the other script failed to populate the sensor.

strftime may be imported in the datetime object. not sure. If that works you should be good.

just letting you know this

pos_start = event.find('entity_id=')+21
pos_end = event.find(',', pos_start)

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

yields the same result.

albeit also only when manually triggered. What could be the reason the python script isnt triggered on each triggered automation?

the automation taking care of that is ‘on’ and like this, just as with the parallel last_cmd automation which works just as expected…

- 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 }}"

(rebooting to check if its not the notification thats causing trouble, now i have exceeded the rate limit ;-)) )

Im not sure what you mean by this?

i think it was the same as

pos_start = event.find('entity_id=')+10
pos_end = event.find(',', pos_start)

# Get the entity_id
entity_id = event[pos_start:pos_end]

but my mind is going crazy with the instability Hassio is showing lately, so I might be mistaken…
So frustrating this is. Tradfri and Hue lights unavailable, system spontaneous reboots…
Hope its the heat, but fear it’s not…

33
grrr