Heads up: 2023.6 longer has persistent notifications in states: what to do?

Now that most functionality is correct, there is one more thing ( there always is…):

Upon restart, the notification tray is empty, and in the former implementation of Pers. notifications, the system would no longer have ‘notifying’ notifications. However, the trigger template still shows the state that it was in before restart, as it is restoring per design.

That is ok in itself, maybe even better than the core Pers. Notifications, but it is no longer in sync.

Also clearing the notifications now does Not work, and the last state remains. Apparently the ids are no longer in the system, so the clear does not know what to clear?
That could be an issue.

Wonder what to do. Maybe add homeassistant start to the triggers for the template?

That would probably make it sync . I do like the ‘memory’ it now displays though , but don’t like we can not clear …

No, adding the homeassistant start trigger is not perfect either, it now errors on:

Template variable error: 'dict object' has no attribute 'notification' when rendering '{% set msgs = this.attributes.get('notifications', []) %} {% if trigger.update_type == 'added' %} {% set new = [{ "id": trigger.notification.notification_id, "title": trigger.notification.title, "message": trigger.notification.message, "created_at": trigger.notification.created_at.isoformat() }] %} {{ msgs + new }} {% else %} {{msgs | rejectattr('id', 'eq', trigger.notification.notification_id) | list }} {% endif %}'

so apparently even the [] in the getter does not help here

  - trigger:
      - platform: homeassistant
        event: start
      - platform: persistent_notification
        update_type:
          - added
          - removed
    sensor:

      - unique_id: persistent_notifications_overview
        device_class: timestamp
        state: >
          {{now()}}
        attributes:
          notifications: >
            {% set msgs = this.attributes.get('notifications', []) %}
            {% if trigger.update_type == 'added' %}
              {% set new = [{
                  "id": trigger.notification.notification_id,
                  "title": trigger.notification.title,
                  "message": trigger.notification.message,
                  "created_at": trigger.notification.created_at.isoformat() }] %}
              {{ msgs + new }}
            {% else %}
              {{msgs | rejectattr('id', 'eq', trigger.notification.notification_id) | list }}
            {% endif %}

Never restarted my test box this many times before testing this!!

Tried to get the template trigger method working for this scenario but also failed (was favoring this approach), so returned to the automation approach and have got it working.

alias: Persistent Notification Mirror
description: ""
trigger:
  - platform: homeassistant
    event: start
    id: start
  - platform: persistent_notification
    update_type:
      - added
      - current
      - updated
    id: added
  - platform: persistent_notification
    update_type:
      - removed
    id: removed
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id:
              - added
        sequence:
          - event: message_create
            event_data:
              id: "{{ trigger.notification.notification_id }}"
              title: "{{ trigger.notification.title }}"
              message: "{{ trigger.notification.message }}"
      - conditions:
          - condition: trigger
            id:
              - removed
        sequence:
          - event: message_delete
            event_data:
              id: |
                {{ trigger.notification.notification_id }}
      - conditions:
          - condition: trigger
            id:
              - start
        sequence:
          - event: message_delete_all
            event_data: {}
mode: queued
max: 30

On restart all previous mirrored notifications are cleared and then as they come in again are recreated. Supports the Dismiss All button on the slide out Persistent Notification panel.

This works well for me, as on a restart any Persistent Notifications I’ve raised via automation are recreated anyway (e.g. device offline).

Note: perhaps its just me and my config @Mariusthvdb; but I re-raise persistent notifications with the same ID multiple times e.g.

id: ntf_device
title: One device offline
message: light.office

then again when a second device goes off line

id: ntf_device
title: Two devices offline
message: light.office and switch.playroom

In this scenario the second message replaces the first (same ID) in the Persistent Notifications and also in my mirror - I think in your current configuration you may get two occurrences of ID ntf_devices in your sensor? (which could be fine for the way your config is set up)

As a side note, has anyone noticed that the notification bell icon counter is not nicely refreshing and often needs a whole page refresh?

