How to forward all notifications to notify.file

Thanks for documenting this. I’m just going to add a couple of things for anyone else who is trying this:

  1. It seems that you have to entirely restart Home Assistant, rather than just reload YAML, if you make a change to the “notify” in configuration.yaml (as of HomeAssistant 2024.1.6)
  2. Once it’s working, it will be shown as a service via the scripting UI
  3. It will automatically create the file if it doesn’t exist
  4. I tried testing this in Developer Tools/Services, and for the life of me couldn’t get it to work. It worked fine within a script, but I got the error “Failed to call service notify.notify-log-to-file. Service notify.notify-log-to-file does not match format . for dictionary value @ data[‘sequence’][0][‘service’]. Got ‘notify.notify-log-to-file’”
service: notify.notify-log-to-file
data:
  message: "This is a test of the notification"

Maybe I’ve just got a dumb YAML error in there

change to notify.notify_log_to_file probably

1 Like

Old but still relevant!

I would have liked to know what the default path is and how to change it to something else.
By experiment (in HA version 2024.2.2) I found

  • the default path is /CONFIG/
  • you cannot include a path in the filename – log_files/logtest.txt does not work, with or without a leading slash
  • file_path: log_files/ combined with filename:logtest.txt does not work, with or without a leading slash

So, can it be done ? If so, how?

The configuration path depends on your installation:

  • Docker: container configuration dependent
  • Homeassistant OS: /config
  • Homeassistant Core: ~/.homeassistant

You can check the path in System information (Settings/System/Repairs → Context Menu)

Source: Configuration.yaml - Home Assistant

1 Like

This looks really useful, and may help with something I have in my head (to log all notification sent to my phone into a file)

My question: is there a way to do so using notify.file but putting most recent entries at the top? and maybe without the header?

from the top of my head, but I believe that is already the case if you use smoothing like this:

  - type: custom:hui-element
    card_type: markdown
    card_mod:
      style: |
        ha-card.type-markdown {
          box-shadow: none;
          margin: 0px -16px -16px -16px;
        }
    content: >
      ## Laatste Repairs

      {{states('sensor.filed_repairs')}}

it shows the last entries?

thanks - a couple of things for me to investigate there (as I am unfamiliar) - smoothing and markdown cards (and maybe custom: hui-element).

Will come back (hopefully next week) once I have tried this out.

So I have an automation (and file notification ) set up to copy all notifications to my phone to a file - based on yours @Mariusthvdb - thank you. This saves me duplicating all the individual automation notifications.

Rationale: phone notifications tend to be useful for info and checking automation triggers/conditions but are ephemeral (not least because there are many from other sources also), so this will allow me to check back.

This is the code so far:

alias: "-851 Copy phone notifications to file"
description: ""
trigger:
  - platform: event
    event_type: call_service
    event_data:
      domain: notify
      service: mobile_app_pixel_6a
condition: []
action:
  - service: notify.phone_notifications
    metadata: {}
    data_template:
      message: " {% set message = trigger.event.data.service_data.message %}, {{ message }} "
mode: single

The problem I am having is that I am only seeing the notification message, and not the title.

I do not quite understand the data_template section; can I just add {{title}} somewhere? or do I need to concatenate (somehow?) 2 messages, one referring to service_data.message and the other service_data.title - there seem to be too many items with very similar names and I am afraid I am unsure which refers to what. I have some other templates (based on copies from others) and have read some of the docs but still find them a mystery at times.

Any constructive suggestion is welcome - thanks.

Then I can look at seeing if we can reverse the order somehow after checking out the smoothing etc.

Meanwhile - I have an automation running at 2359 that renames the phonemsgs.txt file by adding the date, ready for a new one the next day. It calls a shell command in configuration.yaml.

shell_command:
  rename_phone_notifications: "mv -n /share/phonemsgs.txt {{ (as_timestamp(now(),0) - (60*60*24)) | timestamp_custom('/share/phonemsgs_%y_%m_%d.txt') }}"

This was based on someone else’s work (I claim no credit) but I cannot recall who, sorry.

It might help with clearing/resetting a log/file, or just building a series per day.
Another shell command could be used presumably to clear old ones.

no, no jut like that. you’ve got to parse the service data for the title, just like you do for the message, so {{trigger.event.data.service_data.title}} most likely

Here is the working code, now storing title and message of phone notifications (on separate lines) in a text file:

alias: "-851 Copy phone notifications to file"
description: ""
trigger:
  - platform: event
    event_type: call_service
    event_data:
      domain: notify
      service: mobile_app_pixel_6a
condition: []
action:
  - service: notify.phone_notifications
    metadata: {}
    data_template:
      message: |2-
         {% set message = trigger.event.data.service_data.title %}  
         {% set message = message+'\n-- '+ trigger.event.data.service_data.message+'\n' %} {{ message }} 
mode: single

This gives the following:

Home Assistant notifications (Log started: 2024-03-26T16:18:43.827285+00:00)
--------------------------------------------------------------------------------
test-title
-- test-message
test-title
-- test-message
test-title
-- test-message

(with test data)

I am sure there may be better/prettier ways but this is a start (thanks again to @Mariusthvdb)

I do not intend to display this info in HA but to copy elsewhere and make it available remotely, as I do not have Nabu Casa/remote access and yet I am interested in the messages that come through when away from home. Hence I am unsure the smoothing/markdown card idea will be applicable.

Consequently I may have to process it remotely to reverse the order (and maybe turn it into html/add some simple rich text formatting for easier reading).

In case others might find it useful, I have added 2 more shell commands to strip the header from the notify file, and then reverse it (I also added the date/time)

