Active_notification_count parsing for Android; keeping track of current notifications

I wanted to keep track of the current notifications on my Android phone. The fact is that the content of the sensor sensor.myphone_active_notification_count is really messy. So I created a template that I put as an attribute in a template entity, that gives that information in a filtered and well structured way.

So the result will look like this:

{
  "io.homeassistant.companion.android": [
    {
      "bigText": "Back in 20 minutes if swiped",
      "text": "Back in 20 minutes if swiped",
      "title": "The clothes in the washing machine are ready for drying",
      "channel_id": "rappels",
      "group_id": "group_The clothes in the washing machine are ready for drying",
      "is_clearable": true,
      "is_ongoing": false,
      "post_time": "2025-04-12 12:26:47",
      "summaryText": "The clothes in the washing machine are ready for drying"
    },
    {
      "bigText": "Back in 10 minutes if swiped",
      "text": "Back in 10 minutes if swiped",
      "title": "Take your pill",
      "channel_id": "rappels",
      "group_id": "group_Take your pill",
      "is_clearable": true,
      "is_ongoing": false,
      "post_time": "2025-04-12 12:27:49",
      "summaryText": "Take your pill"
    }
  ],
  "de.danoeh.antennapod": [
    {
      "text": "Rattrapage du 15 nov. 2024 : La vitesse des vinyles, et la vraisemblance des séries policières",
      "title": "Moteur de recherche",
      "category": "transport",
      "channel_id": "playing",
      "is_clearable": false,
      "is_ongoing": false,
      "post_time": "2025-04-12 11:26:24"
    },
    {
      "channel_id": "cast_media_notification",
      "group_id": "ranker_group",
      "is_clearable": false,
      "is_ongoing": false,
      "post_time": "2025-04-12 11:09:49"
    }
  ],
  "org.fossify.messages": [
    {
      "text": "Texto",
      "title": "Doe John",
      "category": "msg",
      "channel_id": "fossify_messages",
      "is_clearable": true,
      "is_ongoing": false,
      "post_time": "2025-04-12 11:27:36"
    }
  ],
  "org.thoughtcrime.securesms": [
    {
      "text": "Signal 2",
      "title": "Doe John",
      "category": "msg",
      "channel_id": "messages_2 : 161",
      "group_id": "messages",
      "is_clearable": true,
      "is_ongoing": false,
      "post_time": "2025-04-12 12:22:45"
    }
  ]
}

While there is always room for customization, but so far the result pleases me. Juste replace with your actual sensor within the line:

{% set raw_attributes = states.sensor.myphone_active_notification_count.attributes %}

Here is the template:

{# Home Assistant Jinja template — Parse Android notifications and group by app, with fusion logic #}

{# Step 1: Define useful suffixes and prefixes for key parsing #}
{% set suffix_fields = ['category', 'channel_id', 'group_id', 'is_clearable', 'is_ongoing', 'post_time'] %}
{% set prefix_fields = ['text', 'bigText', 'title', 'summaryText'] %}

{# Step 2: Extract and reformat data into intermediate nested structure #}
{% set raw_attributes = states.sensor.myphone_active_notification_count.attributes %}
{% set parsed = namespace(notifications={}) %}

{% for key, value in raw_attributes.items() %}
  {% if value in [none, '', 'null'] %}
    {% continue %}
  {% endif %}

  {% if key.startswith('android.') %}
    {% set parts = key[8:].split('_') %}
    {% if parts[0] in prefix_fields %}
      {% set parsed.notifications = combine(parsed.notifications, {parts[2]: {parts[1]: {parts[0]: value}}}, recursive=True) %}
    {% endif %}
  {% else %}
    {% set parts = key.split('_', 2) %}
    {% if parts[2] in suffix_fields %}
      {% if parts[2] == 'post_time' %}
        {% set value = (value // 1000) | timestamp_custom %}
      {% endif %}
      {% set parsed.notifications = combine(parsed.notifications, {parts[1]: {parts[0]: {parts[2]: value}}}, recursive=True) %}
    {% endif %}
  {% endif %}
{% endfor %}

{# Step 3: Convert dictionary into a list without the Android notification IDs #}
{% set app_list = namespace(notifs=[]) %}
{% for id in parsed.notifications %}
  {% set app_list.notifs = app_list.notifs + [parsed.notifications[id]] %}
{% endfor %}

{# Step 4: Merge Home Assistant notifications when summaryText matches title or text #}
{% set output = namespace(grouped={}, current={}, merged_indexes=[]) %}

{% for item in app_list.notifs %}
{% set outer = loop %}
{% if loop.index in output.merged_indexes %}
  {% continue %}
{% endif %}

{% set app = item.keys() | list | first %}
{% set output.current = item[app] %}

{% if app == 'io.homeassistant.companion.android' %}
  {% if 'summaryText' in output.current %}
    {% set ref_values = [output.current['summaryText']] %}
  {% else %}
    {% set ref_values = [output.current.get('title', ''), output.current.get('text', '')] %}
  {% endif %}
  {% if not outer.last %}
    {% for index in range(outer.index0 + 1, app_list.notifs | count) %}
      {% if not app in app_list.notifs[index] %}
        {% continue %}
      {% endif %}
      {% set other = app_list.notifs[index][app] %}

  {% if 'summaryText' in other %}
    {% set compare_values = [other['summaryText']] %}
  {% else %}
    {% set compare_values = [other.get('title', ''), other.get('text', '')] %}
  {% endif %}
  {% if compare_values[0] in ref_values or ref_values[0] in compare_values %}
    {% set output.merged_indexes = output.merged_indexes + [outer.index + loop.index] %}
    {% set output.current = output.current | combine(other) %}
  {% endif %}
{% endfor %}
{% endif %}
{% endif %}

{% if app in output.grouped %}
    {% set output.grouped = output.grouped | combine({ app: output.grouped[app] + [output.current] }) %}
  {% else %}
    {% set output.grouped = output.grouped | combine({ app: [output.current] }) %}
  {% endif %}
{% endfor %}

{{ output.grouped }}

Let me know what you think.