template config

  - 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' %}
              {% set msgs = msgs | rejectattr('id', 'eq', trigger.event.data.id) | list %}
              {% 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' %}
              {% set msgs = msgs | rejectattr('id', 'eq', trigger.event.data.id) | list %}
              {{ msgs }}
            {% else %}
              {{ [] }}
            {% endif %}

For interest I have logged a bug for this. It appears if you restart the count is is being persisted unless you refresh the page - a small issue but a differing in behavior and potentially misleading following restart.

I think that is a frontend issue more than a core issue though, and yes that is new behavior. With more than the notification tray I fear, but there it is very obvious.

on the restart restore:
maybe I should add a clear notifications on Ha restart/stop.
it would be my first usage of

automation:
  trigger:
    - platform: homeassistant
      # Event can also be 'shutdown'
      event: start

so I have to ask if shutdown would also trigger on restart, which would be what Id need.

Btw, on the subject of that tray: ive always found it silly we can open that without having a single notification, only to have it show an empty half screen

You’ll have to test for your needs, but I couldn’t get the shutdown event to trigger on restart. The homeassistant.start event seems run before any notifications were getting generated so works for my needs.

thanks for the heads up, moved that issue to frontend now :slight_smile:

This is what i have now, and it works for me.

template:
  - trigger:
      - platform: persistent_notification
        update_type:
          - added
          - removed
        id: pn

      - platform: homeassistant
        event: shutdown
        id: shutdown

    sensor:
      - name: pn_messages
        state: "{{ now().timestamp() | timestamp_custom() }}"
        # state: "{{ state_attr('sensor.pn_messages', 'pn_ids') | length }}"   # not possible, also with 'this.attributes'    
        unique_id: 20230630060219
        attributes:
          pn_ids: >
            {% if trigger.id == 'pn' %}
              {% if trigger.notification.notification_id is defined %}
                {% set id = trigger.notification.notification_id %}
                {% set pn_ids = this.attributes.get('pn_ids', []) %}
                {% if trigger.update_type == 'added' %}
                  {% set new = [id] %}
                  {{ (pn_ids + new) | unique | list }}
                {% else %}                
                  {{ pn_ids | reject('equalto', id) | list }}
                {% endif %}
              {% endif %}
            {% elif trigger.id == 'shutdown' %}
              {{ [] }}
            {% endif %}

  - trigger:
      - platform: state
        entity_id: sensor.pn_messages
    sensor:
      - name: pn_count
        state: "{{ state_attr('sensor.pn_messages', 'pn_ids') | length }}"
        unique_id: 20230615210019

I need only a list for counting and testing of notifications, so a list with id’s is enough for me.
Creating/updating multiple notifications with the same id falsified the counter, so the unique filter.
Restarting HA deletes the notifications, but the attributes are restored, so the restart trigger to set an empty list.

What i can’t get to work ist the count as state or attribute, it seems it’s not possible to set this with values from the same sensor.
It’s also not possible to test for a notification that is created for the first time.
The trigger in a template is always faster than the same trigger in an automation, it always is false.

automation:
  - alias: persistent_notification_log
    id: '20230630190625'
    variables:
      pn_ids: "{{ state_attr('sensor.pn_messages', 'pn_ids') }}"
    initial_state: true
    mode: parallel
    trigger:
      - platform: persistent_notification
        update_type:
          - added
    # condition:
    #   - "{{ trigger.notification.notification_id not in pn_ids }}"    # always false
    action:
      - service: notify.pn_log
        data_template:
          message: >
            {{ now().strftime('%Y%m%d %H%M%S') }} 
            {{ trigger.notification.title }} /
            {{ trigger.notification.message }}

I’m open for improvements. :slightly_smiling_face:

1 Like

Need to test that a bit but I feel the count sensor works best a regular template and not at trigger .

Does here anyway.
Experimenting with the restart didn’t yet bring a solution as the trigger shutdown doesnt fire on restart….

update

I was so fixated on the restart event, I completely overlooked the fact I should not try to trigger off the restart/shutdown event, but simply use the start event…

  - trigger:
      - platform: homeassistant
        event: start
        id: start
      - platform: persistent_notification
        update_type:
          - added
          - removed
    sensor:

      - unique_id: persistent_notifications_overview
        device_class: timestamp
        state: >
          {{now()}}
        attributes:
          notifications: >
            {% set msgs = this.attributes.get('notifications', []) %}
            {% if trigger.update_type == 'added' %}
              {% set new = [{
                  "id": trigger.notification.notification_id,
                  "title": trigger.notification.title,
                  "message": trigger.notification.message,
                  "created_at": trigger.notification.created_at.isoformat() }] %}
              {{ msgs + new }}
            {% elif trigger.id == 'start' %}
              {{[]}}
            {% else %}
              {{msgs | rejectattr('id', 'eq', trigger.notification.notification_id) | list }}
            {% endif %}

makes it happen.
its a bit weird to see it go from a number, then restart, change to unavailable, then unknown, and then back to the number it had before (apparently from restore. Finally it is reset by the start event trigger ti an empty list, and causing the number And the binary to get the correct state. All perfect now.

excpet for the Frontend, which is still left from where it was before the restart

Scherm­afbeelding 2023-07-01 om 22.59.36

and requires a reload :wink: But thats a bug, and not to do with this template trigger

I linked your issue in the #beta channel on Discord, hoping it might be fixed before release

I’m not testing the July beta so I can’t test your latest example posted above (and answer my own question). What happens to this line when your Trigger-based Template Sensor is triggered by its first trigger (homeassistant start)?

{% if trigger.update_type == 'added' %}

Isn’t update_type exclusively a property of the second trigger (persistent_notification) and not the first trigger (homeassistant start)?

I would imagine it would cause an error message indicating the trigger object doesn’t have an update_type property.

I understand why you expect that and I gave it another check with a single notification being on.

There is nothing in the log though.

I’ll keep an eye on it, and maybe I could swap the if /elif, or even return the trigger.id for the core events, and only use those in the template

Or even simpler: split the 2 and have the clear action added to my other startup logic.
Ignore that, it is not simpler at all…

Thing is I found it neater/prefer to keep this together in a single bit of yaml and not spread it over the config…

  - trigger:
      - id: start
        platform: homeassistant
        event: start
      - id: notify
        platform: persistent_notification
        update_type:
          - added
          - removed
    sensor:

      - unique_id: persistent_notifications_overview
        device_class: timestamp
        state: >
          {{now()}}
        attributes:
          notifications: >
            {% set msgs = this.attributes.get('notifications', []) %}
            {% if trigger.id == 'notify' and trigger.update_type == 'added' %}
              {% set new = [{
                  "id": trigger.notification.notification_id,
                  "title": trigger.notification.title,
                  "message": trigger.notification.message,
                  "created_at": trigger.notification.created_at.isoformat() }] %}
              {{ msgs + new }}
            {% elif trigger.id == 'start' %}
              {{[]}}
            {% else %}
              {{msgs | rejectattr('id', 'eq', trigger.notification.notification_id) | list }}
            {% endif %}
1 Like

thx.

ws looking for the trigger syntax of the homeassistant_start event in a template, like

{% if trigger.event == 'homeassistant_start' %}

this isn’t correct, but I couldn’t find docs or examples how to do it correctly (and I mean without setting an id on that trigger).

You can also use the value of trigger.platform to determine which trigger occurred given that the first trigger’s platform is homeassistant and the second one’s is persistent_notification.

for now (although I didnt see an error in the first place) I changed the order, which should also mitigate any risk?

  - trigger:
      - platform: homeassistant
        event: start
        id: start
      - platform: persistent_notification
        update_type:
          - added
          - removed
    sensor:

      - unique_id: persistent_notifications_overview
        device_class: timestamp
        state: >
          {{now()}}
        attributes:
          notifications: >
            {% set msgs = this.attributes.get('notifications', []) %}
            {% if trigger.id == 'start' %}
              {{[]}}
            {% elif trigger.update_type == 'added' %}
              {% set new = [{
                  "id": trigger.notification.notification_id,
                  "title": trigger.notification.title,
                  "message": trigger.notification.message,
                  "created_at": trigger.notification.created_at.isoformat() }] %}
              {{ msgs + new }}
            {% else %}
              {{msgs|rejectattr('id','eq',trigger.notification.notification_id)|list}}
            {% endif %}

next, since I also like to have some insight in the historic development of these notifications (and didnt want to add another attribute ‘history’ as that would blow up the Db) I added a filing system:

sensor:

  - platform: file
    file_path: /config/logging/filed/filed_presence_notifications.txt
    name: Filed presence notifications

  - platform: file
    file_path: /config/logging/filed/filed_persistent_notifications.txt
    name: Filed persistent notifications
    value_template: >
      {% if value is not none %}
        {% if value|length < 255 %} {{value}}
        {% else %} Truncated: {{value|truncate(240,True, '')}}
        {% endif %}
      {% endif %}

notify:

  - name: filed_persistent_notifications
    platform: file
    filename: /config/logging/filed/filed_persistent_notifications.txt

automation:

  - alias: File persistent notifications
    id: file_persistent_notifications
    trigger:
      platform: persistent_notification
      update_type: added
    action:
      service: notify.filed_persistent_notifications
      data:
#         title: >
#           {% set time = trigger.notification.created_at.isoformat() %}
#           {{as_timestamp(time)|timestamp_custom}}:{{trigger.notification.title}}
        message: >
          {% set time = trigger.notification.created_at.isoformat() %}
          {{as_timestamp(time)|timestamp_custom}}: {{trigger.notification.title}},
          {{trigger.notification.message}},
          id: {{trigger.notification.notification_id}}

this will write all notifications to the file, so I can always check what happened when, and dont have to bother the recorder with that.

the format in that file is really ugly, but it gets the thing done

I have one outstanding niggle which I think will be a case of living with it. During start up I’ve noticed that the

Integration requires reconfiguration

persistent notification raised by HA is not being picked up by any of the methods implemented here. I would suspect its a timing issue that this is raised early on during the start up before either the template sensor or automation methods are ready. Other PN’s raised by HA during start up are coming through reinforcing my thoughts on timing.

If anyone has an idea on how to get around that I’d love to hear otherwise I think I’m ready for the release into my Production environment later this week!

In regard to clearing notifications, I currently have a python script that does it, is it true that would no longer work if i move off of 2023.5 as well? It sounds like it based upon all the trouble you guys are going through whilst I’m stuck on the +1 issue.

the python script worked using states, which no longer exist.

you can now use the dismiss_all core service which is/will be added in latest release

to dismiss all just use:

script:

 dismiss_all_persistent_notifications:
   alias: Clear All Persistent Notifications
   sequence:
     service: persistent_notification.dismiss_all

Sweet, looks like all that’s missing now is the incremental default IDs.

sorry, wrong topic…

Ive tried to see where we can fix this, unsuccessfully so though.

And yes, it is quite an issue, as during startup several important notifications are constructed we now miss out on. Not only the one you just mentioned, but also the related, and maybe even more important one below (as it truly notifies about an issue/bug, not so much a reconfig of an existing and proper integration)

btw, this one does not block restart, is not noted by the UI config checker, so is quite fundamental not to miss out on

Would you please care to write-up an issue on this? Maybe Bdraco has ways to figure out in core how to solve this rather annoying result of the migration to state less notifications…

Worst excuse ever. Basic principle is to first deprecate something way before removing it. Giving warnings to users upon invocation/use that this feature will not be working in e.g. 3 months or so. Then you will receive a lot of feedback from general users without forcing them into glitchy beta-releases.

General users would like a stable (non-beta) environment that just works. And for the same reason, breaking changes that definitely could wait should be announced by deprecation warnings way before taking effect.

Workarounds using templates and input booleans etc works reasonably well for discrete (and few) well-known things. Like taking out the trash, or something that is regular as coming from a calendar.

But the real usage for this notification service is: something happened, you create a notification of whatever happened, and the user needs to take care of it and then dismiss it. And if more things happens, then they are simply pushed to a list of events to take care of. Doing this with input texts, input booleans and template sensors is possible but not feasible.

The remark that it was in fact not persistent (despite it’s name) is also not an excuse for removing it. Better to implement it to become persistent. But as with the “last changed” and “last updated” attributes, the developers of home assistant seems to prefer not saving stuff for some unexplained reason.

3 Likes