The result generates a reverse log file of notifications to my phone as per my original objective (which can then be copied remotely). Credit and thanks to @vbphil from here

  strip_notify_header: "sed -n '3,$p' /share/phonemsgs.txt > /share/phone2.txt"
  reverse_phonemsgs: "tac /share/phone2.txt > /share/phone3.txt"

Which turns:

Home Assistant notifications (Log started: 2024-03-26T16:18:43.827285+00:00)
--------------------------------------------------------------------------------

test-title2--test-message2
test-title3--test-message3
test-title4--test-message4
16:41 Tue 26-Mar,test-title4--test-message4
16:42 Tue 26-Mar,test-title5--test-message5
16:50 Tue 26-Mar,test-title6--test-message6
16:50 Tue 26-Mar,test-title7--test-message7
16:57 Tue 26-Mar,test-title 8--test-message 8

into

16:57 Tue 26-Mar,test-title 8--test-message 8
16:50 Tue 26-Mar,test-title7--test-message7
16:50 Tue 26-Mar,test-title6--test-message6
16:42 Tue 26-Mar,test-title5--test-message5
16:41 Tue 26-Mar,test-title4--test-message4
test-title4--test-message4
test-title3--test-message3
test-title2--test-message2

This is a demonstration of principle so far - it needs a little tidying in terms of filenames etc.
Those commands can be added to the automation above and then mode changed to queued in case it is called again during the file operations.

If I have missed something obvious I am open to suggestions.

2 Likes

Thanks, this was indeed the problem. In the configuration.yaml I have

notify:
  - platform: file
    name: notify-log-to-file
    filename: notification-log.csv
    timestamp: True

But it converts those hyphens into underscores just as it would have if I had called it “notify log to file”

crosspost from Notify.send_message in 2024.6 - #8 by Mariusthvdb

because the platform: file notify service has been migrated to the UI:

where we had this before:

      service: notify.filed_notifications
      data:
        message: >
          {% set message = trigger.event.data.service_data.message %}
          {% set service = trigger.event.data.service %}
            {{now().strftime('%d %b: %X')}} - {{service}}: {{message}}

we need to replace it with this now:

      service: notify.send_message
      target:
        entity_id: notify.filed_notifications
      data:
        message: >
          {% set message = trigger.event.data.service_data.message %}
          {% set service = trigger.event.data.service %}
            {{now().strftime('%d %b: %X')}} - {{service}}: {{message}}

thats all :wink:

note the platform: file sensor entities haver also migrated, and that is a bit of an issue. The value_templates and path used in those yaml configs are not visible in the UI, nor can the be edited.

(you can confirm them in the storage the core.config_entries:)

      {
        "data": {
          "value_template": "{% if value is not none %}\n  {% if value|length < 255 %} {{value}}\n  {% else %} Truncated: {{value|truncate(240,True, '')}}\n  {% endif %}\n{% endif %}\n",
          "platform": "sensor",
          "file_path": "/config/logging/filed/filed_notifications.txt",
          "name": "Filed notifications"
        },
        "disabled_by": null,
        "domain": "file",
        "entry_id": "c4ac56c0190d80309c023f4a98320c05",
        "minor_version": 1,
        "options": {},
        "pref_disable_new_entities": false,
        "pref_disable_polling": false,
        "source": "import",
        "title": "Filed notifications",
        "unique_id": null,
        "version": 1
      },

will add the solution tick to this, as it actually answers my own OP. not to pat myself on the shoulders here, but for community sanity, and others to find the solution.

1 Like

Just wondering if this is the correct way.
The above solution works for the service notify.notify or notify.my_phone_name

But I want to file every message sent with the service notify.sent_message.
To write this to a file, you have to use notify.sent_message. I missed that, within less than 4 hours after activating the automation, I ended up with a non responsive system with no drive-space and a 32gb notification file. That’s caused by the recursive action. Stupid me.

Now, I added a condition to the same automation, but I’m not sure if I have it right. And instead of trying, now I’m asking first.

  - alias: Forward notifications to txt
    initial_state: 'on'
    trigger:
      - platform: event
        event_type: call_service
        event_data:
          domain: notify
          service: send_message       # this was 'notify' in the first message in this topic
    condition: not
    conditions:
      - condition: event
        event_type: call_service
        event_data:
          domain: notify
          service: send_message
          entity_id: notify.filed_notifications   # to exclude itself
    action:
      - service: notify.send_message
        target:
          entity_id: notify.filed_notifications
        data:
          message: >
            {% set message = trigger.event.data.service_data.message %}
            {% set service = trigger.event.data.service %}
              '{{ now().strftime("%Y-%m-%d %H:%M.%S") }}; {{service}}; {{message}}'
    mode: queued

why not just write that to a script and call the script in the automations that have the send_message service. so you have a send and file service in those always.

or do something ike this:

  - id: forward_notifications_to_filed_notifications
    mode: queued
    trigger:
      platform: event
      event_type: call_service
      event_data:
        domain: notify
    condition:
      >
       {{trigger.event.data.service in ['system','notify']}}
    action:
      service: notify.send_message
      target:
        entity_id: notify.filed_notifications
      data:
        message: >
          {% set message = trigger.event.data.service_data.message %}
          {% set service = trigger.event.data.service %}
            {{now().strftime('%d %b: %X')}} - {{service}}: {{message}}

What is this condition doing exactly?
How is that excluding the send_message in the action part ?

no, it is Selecting the services you want to use, to pass the condition

Okay, but in that case, I want
ALL notify.send_messages
EXCEPT when target = notify.filed_notifications
(to avoid recursion)

Isn’t that what I created in my example ?

or is it something like this ?

    condition: not
      >
       {{trigger.event.data.entity_id in ['notify.filed_notifications']}}

Yes, or add the not to the template