why are you using an event… those are created by the services (in the next release). Oh I see what he’s attempting to do.
You can template in event_data, not sure why it’s not working for you. It may be an UI thing, switch it to yaml. It may even rquire the old event_data_template
just for interest…seems a cool thing to try and continues to build stuff in your kit bags of ideas - before reworking my set up for this approach was going to wait to see where the upcoming changes end up (have read the PR’s but not fully processed what this means, I’ll have a play with the beta tomorrow! Thanks again
so with the new beta Ive moved this to use the actual notification events, and made it up to:
template:
- trigger:
- platform: event
event_type: call_service
event_data:
domain: persistent_notification
service: create
- platform: event
event_type: call_service
event_data:
domain: persistent_notification
service: dismiss
- platform: event
event_type: call_service
event_data:
domain: persistent_notification
service: dismiss_all
sensor:
- unique_id: persistent_notifications_overview
name: Persistent notifications
state: >
{{ now().timestamp() | timestamp_custom() }}
attributes:
notifications: >
{% set msgs = this.attributes.get('notifications', []) %}
{% if trigger.event.data.service == 'create' %}
{% set new = [{
"id": trigger.event.data.service_data.notification_id | default('TS' ~ now().timestamp()),
"title": trigger.event.data.service_data.title | default(''),
"message": trigger.event.data.service_data.message | default(''),
"time": now().isoformat() }] %}
{{ (msgs + new) }}
{% elif trigger.event.data.service == 'dismiss' %}
{% if trigger.event.data.service_data.notification_id is defined %}
{% set msgs = msgs | rejectattr('id', 'eq', trigger.event.data.service_data.notification_id) | list %}
{% elif trigger.event.data.index is defined and trigger.event.data.index | is_number %}
{% set t = trigger.event.data.index | int(0) - 1 %}
{% if 0 <= t < msgs|count %}
{% set msgs = msgs | rejectattr('id', 'eq', msgs[t].id) | list %}
{% endif %}
{% endif %}
{{ msgs }}
{% else %}
{{ [] }}
{% endif %}
the service_data had to be changed accordingly but now it builds that attributes list nicely.
I must have made a typo, because I can not get the dismissed notification out of the attributes list. When dismissing to 0 notifications does not clear the sensor. Using the UI dismiss all does in fact reset the sensor.
so it seems the trigger.event.data.index is not functional as expected
but unfortunately that is not accepted (no config error, it simply remains unchanged)
what I would most fervently love to see is an attribute with the number of currently notifying notifications . Hopefully, doing that without repeating the complete attribute above.
providing the number of notifications (not yet working dor dismiss/dismiss_all) and an additional attribute for the last change (as that was in the state in Taras’s first suggestion)
changing the state to:
state: >
{{this.attributes.notifications|count if trigger.event.data.service in ['create','dismiss']
else 0 }}
almost makes it happen…
dismiss_all resets to 0 alright.
however, adding another notification only starts counting after the first additional notification, making the state trail 1 compared to the actual number of notifications in the list (and notification icon in the tray)
apparently this is suffering from the fact this variable is the ‘before’ state and not the actual state. But, even when verbosely using the entity_id it behaves the same…
all in all, some serious progress (thx Taras!) , and I need to fix some more…
It may be the 2am side of things talking but reading through the posts I’m unsure if a viable workaround has been found yet for the user case of holding automations for TTS to read them like how you could easily make TTS read persistent notification 1 2 3 4 etc in a row no matter which persistent notifications went off. The requirement for IDs rather than having them as a possible option on top of the +1 system seems to still be a thing.
Just as a reference point, this is what I have now, Its still not 100% correct, most importantly the index in the else is not functional, and (core) notifications are not deleted from the template when dismissed using the UI:
template:
- sensor:
- unique_id: persistent_notifications_count
state: >
{% set msgs = state_attr('sensor.persistent_notifications','notifications') %}
{{msgs|count}}
- trigger:
- platform: event
event_type: call_service
event_data:
domain: persistent_notification
service: create
- platform: event
event_type: call_service
event_data:
domain: persistent_notification
service: dismiss
- platform: event
event_type: call_service
event_data:
domain: persistent_notification
service: dismiss_all
sensor:
- unique_id: persistent_notifications_overview
name: Persistent notifications
device_class: timestamp
state: >
{{now()}}
attributes:
notifications: >
{% set msgs = this.attributes.get('notifications', []) %}
{% if trigger.event.data.service == 'create' %}
{% set new = [{
"id": trigger.event.data.service_data.notification_id | default('TS' ~ now().timestamp()),
"title": trigger.event.data.service_data.title | default(''),
"message": trigger.event.data.service_data.message | default(''),
"time": now().isoformat() }] %}
{{ (msgs + new) }}
{% elif trigger.event.data.service == 'dismiss' %}
{% if trigger.event.data.service_data.notification_id is defined %}
{% set msgs = msgs | rejectattr('id', 'eq', trigger.event.data.service_data.notification_id) | list %}
{% elif trigger.event.data.index is defined and trigger.event.data.index | is_number %}
{% set t = trigger.event.data.index | int(0) - 1 %}
{% if 0 <= t < msgs|count %}
{% set msgs = msgs | rejectattr('id', 'eq', msgs[t].id) | list %}
{% endif %}
{% endif %}
{{ msgs }}
{% else %}
{{ [] }}
{% endif %}
- binary_sensor:
- unique_id: binary_persistent_notifications
device_class: problem
state: >
{{states('sensor.persistent_notifications_count')|int(default=0) != 0}}
icon: >
mdi:message-bulleted{{'-off' if this.state == 'off'}}
the binary is ok, but it is also frustrated by the fact the state of the source sensors is not correct yet in all circumstances
moving that counter to a dedicated template sensor seemed simplest, and we can again use what Taras envisioned above in the state, but I changed it to being a timestamp sensor using:
state: >
{{now()}}
so we can use the nicer representation of the entity in the Frontend:
- entity: binary_sensor.persistent_notifications
secondary_info: last-changed
- entity: sensor.persistent_notifications_count
secondary_info: last-changed
format: relative
- entity: sensor.persistent_notifications
secondary_info: last-changed
# and a conditional Markdown, iterating the list of notifications
- type: custom:hui-element
card_type: conditional
conditions:
- entity: binary_sensor.persistent_notifications
state: 'on'
card:
type: custom:hui-element
card_type: markdown
card_mod:
style: |
ha-card {
box-shadow: none;
margin: 0px -16px;
}
content: >
{% set count = states('sensor.persistent_notifications_count') %}
#### {{count}} Notification{{'' if count == '1' else 's'}}:
{{'\n'}}
{% for m in state_attr('sensor.persistent_notifications','notifications') if m %}
{{m.id}}
{{m.title}}
{{m.message}}{{'\n'}}
{% else %} Geen notificaties
{% endfor %}
taking out the need for my additional attribute. ! problem down, 1 left to go:
now, how to get those notifications dismissed correctly. above template deletes notifications using the dev tools and using a notification_id, either manually set ‘test123’ or the one set by the default.
It does Not delete individual notifications using the UI tray notification Dismiss button.
we can, I repeat, dismiss all, either programmatically using the new service, or the UI tray button,
I’ve gone a slightly different path. Working on @123’s method but using the following automation to “mirror” the persistant notifications to sensor.messages:
The thing here is to have the mode queued or parallel so that when the Dismiss All is called from the UI or via a service the automation repeats each removed trigger and keeps everything aligned - still need to test edge cases but so far holding up nicely.
One change I did make to 123’s template was on create, I check for the existence of a message with the same ID and delete the original first (this could be the way I had my config set up but for example I generate a persistent notification for unavailable devices and list them - if a another device becomes unavailable I re-trigger the notification on the same ID, the persistent notifications replace it but was ending up with duplicates in the mirror messages):
template:
- trigger:
- platform: event
event_type:
- message_create
- message_delete
- message_delete_all
sensor:
- name: Messages
state: "{{ now().timestamp() | timestamp_custom() }}"
attributes:
messages: >
{% set msgs = this.attributes.get('messages', []) %}
{% if trigger.event.event_type == 'message_create' %}
>>> {% if trigger.event.data.id is defined %} <<<--- ADDED THIS IF STATEMENT
{% set msgs = msgs | rejectattr('id', 'eq', trigger.event.data.id) | list %}
{% endif %}
{% set new = [{
"id": trigger.event.data.id | default('TS' ~ now().timestamp()),
"title": trigger.event.data.title | default(''),
"message": trigger.event.data.message | default(''),
"time": now().isoformat() }] %}
{{ (msgs + new) }}
{% elif trigger.event.event_type == 'message_delete' %}
{% if trigger.event.data.id is defined %}
{% set msgs = msgs | rejectattr('id', 'eq', trigger.event.data.id) | list %}
{% elif trigger.event.data.index is defined and trigger.event.data.index | is_number %}
{% set t = trigger.event.data.index | int(0) - 1 %}
{% if 0 <= t < msgs|count %}
{% set msgs = msgs | rejectattr('id', 'eq', msgs[t].id) | list %}
{% endif %}
{% endif %}
{{ msgs }}
{% else %}
{{ [] }}
{% endif %}
Still working on the front end display but rolling with something like this (POC currently and needs styling nicely to match my set up etc…):
type: markdown
content: |-
{%- if state_attr('sensor.messages','messages') | list | count == 0 %}
No Notifications
{%- else %}
{%- for item in state_attr('sensor.messages', 'messages') %}
{%- if not loop.first %}<hr> {% endif -%}
<table width="100%">
<tr>
<td width="30%"><font color='#03a9f4'>{{item.title}}</font></td>
<td>{{item.message}}</td>
</tr>
<tr>
<td></td>
<td>{{ item.time | as_datetime | relative_time }} ago</td>
</td>
</table>
{%- endfor %}
{%- endif %}
card_mod:
style: |
ha-card {
box-shadow: var(--sl-shadow);
}
EDIT: I’ve made the assumption that all persistent notifications have an ID, ones I manually raise do and assumed systems ones will, should I find a case that doesn’t the dismiss all wouldn’t work in this configuration I think
however, there is no dedicated trigger for dismiss_all, so I guess I have to keep that event trigger in the template? or would it also fire on dismiss_all… not sure what the effect would be there.
in your case, what happens when clicking the UI notification dismiss? does it actually decrease the number of the counter, and the list in the template?
also, on those triggers:
what do current and updated indicate? Ive seen them in the code, but they are not listed in the services, so I am a bit in the dark why/when we would use those
fear a bit that updated is also valid when a deleted action takes place, which would upset the template
You will get a remove for each notification you have when you dismiss_all. So 100 notifications will be 100 triggers. Make sure your automation is parallel
No, but set the automation to queued or parallel - the Dismiss All generates a trigger of dismiss for each Persistent Notification individually so it works.
Yes, I assume you mean in the popout persistent notification panel? The template sensor.messages (or whatever you’ve called it) is updated by the automation.
Not sure, not hit a case where I’ve seen these triggered yet - but I wrapped them up in the create (and modified the create to delete any notification/message with the same ID first so that everything stays in sync).
template sensors wont have this issue. Automations will. There’s a max number of parallel automations that can run at a time, the default is 10. If you use this in an automation, make the number large.
for now, besides some formatting of the markdown, I believe we’ve got the complete package:
count the number of active persistent notifications (sensor.persistent_notifications_count)
alert on notifying notifications (binary_sensor.persistent_notifications)
display list of notifications (attribute on sensor.persistent_notifications)
all updated on programmatic and manual creation/dismissal
working for core and manual notifications
dismiss_all service in core
no mirroring system required for ‘messages’, though people might like that and can follow what Mike does above with Taras’s first suggestion
very nice indeed
I’m reworking the template now. There’s a bunch of things that aren’t correct anymore in that template. Like all notifications via that trigger will have a notification_id