this must be too simple, but really sorry to admit my brains fail to see the solution for now…
please allow me the following:
I have an automation triggered by a system fault (Integration Tradfri keep-alive fails), and I want to keep track of how often and when that happens.
Ive considered the Counter integration obviously, but that is not persistent across restarts.
So I was looking at the trigger template integration for Number which is persistent, but it might not be the correct option, maybe I should use a regular trigger template?
this is what I had in mind:
template:
- trigger:
- platform: state
entity_id: automation.integration_reload
# should trigger on automation being triggered
number or sensor:
- unique_id: count_number_automation_reloaded
name: Count number automation reloaded
icon: mdi:counter
state: >
{{former state + 1}}
attributes:
last: >
{% set stamp = as_local(states[trigger.entity_id].last_changed).strftime('%X') %}
{{ stamp }}
<<: &history
history_1: >
{{this.attributes.last|default('Not yet set')}}
history_2: >
{{this.attributes.history_1|default('Not yet set')}}
history_3: >
{{this.attributes.history_2|default('Not yet set')}}
history_4: >
{{this.attributes.history_3|default('Not yet set')}}
history_5: >
{{this.attributes.history_4|default('Not yet set')}}
last_triggered: >
{{trigger.to_state.last_changed.isoformat()}}
ofc this is pseudo code on the state (the attributes work, as I have those on my other trigger templates to record the last few motion detections.
It might be a bit of overkill, as I could probably just use the last_changed of the counter… but, that is not the main challenge here.
Can you help me out here how to update the counter each time the automation is triggered?
Ive also considered adding a service in the automation itself, but as said that included the counter integration not being persistent.
which narrows down the issue to ‘recording’ the moments only. I will include it in recorder ofc. and might not even require the below trigger template sensor because of that
I’m sure there’s other ways to do this and the template might be a bit verbose, but it should work. You might want to add a trigger to reset it to zero though.
If you are interested, there’s a way to create a single “history” attribute containing a list of historical values (as opposed to multiple attributes, each containing one historical value).
Another user needed to maintain a record of two things: the names of the last 5 songs that had been played and the time when each song was played. What I suggested creates a list of the desired information sorted in reverse chronological order (newest is first).
For your application it would be simpler because you only need to track one item, the time. The advantage of the suggested approach is that the history can be easily extended beyond 5 entries.
Here’s another example of the same principle used to record when a door was opened, closed, and the duration it was left open.
Not shown in these examples, but something that I have implemented for my own application, is the ability to purge the history via a custom event. The second example comes close to demonstrating how to do that because it uses a Time Trigger (instead of an Event Trigger) to purge history every day at midnight.
On a separate note, I believe the following template can also be used as an incrementing counter. Please note that I only tested it in the Template Editor with a non-existent entity, like states.counter.xyz.state, and not in a Trigger-based Template Sensor with this.state, but I think it should work.
that is most attractive indeed!
I confess having something similar for some of my motion template triggers (made with guidance by @TheFes ):
- unique_id: last_time_motion_triggered
name: Last time motion triggered
icon: mdi:update
state: >
{{as_local(states[trigger.entity_id].last_changed).strftime('%X')}}
attributes:
history: >
{%- set previous = this.attributes.history | default([]) %}
{%- set new = [this.attributes.last_area | default('nowhere') + ': ' + this.state] %}
{{ previous[-4:] + new }}
last_area: >
{{area_name(trigger.entity_id)}}
and did not consider that here.
Your 2 examples have even gone a bit further. I’ll copy those to my cookbook for sure. I believe they go a bit beyond the purpose if my current quest, but they are very useful in several scenarios I do use.
On the Markdown card: check this btw for some formatting I ran in today, it should be registered in the Frontend examples too.
I already had vingerha’s post bookmarked. It’s the alternating row shading that had caught my eye. I don’t use card-mod (my Dashboard is plain vanilla) but thought that was a neat application for the Markdown card (which I do use).
I made your suggestions into a test trigger template sensor, but it is not correct just yet:
- unique_id: count_reload_tradfri_integration_single_attribute
name: Count reload Tradfri integration single attribute
icon: mdi:eye-plus-outline
state: >
{{this.state|default(0)|int(0)+ 1}}
attributes:
history: >
{% set current = this.attributes.get('history', []) %}
{% set new = [{
"time": trigger.to_state.last_changed.isoformat() }] %}
{{ (new + current)[:5] }}
on each trigger, it registers twice… both state and attributes. Ive reloaded the automation 2 times only (note it also shows the time to be identical 4 times):
lastly, note the difference in representation of the last_changed.isoformat() in both of my screens. When used in the single attribute, it shows as the timestamp, but when used as single attribute, it renders a nicely formatted time March 16, 2023 at 1:52:46 PM
template:
- trigger:
- platform: state
entity_id: automation.reload_tradfri_integration #counter.
I triggered it manually btw, but that should not make a difference I suppose. Could it be this triggers twice because of the automation itself? some attribute next to the state_changed maybe…
fwiw, this is the automation:
- alias: Reload Tradfri integration
id: reload_tradfri_integration
mode: single
trigger:
- platform: event
event_type: system_log_event
event_data:
level: WARNING
id: observation
- platform: event
event_type: system_log_event
event_data:
level: ERROR
id: failed
condition:
- >
{{now() - this.attributes.last_triggered > timedelta(minutes=5) if
this.attributes.last_triggered is not none else true}}
# or:
# - >
# {{trigger.event.data.name == 'tradfri.base_class' and 'Observation failed for'
# in trigger.event.data.message[0]}}
- >
{{trigger.event.data.name == 'homeassistant.components.tradfri' and
'Keep-alive failed' in trigger.event.data.message[0]}}
# - >
# {{trigger.event.data.name == 'coap' and
# 'Error received in UDP connection under DTLS' in trigger.event.data.message[0]}}
action:
- service: counter.increment
entity_id: counter.reload_tradfri_integration
- service: system_log.write
data:
message: >
Ikea Tradfri: '{{trigger.id}}' on {{trigger.event.data.name}} issue logged:
{{trigger.event.data.message[0]}}.
Reloading integration
level: critical
logger: homeassistant.components.tradfri
- service: script.reload_tradfri_integration
- service: system_log.write
data:
message: >
Ikea Tradfri integration was reloaded because of {{trigger.id}}
Full data:
{{trigger.event}}
level: critical
logger: homeassistant.components.tradfri
- service: persistent_notification.create
data:
title: >
{{trigger.event.data.timestamp|timestamp_custom('%X')}}: Tradfri reloaded
message: >
{{now().timestamp()|timestamp_custom('%X')}}: Ikea Tradfri integration was
reloaded because of {{trigger.id}}:
Message: {{trigger.event.data.message[0]}},
Logger: {{trigger.event.data.name}},
Source: {{trigger.event.data.source}},
Level: {{trigger.event.data.level}}
Redacted; nope. What I had in mind wouldn’t work.
What exactly do you want to detect with that State Trigger? In its current form it triggers when you enable/disable the automation and if any of its attributes changes value.
last_triggered current
I suggest you limit the State Trigger to listen to changes to last_triggered.
- platform: state
entity_id: automation.reload_tradfri_integration #counter.
attribute: last_triggered
I want the trigger sensor to count the number of times the automation gets triggered, or, more specifically, when the automation fires the action block (so its last_triggered is changed)
when I added the counter increment as service, that of course was no longer required, as the automation simply causes the secondary counter entity to increment.
I could also may fire a custom event as service:
- event: used_for_trigger_sensor_counter
and then use that event as trigger in the trigger template sensor:
that does seem to help, it only registers a single increment now. so that is good. the attribute itself though still is not touched by this ofc, and lists 5 identical timings:
and I now see that the last_changed there is exactly what it returns. … the last changed of the automation (on/off) and not it’s last_triggered, or the last_changed of the ‘this.state’ for that matter.
this helps:
attributes:
history: >
{% set current = this.attributes.get('history', []) %}
{% set new = [{
"time": trigger.to_state.attributes.last_triggered.strftime('%D %X') }] %}
{{ (new + current)[:5] }}
FWIW, you’re recording just the time so there’s no need to store it as a key-value pair. In other words, the attribute’s value can simply be a list of strings (where each string is a time value) and not a list of dictionaries (where each dictionary contains a single key-value pair).
{% set new = [op] %}
The reason why the other examples used a list of dictionaries is because they tracked several things for each event (door opened time, door closed time, duration left open).
On a separate note, while experimenting with this technique, I encountered a Home Assistant feature that made the testing more challenging.
Let’s say you did some testing and the attribute now contains several items. However, you now want to significantly change how the attribute records information so you need to purge all of the recorded items.
So you delete the entity’s configuration and reload Template entities. The entity is now gone.
Now you recreate the entity’s configuration, same entity_id but with modifications to how the attribute is computed, and reload Template entities. The entity is created with the previous entity’s attribute data.
Home Assistant restores the data for Trigger-based Template Sensors. If you delete one, it doesn’t purge the delayed sensor’s stored data. So if you create a new Trigger-based Template Sensor with the same entity_id, it gets the previous one’s stored data.
I assumed that if you create a Trigger-based Template Sensor with a unique_id, then delete the sensor via the UI, it would take care of housekeeping and delete the sensor’s stored data. However, it doesn’t do that either. Basically, there’s no way to get rid of a Trigger-based Template Sensor’s stored data (short of editing the hidden restoration file … which is what I initially did).
It is what also led me to add the ability to purge the attribute’s value via an event (for greater convenience).
correct, I will adapt. have to find a way to get it to show nicely though, the pairing does take care of that
yes had noticed that, and tbh, I liked it, because the new sensor I used was intended to do so, and now I did not lose all of my historic data.
I can see though that in some situations this might actually be ‘unexpected’.
Not being able to delete that other than editing the hidden files would be an issue, though for that you also found a way as you describe. I think it would be a good idea to add that to the trigger entity documentation.
consider me guilty there, and I am very glad we have that now. It makes various things possible, like showing the last pressed button on state less entities.
I want the trigger sensor to count the number of times the automation gets triggered, or, more specifically, when the automation fires the action block (so its last_triggered is changed).