PostNL Integration

Nope

@ptnijssen or @arjenbos (owner of the package on gridhub) have to look into this

I had a look at DPD a while back, but they dont have a json response only a html response. So you probably have to do a lot of filtering to get data out neatly.

See also support for letters? (not a issue, but a question). Ā· Issue #8 Ā· arjenbos/ha-postnl Ā· GitHub

Letters is not available currently. Best to reply on github I suppose.

Thanks for the DHL with cookie explanation, it works perfectly.

After a few hours of crafting I made the following cards based on car entities.

You can choose between separate cards for PostNL and DHL. Let packages be those that are on their way and packages up to and including 3 days that have already been delivered. You can easily change this yourself in the auto-entities config.

And then a combined card of both. That then also puts in brackets who the deliverer is.

Code PostNL:

type: custom:auto-entities
card:
  type: entities
  title: PostNL Zendingen
filter:
  template: >
    {% set onderweg_pakketjes = state_attr('sensor.postnl_delivery', 'enroute')
    or [] %} {% set afgeleverd_pakketjes = state_attr('sensor.postnl_delivery',
    'delivered') or [] %} {% set onderweg = namespace(list=[]) %} {% set
    recent_afgeleverd = namespace(list=[]) %}

    {# Onderweg pakketten #} {% for pakket in onderweg_pakketjes %}
      {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
      {% set barcode = pakket.key %}
      {% set nette_status = pakket.status_message | default('Status onbekend') %}
      {% set tijd_raw = pakket.planned_from %}
      {% if tijd_raw %}
        {% set tijd = as_timestamp(tijd_raw) | timestamp_custom('%d-%m-%Y %H:%M') %}
      {% else %}
        {% set tijd = 'Onbekend' %}
      {% endif %}
      {% set row = {
        'type': 'custom:template-entity-row',
        'entity': 'sensor.postnl_delivery',
        'name': naam ~ ' - ' ~ barcode,
        'state': nette_status,
        'secondary': 'Verwacht: ' ~ tijd,
        'icon': 'mdi:truck-delivery'
      } %}
      {% set onderweg.list = onderweg.list + [row] %}
    {% endfor %}

    {# Recent afgeleverd pakketten (binnen 3 dagen) #} {% for pakket in
    afgeleverd_pakketjes %}
      {% set tijd_raw = pakket.delivery_date %}
      {% if tijd_raw %}
        {% set tijd_ts = as_timestamp(tijd_raw) %}
        {% set nu = now().timestamp() %}
        {% set dagen_verschil = (nu - tijd_ts) / 86400 %}
      {% else %}
        {% set dagen_verschil = 999 %}
      {% endif %}
      {% if dagen_verschil <= 3 %}
        {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
        {% set barcode = pakket.key %}
        {% set nette_status = pakket.status_message | default('Status onbekend') %}
        {% set tijd = tijd_ts | timestamp_custom('%d-%m-%Y %H:%M') %}
        {% set row = {
          'type': 'custom:template-entity-row',
          'entity': 'sensor.postnl_delivery',
          'name': naam ~ ' - ' ~ barcode,
          'state': nette_status,
          'secondary': 'Bezorgd op: ' ~ tijd,
          'icon': 'mdi:package-variant-closed'
        } %}
        {% set recent_afgeleverd.list = recent_afgeleverd.list + [row] %}
      {% endif %}
    {% endfor %}

    [
      {% if onderweg.list | count > 0 %}
        {
          "type": "section",
          "label": "šŸ“¦ Onderweg"
        },
        {{ onderweg.list | join(',') }},
      {% endif %}
      {% if recent_afgeleverd.list | count > 0 %}
        {
          "type": "section",
          "label": "āœ… Recent afgeleverd"
        },
        {{ recent_afgeleverd.list | join(',') }}
      {% endif %}
    ]
show_empty: true

Code DHL:

type: custom:auto-entities
card:
  type: entities
  title: DHL Zendingen
filter:
  template: >
    {% set pakketjes = state_attr('sensor.dhl_packages', 'parcels') or [] %} {%
    set onderweg = namespace(list=[]) %} {% set recent_afgeleverd =
    namespace(list=[]) %} {% for pakket in pakketjes %}
      {% set status = pakket.status | lower %}
      {% set tijd_raw = pakket.receivingTimeIndication.start if pakket.receivingTimeIndication.start is defined else pakket.receivingTimeIndication.moment %}
      {% if tijd_raw %}
        {% set tijd = as_timestamp(tijd_raw) | timestamp_custom('%d-%m-%Y %H:%M') %}
      {% else %}
        {% set tijd = 'Onbekend' %}
      {% endif %}
      {% set naam = pakket.sender.name if pakket.sender.name else 'Onbekende afzender' %}
      {% set barcode = pakket.barcode %}
      {% set nette_status = pakket.status | replace('_', ' ') | lower() | capitalize() %}
      {% set row = {
        'type': 'custom:template-entity-row',
        'entity': 'sensor.dhl_packages',
        'name': naam ~ ' - ' ~ barcode,
        'state': nette_status,
        'secondary': 'Bezorgtijd: ' ~ tijd,
        'icon': 'mdi:truck-delivery'
      } %}
      
      {% if 'delivered' not in status %}
        {% set onderweg.list = onderweg.list + [row] %}
      {% else %}
        {% if pakket.receivedDaysAgo is not none and pakket.receivedDaysAgo <= 3 %}
          {% set recent_afgeleverd.list = recent_afgeleverd.list + [row] %}
        {% endif %}
      {% endif %}
    {% endfor %} [
      {% if onderweg.list | count > 0 %}
        {
          "type": "section",
          "label": "šŸ“¦ Onderweg"
        },
        {{ onderweg.list | join(',') }},
      {% endif %}
      {% if recent_afgeleverd.list | count > 0 %}
        {
          "type": "section",
          "label": "āœ… Recent afgeleverd"
        },
        {{ recent_afgeleverd.list | join(',') }}
      {% endif %}
    ]
show_empty: true

Code gecombineerd:

type: custom:auto-entities
card:
  type: entities
  title: Pakketjes
filter:
  template: >
    {# DHL ophalen #} {% set dhl_pakketjes = state_attr('sensor.dhl_packages',
    'parcels') or [] %} {% set dhl_onderweg = namespace(list=[]) %} {% set
    dhl_recent_afgeleverd = namespace(list=[]) %}

    {% for pakket in dhl_pakketjes %}
      {% set status = pakket.status | lower %}
      {% set tijd_raw = pakket.receivingTimeIndication.start if pakket.receivingTimeIndication.start is defined else pakket.receivingTimeIndication.moment %}
      {% if tijd_raw %}
        {% set tijd = as_timestamp(tijd_raw) | timestamp_custom('%d-%m-%Y %H:%M') %}
      {% else %}
        {% set tijd = 'Onbekend' %}
      {% endif %}
      {% set naam = pakket.sender.name if pakket.sender.name else 'Onbekende afzender' %}
      {% set barcode = pakket.barcode %}
      {% set nette_status = pakket.status | replace('_', ' ') | lower() | capitalize() %}
      {% set row = {
        'type': 'custom:template-entity-row',
        'entity': 'sensor.dhl_packages',
        'name': '[DHL] ' ~ naam ~ ' - ' ~ barcode,
        'state': nette_status,
        'secondary': 'Bezorgtijd: ' ~ tijd,
        'icon': 'mdi:truck-delivery'
      } %}

      {% if 'delivered' not in status %}
        {% set dhl_onderweg.list = dhl_onderweg.list + [row] %}
      {% else %}
        {% if pakket.receivedDaysAgo is not none and pakket.receivedDaysAgo <= 3 %}
          {% set dhl_recent_afgeleverd.list = dhl_recent_afgeleverd.list + [row] %}
        {% endif %}
      {% endif %}
    {% endfor %}

    {# PostNL ophalen #} {% set postnl_enroute =
    state_attr('sensor.postnl_delivery', 'enroute') or [] %} {% set
    postnl_delivered = state_attr('sensor.postnl_delivery', 'delivered') or []
    %} {% set postnl_onderweg = namespace(list=[]) %} {% set
    postnl_recent_afgeleverd = namespace(list=[]) %}

    {# PostNL onderweg pakketten #} {% for pakket in postnl_enroute %}
      {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
      {% set barcode = pakket.key %}
      {% set nette_status = pakket.status_message | default('Status onbekend') %}
      {% set tijd_raw = pakket.planned_from %}
      {% if tijd_raw %}
        {% set tijd = as_timestamp(tijd_raw) | timestamp_custom('%d-%m-%Y %H:%M') %}
      {% else %}
        {% set tijd = 'Onbekend' %}
      {% endif %}
      {% set row = {
        'type': 'custom:template-entity-row',
        'entity': 'sensor.postnl_delivery',
        'name': '[PostNL] ' ~ naam ~ ' - ' ~ barcode,
        'state': nette_status,
        'secondary': 'Verwacht: ' ~ tijd,
        'icon': 'mdi:truck-delivery'
      } %}
      {% set postnl_onderweg.list = postnl_onderweg.list + [row] %}
    {% endfor %}

    {# PostNL recent afgeleverd pakketten (max 3 dagen) #} {% for pakket in
    postnl_delivered %}
      {% set tijd_raw = pakket.delivery_date %}
      {% if tijd_raw %}
        {% set tijd_ts = as_timestamp(tijd_raw) %}
        {% set nu = now().timestamp() %}
        {% set dagen_verschil = (nu - tijd_ts) / 86400 %}
      {% else %}
        {% set dagen_verschil = 999 %}
      {% endif %}
      {% if dagen_verschil <= 3 %}
        {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
        {% set barcode = pakket.key %}
        {% set nette_status = pakket.status_message | default('Status onbekend') %}
        {% set tijd = tijd_ts | timestamp_custom('%d-%m-%Y %H:%M') %}
        {% set row = {
          'type': 'custom:template-entity-row',
          'entity': 'sensor.postnl_delivery',
          'name': '[PostNL] ' ~ naam ~ ' - ' ~ barcode,
          'state': nette_status,
          'secondary': 'Bezorgd op: ' ~ tijd,
          'icon': 'mdi:package-variant-closed'
        } %}
        {% set postnl_recent_afgeleverd.list = postnl_recent_afgeleverd.list + [row] %}
      {% endif %}
    {% endfor %}

    {# Eindlijst bouwen #} [
      {% if (dhl_onderweg.list | count > 0) or (postnl_onderweg.list | count > 0) %}
        {
          "type": "section",
          "label": "šŸ“¦ Onderweg"
        },
        {{ dhl_onderweg.list | join(',') }},
        {{ postnl_onderweg.list | join(',') }},
      {% endif %}
      {% if (dhl_recent_afgeleverd.list | count > 0) or (postnl_recent_afgeleverd.list | count > 0) %}
        {
          "type": "section",
          "label": "āœ… Recent afgeleverd"
        },
        {{ dhl_recent_afgeleverd.list | join(',') }},
        {{ postnl_recent_afgeleverd.list | join(',') }}
      {% endif %}
    ]
show_empty: true
grid_options:
  columns: full
2 Likes

@rdekruyf Very nice, thanks for sharing the code.
I changed the text DHL / PostNL with icons phu:dhl and phu:postnl.
Do you know how to color the icons and how to sort data by date ?

1 Like

I’ve adjusted it a little since it was giving me errors on the postnl sensor and the collected at parcelshop werent tagged as deliverd:

type: custom:auto-entities
card:
  type: entities
  title: Pakketjes
filter:
  template: >
    {# DHL ophalen #}
    {% set dhl_pakketjes = state_attr('sensor.dhl_packages', 'parcels') or [] %}
    {% set dhl_onderweg = namespace(list=[]) %}
    {% set dhl_recent_afgeleverd = namespace(list=[]) %}

    {% for pakket in dhl_pakketjes %}
      {% set status = pakket.status | lower %}
      {% set tijd_raw = pakket.receivingTimeIndication.start if pakket.receivingTimeIndication.start is defined else pakket.receivingTimeIndication.moment %}
      {% set tijd = tijd_raw | as_timestamp | timestamp_custom('%d-%m-%Y %H:%M') if tijd_raw else 'Onbekend' %}
      {% set dagen_verschil = ((now().timestamp() - tijd_raw | as_timestamp) / 86400) if tijd_raw else 999 %}
      {% if dagen_verschil <= 3 %}
        {% set naam = pakket.sender.name if pakket.sender.name else 'Onbekende afzender' %}
        {% set barcode = pakket.barcode %}
        {% set nette_status = pakket.status | replace('_', ' ') | lower() | capitalize() %}
        {% set row = {
          'type': 'custom:template-entity-row',
          'entity': 'sensor.dhl_packages',
          'name': '[DHL] ' ~ naam ~ ' - ' ~ barcode,
          'state': nette_status,
          'secondary': 'Bezorgtijd: ' ~ tijd,
          'icon': 'mdi:truck-delivery'
        } %}

        {% if 'delivered' in status or 'collected' in status %}
          {% set dhl_recent_afgeleverd.list = dhl_recent_afgeleverd.list + [row] %}
        {% else %}
          {% set dhl_onderweg.list = dhl_onderweg.list + [row] %}
        {% endif %}
      {% endif %}
    {% endfor %}

    {# PostNL ophalen #}
    {% set postnl_enroute = state_attr('sensor.postnl_delivery', 'enroute') or [] %}
    {% set postnl_delivered = state_attr('sensor.postnl_delivery', 'delivered') or [] %}
    {% set postnl_onderweg = namespace(list=[]) %}
    {% set postnl_recent_afgeleverd = namespace(list=[]) %}

    {# PostNL onderweg pakketten #}
    {% for pakket in postnl_enroute %}
      {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
      {% set barcode = pakket.key %}
      {% set nette_status = pakket.status_message | default('Status onbekend') %}
      {% set tijd_raw = pakket.planned_from %}
      {% set tijd = tijd_raw | as_timestamp | timestamp_custom('%d-%m-%Y %H:%M') if tijd_raw else 'Onbekend' %}
      {% set row = {
        'type': 'custom:template-entity-row',
        'entity': 'sensor.postnl_delivery',
        'name': '[PostNL] ' ~ naam ~ ' - ' ~ barcode,
        'state': nette_status,
        'secondary': 'Verwacht: ' ~ tijd,
        'icon': 'mdi:truck-delivery'
      } %}
      {% if 'parcelshop' in nette_status or 'collected' in nette_status %}
        {% set postnl_recent_afgeleverd.list = postnl_recent_afgeleverd.list + [row] %}
      {% else %}
        {% set postnl_onderweg.list = postnl_onderweg.list + [row] %}
      {% endif %}
    {% endfor %}

    {# PostNL recent afgeleverd pakketten (max 3 dagen) #}
    {% for pakket in postnl_delivered %}
      {% set tijd_raw = pakket.delivery_date %}
      {% set dagen_verschil = ((now().timestamp() - tijd_raw | as_timestamp) / 86400) if tijd_raw else 999 %}
      {% if dagen_verschil <= 3 %}
        {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
        {% set barcode = pakket.key %}
        {% set nette_status = pakket.status_message | default('Status onbekend') %}
        {% set tijd = tijd_raw | as_timestamp | timestamp_custom('%d-%m-%Y %H:%M') %}
        {% set row = {
          'type': 'custom:template-entity-row',
          'entity': 'sensor.postnl_delivery',
          'name': '[PostNL] ' ~ naam ~ ' - ' ~ barcode,
          'state': nette_status,
          'secondary': 'Bezorgd op: ' ~ tijd,
          'icon': 'mdi:package-variant-closed'
        } %}
        {% set postnl_recent_afgeleverd.list = postnl_recent_afgeleverd.list + [row] %}
      {% endif %}
    {% endfor %}

    {# Eindlijst bouwen #}
    [
      {% if dhl_onderweg.list | count > 0 or postnl_onderweg.list | count > 0 %}
        {
          "type": "section",
          "label": "šŸ“¦ Onderweg"
        },
        {{ dhl_onderweg.list | join(',') }},
        {{ postnl_onderweg.list | join(',') }}
      {% endif %}
      {% if dhl_recent_afgeleverd.list | count > 0 or postnl_recent_afgeleverd.list | count > 0 %}
        {
          "type": "section",
          "label": "āœ… Recent afgeleverd"
        },
        {{ dhl_recent_afgeleverd.list | join(',') }},
        {{ postnl_recent_afgeleverd.list | join(',') }}
      {% endif %}
    ]
show_empty: true
grid_options:
  columns: full

2 Likes

Thanks a lot for reviving this awesome integration! It’s working great!
Hope letters get added back too!

Made some further changes to implement it in my Sections dashboard:

Translated the DHL statusses to Dutch and fixed some of the really long statusses of PostNL.
Also made the packages clickable which redirects to the track&trace website of PostNL and DHL respectively.

The heading shows 2 entities: one counter for PostNL and one for DHL.

type: heading
heading: Pakketten
heading_style: title
icon: mdi:package-variant-closed
badges:
  - type: entity
    show_state: true
    show_icon: true
    entity: sensor.postnl_delivery
    name: PostNL
    icon: phu:postnl
  - type: entity
    show_state: true
    show_icon: true
    entity: sensor.aantal_aankomende_dhl_pakketjes
    icon: phu:dhl

For the DHL counter, I had to make a helper sensor template that only counts the incoming packages:

{% set dhl_pakketjes = state_attr('sensor.dhl_packages', 'parcels') or [] %}
{% set undelivered_count = 0 %}

{% for pakket in dhl_pakketjes %}
  {% set status = pakket.status | lower %}
  {% if 'delivered' not in status and 'collected' not in status %}
    {% set undelivered_count = undelivered_count + 1 %}
  {% endif %}
{% endfor %}

{{ undelivered_count }}

For the card itself, I made some changes to the excellent examples of Marco and Robbin.

type: custom:auto-entities
card:
  type: entities
  show_header_toggle: false
  card_mod:
    style: |
      #states {
        margin-right: 10px;
        padding-left: 15px;
      }
      #states > div:nth-child(1) {
        margin-top: -25px;
      }
filter:
  template: >
    {# DHL ophalen #}  {% set dhl_pakketjes =
    state_attr('sensor.dhl_packages','parcels') or [] %}  {% set dhl_onderweg =
    namespace(list=[]) %}  {% set dhl_recent_afgeleverd = namespace(list=[]) %}

    {# DHL pakketten #} {% for pakket in dhl_pakketjes %}
      {% set status = pakket.status | lower %}
      {% set tijd_raw = pakket.receivingTimeIndication.start if pakket.receivingTimeIndication.start is defined else pakket.receivingTimeIndication.moment %}
      {% if tijd_raw %}
        {% set tijd = as_timestamp(tijd_raw) | timestamp_custom('%d-%m-%Y %H:%M') %}
      {% else %}
        {% set tijd = 'Onbekend' %}
      {% endif %}
      {% set naam = pakket.sender.name if pakket.sender.name else 'Onbekende afzender' %}
      {% set barcode = pakket.barcode %}
      {% set nette_status = pakket.status | replace('_', ' ') | lower() | capitalize() %}
      {% if nette_status == 'Prenotification received' %}
        {% set nette_status = 'Aangemeld' %}
      {% endif %}
      {% if nette_status == 'Shipment picked up' %}
        {% set nette_status = 'Ontvangen door DHL' %}
      {% endif %}
      {% if nette_status == 'In transit' %}
        {% set nette_status = 'Onderweg' %}
      {% endif %}
      {% if nette_status == 'Out for delivery' %}
        {% set nette_status = 'Wordt bezorgd' %}
      {% endif %}
      {% if nette_status == 'Delivered' or nette_status == 'Delivered in mailbox' %}
        {% set nette_status = 'Bezorgd' %}
      {% endif %}
      {% set dhl_track_url = 'https://www.dhl.com/nl-en/home/tracking.html?tracking-id=' ~ barcode ~ '&submit=1' %}

      {% set row = {
        'type': 'custom:template-entity-row',
        'entity': 'sensor.dhl_packages',
        'name': '' ~ naam ~ ' - ' ~ barcode,
        'state': nette_status,
        'secondary': 'Bezorgtijd: ' ~ tijd,
        'icon': 'phu:dhl',
        'color': '#ffcc00',
        'tap_action': {
          'action': 'url',
          'url_path': dhl_track_url
        }
      } %}

      {% if 'delivered' in status or 'collected' in status %}
        {% if pakket.receivedDaysAgo is not none and pakket.receivedDaysAgo <= 3 %}
          {% set dhl_recent_afgeleverd.list = dhl_recent_afgeleverd.list + [row] %} 
        {% endif %}
      {% else %}
        {% set dhl_onderweg.list = dhl_onderweg.list + [row] %}
      {% endif %}
    {% endfor %}

    {# PostNL ophalen #}  {% set postnl_enroute =
    state_attr('sensor.postnl_delivery', 'enroute') or [] %}  {% set
    postnl_delivered = state_attr('sensor.postnl_delivery', 'delivered') or []
    %}  {% set postnl_onderweg = namespace(list=[]) %}  {% set
    postnl_recent_afgeleverd = namespace(list=[]) %}

    {# PostNL onderweg pakketten #}  {% for pakket in postnl_enroute %}
      {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
      {% set barcode = pakket.key %}
      {% set nette_status = pakket.status_message | default('Status onbekend') %}
      {% if 'nog niet door PostNL ontvangen of verwerkt' in nette_status %}
        {% set nette_status = 'Aangemeld' %}
      {% endif %}
      {% set tijd_raw = pakket.planned_from %}
      {% if tijd_raw %}
        {% set tijd = as_timestamp(tijd_raw) | timestamp_custom('%d-%m-%Y %H:%M') %}
      {% else %}
        {% set tijd = 'Onbekend' %}
      {% endif %}
      {% set postnl_track_url = pakket.url if pakket.url is defined else 'https://www.postnl.nl/tracktrace' %}
      {% set row = {
        'type': 'custom:template-entity-row',
        'entity': 'sensor.postnl_delivery',
        'name': '' ~ naam ~ ' - ' ~ barcode,
        'state': nette_status,
        'secondary': 'Verwacht: ' ~ tijd,
        'icon': 'phu:postnl',
        'color': '#FB6200',
        'tap_action': {
          'action': 'url',
          'url_path': postnl_track_url
        }
      } %}
      {% set postnl_onderweg.list = postnl_onderweg.list + [row] %}
    {% endfor %}

    {# PostNL recent afgeleverd pakketten (max 3 dagen) #}  {% for pakket in
    postnl_delivered %}
      {% set tijd_raw = pakket.delivery_date %}
      {% if tijd_raw %}
        {% set tijd_ts = as_timestamp(tijd_raw) %}
        {% set nu = now().timestamp() %}
        {% set dagen_verschil = (nu - tijd_ts) / 86400 %}
      {% else %}
        {% set dagen_verschil = 999 %}
      {% endif %}
      {% if dagen_verschil <= 3 %}
        {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
        {% set barcode = pakket.key %}
        {% set nette_status = pakket.status_message | default('Status onbekend') %}
        {% if 'Pakket is bezorgd' in nette_status %}
          {% set nette_status = 'Bezorgd' %}
        {% endif %}
        {% set tijd = tijd_ts | timestamp_custom('%d-%m-%Y %H:%M') %}
        {% set postnl_track_url = pakket.url if pakket.url is defined else 'https://www.postnl.nl/tracktrace' %}
        {% set row = {
          'type': 'custom:template-entity-row',
          'entity': 'sensor.postnl_delivery',
          'name': '' ~ naam ~ ' - ' ~ barcode,
          'state': nette_status,
          'secondary': 'Bezorgd op: ' ~ tijd,
          'icon': 'phu:postnl',
          'color': '#FB6200',
          'tap_action': {
            'action': 'url',
            'url_path': postnl_track_url
          }
        } %}
        {% set postnl_recent_afgeleverd.list = postnl_recent_afgeleverd.list + [row] %}
      {% endif %}
    {% endfor %}

    {# Eindlijst bouwen #} {% set all_onderweg_items = [] %}

    {% if dhl_onderweg.list %}
      {% set all_onderweg_items = all_onderweg_items + dhl_onderweg.list %}
    {% endif %}

    {% if postnl_onderweg.list %}
      {% set all_onderweg_items = all_onderweg_items + postnl_onderweg.list %}
    {% endif %}

    {% set all_recent_afgeleverd_items = [] %}

    {% if dhl_recent_afgeleverd.list %}
      {% set all_recent_afgeleverd_items = all_recent_afgeleverd_items + dhl_recent_afgeleverd.list %}
    {% endif %}

    {% if postnl_recent_afgeleverd.list %}
      {% set all_recent_afgeleverd_items = all_recent_afgeleverd_items + postnl_recent_afgeleverd.list %}
    {% endif %}

    [
      {% if all_onderweg_items | count > 0 %}
        {
          "type": "section",
          "label": "🚚 Onderweg"
        }
        {% if all_onderweg_items | count > 0 %}, {{ all_onderweg_items | join(',') }}{% endif %}
      {% endif %}
      
      {# Add a comma between sections ONLY if both exist #}
      {% if (all_onderweg_items | count > 0) and (all_recent_afgeleverd_items | count > 0) %},{% endif %}

      {% if all_recent_afgeleverd_items | count > 0 %}
        {
          "type": "section",
          "label": "šŸ“¦ Recent afgeleverd"
        }
        {% if all_recent_afgeleverd_items | count > 0 %}, {{ all_recent_afgeleverd_items | join(',') }}{% endif %}
      {% endif %}
    ]
show_empty: true
grid_options:
  columns: full

The only thing I can’t get perfect are the dividers that are included with the sections. I tried replacing the sections with other card types (i.e. ā€œheadingā€), but that didn’t go very well. I also tried to apply a card-mod to the sections, but that seems to be completely ignored when used inside an auto-entities filter for some reason, even when formatted like:

"type": "section",
"label": "🚚 Onderweg",
"card-mod": {
  "style" : " | <css here>"
}

And I tried many variations on that…

All in all I’m quite happy with the end result, but if someone knows a way to use card-mod styling on the sections inside the auto-entities card, that would be great!

4 Likes

Nice bedankt @Lxxrxns

Only the dhl counter stays on 0

Did put helper in my sensor.yaml

According Gemini must be the correct helper sensor code:

# DHL pakketten
- sensor:
    - name: "Aantal Aankomende DHL Pakketjes"
      state: >
        {% set dhl_pakketjes = state_attr('sensor.dhl_packages', 'parcels') or [] %}
        {% set undelivered_count = namespace(value=0) %} {# Initialize as a namespace object #}
        {% for pakket in dhl_pakketjes %}
          {% set status = pakket.status | lower %}
          {% if 'delivered' not in status and 'collected' not in status %}
            {% set undelivered_count.value = undelivered_count.value + 1 %} {# Update the value property #}
          {% endif %}
        {% endfor %}
        {{ undelivered_count.value }} {# Access the value property #}

After this I got the right counting of DHL packages

You’re right! Thanks for the fix!

This is awesome guys. Do you know if there is a way to sort the packages on delivery date? Now it orders fiets on DHL/postnl and then date. I would like to have them mixed but sorted on date if possible

Hi remcop!

Here is the updated template code. All it took was 1 prompt to ChatGPT to fix what you want :slight_smile:

I took the liberty of also sorting the ā€œRecent afgeleverdā€ by most recent delivery.

If the delivery date is still ā€œOnbekendā€, the package will be sorted last.

{# DHL ophalen #}
{% set dhl_pakketjes = state_attr('sensor.dhl_packages','parcels') or [] %}
{% set dhl_onderweg = namespace(list=[]) %}
{% set dhl_recent_afgeleverd = namespace(list=[]) %}

{# DHL pakketten #}
{% for pakket in dhl_pakketjes %}
  {% set status = pakket.status | lower %}
  {% set tijd_raw = pakket.receivingTimeIndication.start if pakket.receivingTimeIndication.start is defined else pakket.receivingTimeIndication.moment %}
  {% set tijd = 'Onbekend' %}
  {% set tijd_ts = 9999999999 %}
  {% if tijd_raw %}
    {% set tijd_ts = as_timestamp(tijd_raw) %}
    {% set tijd = tijd_ts | timestamp_custom('%d-%m-%Y %H:%M') %}
  {% endif %}
  
  {% set naam = pakket.sender.name if pakket.sender.name else 'Onbekende afzender' %}
  {% set barcode = pakket.barcode %}
  {% set nette_status = pakket.status | replace('_', ' ') | lower() | capitalize() %}
  {% if nette_status == 'Prenotification received' %}
    {% set nette_status = 'Aangemeld' %}
  {% endif %}
  {% if nette_status == 'Shipment picked up' %}
    {% set nette_status = 'Ontvangen door DHL' %}
  {% endif %}
  {% if nette_status == 'Parcel picked up at parcelshop' %}
    {% set nette_status = 'Ontvangen door DHL' %}
  {% endif %}
  {% if nette_status == 'Shipment acceptance parcelshop' %}
    {% set nette_status = 'Ontvangen door DHL' %}
  {% endif %}
  {% if nette_status == 'Parcel sorted at hub' %}
    {% set nette_status = 'Gesorteerd' %}
  {% endif %}
  {% if nette_status == 'In transit' %}
    {% set nette_status = 'In doorvoer' %}
  {% endif %}
  {% if nette_status == 'Parcel arrived at local depot' %}
    {% set nette_status = 'Bij lokale depot' %}
  {% endif %}
  {% if nette_status == 'Out for delivery' %}
    {% set nette_status = 'Onderweg' %}
  {% endif %}
  {% if nette_status == 'Not home system intervention delivery at parcelshop' %}
    {% set nette_status = 'Onderweg naar DHL punt' %}
  {% endif %}
  {% if nette_status == 'Notification for parcelshop collection has been sent' %}
    {% set nette_status = 'Op te halen bij DHL punt' %}
  {% endif %}
  {% if nette_status == 'Delivered' or nette_status == 'Delivered in mailbox' or nette_status == 'Collected at parcelshop' %}
    {% set nette_status = 'Bezorgd' %}
    {% set verwacht_of_bezorgd = 'Bezorgd' %}
  {% else %}
    {% set verwacht_of_bezorgd = 'Verwacht' %}
  {% endif %}
  {% set dhl_track_url = 'https://www.dhl.com/nl-en/home/tracking.html?tracking-id=' ~ barcode ~ '&submit=1' %}

  {% set row = {
    'type': 'custom:template-entity-row',
    'entity': 'sensor.dhl_packages',
    'name': '' ~ naam ~ ' - ' ~ barcode,
    'state': nette_status,
    'secondary': '' ~ verwacht_of_bezorgd ~': ' ~ tijd,
    'icon': 'phu:dhl',
    'color': '#ffcc00',
    'tap_action': {
      'action': 'url',
      'url_path': dhl_track_url
    },
    'sort_tijd': tijd_ts
  } %}

  {% if 'delivered' in status or 'collected' in status %}
    {% if pakket.receivedDaysAgo is not none and pakket.receivedDaysAgo <= 3 %}
      {% set dhl_recent_afgeleverd.list = dhl_recent_afgeleverd.list + [row] %}
    {% endif %}
  {% else %}
    {% set dhl_onderweg.list = dhl_onderweg.list + [row] %}
  {% endif %}
{% endfor %}

{# PostNL ophalen #}
{% set postnl_enroute = state_attr('sensor.postnl_delivery', 'enroute') or [] %}
{% set postnl_delivered = state_attr('sensor.postnl_delivery', 'delivered') or [] %}
{% set postnl_onderweg = namespace(list=[]) %}
{% set postnl_recent_afgeleverd = namespace(list=[]) %}

{# PostNL onderweg pakketten #}
{% for pakket in postnl_enroute %}
  {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
  {% set barcode = pakket.key %}
  {% set nette_status = pakket.status_message | default('Status onbekend') %}
  {% if 'nog niet door PostNL ontvangen of verwerkt' in nette_status %}
    {% set nette_status = 'Aangemeld' %}
  {% endif %}
  {% if 'is ontvangen door PostNL' in nette_status %}
    {% set nette_status = 'Verzonden' %}
  {% endif %}
  {% if 'is gesorteerd' in nette_status %}
    {% set nette_status = 'Gesorteerd' %}
  {% endif %}
  {% if 'is onderweg' in nette_status %}
    {% set nette_status = 'Onderweg' %}
  {% endif %}
  {% if 'Je hebt betaald' in nette_status %}
    {% set nette_status = 'Inklaringskosten betaald' %}
  {% endif %}
  {% set tijd_raw = pakket.planned_from %}
  {% set tijd = 'Onbekend' %}
  {% set tijd_ts = 9999999999 %}
  {% if tijd_raw %}
    {% set tijd_ts = as_timestamp(tijd_raw) %}
    {% set tijd = tijd_ts | timestamp_custom('%d-%m-%Y %H:%M') %}
  {% endif %}

  {% set postnl_track_url = pakket.url if pakket.url is defined else 'https://www.postnl.nl/tracktrace' %}
  {% set row = {
    'type': 'custom:template-entity-row',
    'entity': 'sensor.postnl_delivery',
    'name': '' ~ naam ~ ' - ' ~ barcode,
    'state': nette_status,
    'secondary': 'Verwacht: ' ~ tijd,
    'icon': 'phu:postnl',
    'color': '#FB6200',
    'tap_action': {
      'action': 'url',
      'url_path': postnl_track_url
    },
    'sort_tijd': tijd_ts
  } %}
  {% set postnl_onderweg.list = postnl_onderweg.list + [row] %}
{% endfor %}

{# PostNL recent afgeleverd pakketten (max 3 dagen) #}
{% for pakket in postnl_delivered %}
  {% set tijd_raw = pakket.delivery_date %}
  {% set tijd = 'Onbekend' %}
  {% set tijd_ts = 0 %}
  {% set dagen_verschil = 999 %}
  {% if tijd_raw %}
    {% set tijd_ts = as_timestamp(tijd_raw) %}
    {% set nu = now().timestamp() %}
    {% set dagen_verschil = (nu - tijd_ts) / 86400 %}
    {% set tijd = tijd_ts | timestamp_custom('%d-%m-%Y %H:%M') %}
  {% endif %}
  
  {% if dagen_verschil <= 3 %}
    {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
    {% set barcode = pakket.key %}
    {% set nette_status = pakket.status_message | default('Status onbekend') %}
    {% if 'Pakket is bezorgd' in nette_status %}
      {% set nette_status = 'Bezorgd' %}
    {% endif %}
    {% set postnl_track_url = pakket.url if pakket.url is defined else 'https://www.postnl.nl/tracktrace' %}
    {% set row = {
      'type': 'custom:template-entity-row',
      'entity': 'sensor.postnl_delivery',
      'name': '' ~ naam ~ ' - ' ~ barcode,
      'state': nette_status,
      'secondary': 'Bezorgd: ' ~ tijd,
      'icon': 'phu:postnl',
      'color': '#FB6200',
      'tap_action': {
        'action': 'url',
        'url_path': postnl_track_url
      },
      'sort_tijd': tijd_ts
    } %}
    {% set postnl_recent_afgeleverd.list = postnl_recent_afgeleverd.list + [row] %}
  {% endif %}
{% endfor %}

{# Eindlijst bouwen #}
{% set all_onderweg_items = [] %}
{% if dhl_onderweg.list %}
  {% set all_onderweg_items = all_onderweg_items + dhl_onderweg.list %}
{% endif %}
{% if postnl_onderweg.list %}
  {% set all_onderweg_items = all_onderweg_items + postnl_onderweg.list %}
{% endif %}
{% set all_onderweg_items_sorted = all_onderweg_items | sort(attribute='sort_tijd') %}

{% set all_recent_afgeleverd_items = [] %}
{% if dhl_recent_afgeleverd.list %}
  {% set all_recent_afgeleverd_items = all_recent_afgeleverd_items + dhl_recent_afgeleverd.list %}
{% endif %}
{% if postnl_recent_afgeleverd.list %}
  {% set all_recent_afgeleverd_items = all_recent_afgeleverd_items + postnl_recent_afgeleverd.list %}
{% endif %}
{% set all_recent_afgeleverd_items_sorted = all_recent_afgeleverd_items | sort(attribute='sort_tijd', reverse=true) %}

[
  {% if all_onderweg_items_sorted | count > 0 %}
    {
      "type": "section",
      "label": "🚚 Onderweg"
    }
    {% if all_onderweg_items_sorted | count > 0 %}, {{ all_onderweg_items_sorted | join(',') }}{% endif %}
  {% endif %}
 
  {# Add a comma between sections ONLY if both exist #}
  {% if (all_onderweg_items_sorted | count > 0) and (all_recent_afgeleverd_items_sorted | count > 0) %},{% endif %}

  {% if all_recent_afgeleverd_items_sorted | count > 0 %}
    {
      "type": "section",
      "label": "šŸ“¦ Recent afgeleverd"
    }
    {% if all_recent_afgeleverd_items_sorted | count > 0 %}, {{ all_recent_afgeleverd_items_sorted | join(',') }}{% endif %}
  {% endif %}
]
4 Likes

I keep forgetting that asking chatGPT is a viable option :slight_smile:
Thanks for helping out!

I changed the DHL counter code a bit. It now has an attribute that displays the delivery window and an attribute that becomes active if a delivery is due. I use that to create dashboard notifications when a delivery is due and hope te integrate that in the doorbell notification somehow.

sensor:
  - platform: template
    sensors:
      dhl_packages_onderweg:
        friendly_name: "DHL pakketjes onderweg"
        unit_of_measurement: "pakketjes"
        value_template: >
          {% set dhl_pakketjes = state_attr('sensor.dhl_packages', 'parcels') or [] %}
          {% set undelivered_count = namespace(value=0) %}
          {% for pakket in dhl_pakketjes %}
            {% set status = pakket.status | lower %}
            {% if 'delivered' not in status and 'collected' not in status %}
              {% set undelivered_count.value = undelivered_count.value + 1 %}
            {% endif %}
          {% endfor %}
          {{ undelivered_count.value }}
        icon_template: "phu:dhl"
        attribute_templates:
          expect_now: >
            {% set pakket = state_attr('sensor.dhl_packages', 'parcels') | rejectattr('category', 'in', ['DELIVERED']) | first or [] %}
            {% set tijd_raw = pakket.receivingTimeIndication %}
            {% if as_timestamp(now()) > as_timestamp(tijd_raw.start) %}
              {% if as_timestamp(now()) < as_timestamp(tijd_raw.end) %}expecting
              {% else %}overdue
              {% endif %}
            {% else %}notexpecting
            {% endif %}
          deliver_window: >
            {% set pakket = state_attr('sensor.dhl_packages', 'parcels') | rejectattr('category', 'in', ['DELIVERED']) | first or [] %}
            {% set tijd_raw = pakket.receivingTimeIndication if pakket.receivingTimeIndication is defined else pakket.receivingTimeIndication.moment %}
            {% if tijd_raw %}
              {{ as_timestamp(tijd_raw.start) | timestamp_custom('%H:%M') }} - {{ as_timestamp(tijd_raw.end) | timestamp_custom('%H:%M') }}
            {% else %}Onbekend
            {% endif %}

Also I am trying to change the code a bit, so it shows the delivery window (start & end) in stead of just the starting time.
For DHL I used:

{# DHL pakketten #}
{% for pakket in dhl_pakketjes %}
  {% set status = pakket.status | lower %}
  {% set tijd_raw = pakket.receivingTimeIndication.start if pakket.receivingTimeIndication.start is defined else pakket.receivingTimeIndication.moment %}
  {% set tijd_end = pakket.receivingTimeIndication.end if pakket.receivingTimeIndication.end is defined else pakket.receivingTimeIndication.moment %}
  {% set tijd = 'Onbekend' %}
  {% set tijd_ts = 9999999999 %}
  {% if tijd_raw %}
    {% set tijd_ts = as_timestamp(tijd_raw) %}
    {% set tijd = tijd_ts | timestamp_custom('%d-%m-%Y %H:%M') %}
    {% if tijd_raw != tijd_end %}
      {% set tijd = tijd_ts | timestamp_custom('%d-%m-%Y %H:%M') ~ ' - ' ~ as_timestamp(tijd_end) | timestamp_custom('%H:%M') %}
    {% endif %}
  {% endif %}

1 Like

Thanks for all the effort. It helped me greatly.
I am used to make very clean cards (and also combine them with card mod and/or layour card), I hope this code helps others:

type: custom:mod-card
style: |
  ha-card {
    border-radius: 20px !important;
    background-color: rgba(10, 10, 10, 0.4) !important;
  }
card:
  type: vertical-stack
  cards:
    - type: heading
      heading: Pakketten
      heading_style: title
      badges:
        - type: entity
          show_state: true
          show_icon: true
          entity: sensor.postnl_packages_onderweg
          icon: phu:postnl
        - type: entity
          show_state: true
          show_icon: true
          entity: sensor.dhl_packages_onderweg
          icon: phu:dhl
      card_mod:
        style: |
          ha-card {
            margin-top: 10px !important;
            margin-right: 10px !important;
            margin-left: 20px !important;
          }
    - type: custom:auto-entities
      card:
        type: entities
        show_header_toggle: false
        card_mod:
          style: |
            ha-card {
              background: none;
              margin-top: -25px
            }
      filter:
        template: >
          {# DHL ophalen #} {% set dhl_pakketjes =
          state_attr('sensor.dhl_packages','parcels') or [] %} {% set
          dhl_onderweg = namespace(list=[]) %} {% set dhl_recent_afgeleverd =
          namespace(list=[]) %}

          {# DHL pakketten #} {% for pakket in dhl_pakketjes %}
            {% set status = pakket.status | lower %}
            {% set tijd_raw = pakket.receivingTimeIndication.start if pakket.receivingTimeIndication.start is defined else pakket.receivingTimeIndication.moment %}
            {% set tijd = 'Onbekend' %}
            {% set tijd_ts = 9999999999 %}
            {% if tijd_raw %}
              {% set tijd_ts = as_timestamp(tijd_raw) %}
              {% set tijd = tijd_ts | timestamp_custom('%d-%m-%Y %H:%M') %}
            {% endif %}
            
            {% set naam = pakket.sender.name if pakket.sender.name else 'Onbekende afzender' %}
            {% set barcode = pakket.barcode %}
            {% set nette_status = pakket.status | replace('_', ' ') | lower() | capitalize() %}
            {% if nette_status == 'Prenotification received' %}
              {% set nette_status = 'Aangemeld' %}
            {% endif %}
            {% if nette_status == 'Shipment picked up' %}
              {% set nette_status = 'Ontvangen door DHL' %}
            {% endif %}
            {% if nette_status == 'Parcel picked up at parcelshop' %}
              {% set nette_status = 'Ontvangen door DHL' %}
            {% endif %}
            {% if nette_status == 'Shipment acceptance parcelshop' %}
              {% set nette_status = 'Ontvangen door DHL' %}
            {% endif %}
            {% if nette_status == 'Parcel sorted at hub' %}
              {% set nette_status = 'Gesorteerd' %}
            {% endif %}
            {% if nette_status == 'In transit' %}
              {% set nette_status = 'In doorvoer' %}
            {% endif %}
            {% if nette_status == 'Parcel arrived at local depot' %}
              {% set nette_status = 'Bij lokale depot' %}
            {% endif %}
            {% if nette_status == 'Out for delivery' %}
              {% set nette_status = 'Onderweg' %}
            {% endif %}
            {% if nette_status == 'Not home system intervention delivery at parcelshop' %}
              {% set nette_status = 'Onderweg naar DHL punt' %}
            {% endif %}
            {% if nette_status == 'Notification for parcelshop collection has been sent' %}
              {% set nette_status = 'Op te halen bij DHL punt' %}
            {% endif %}
            {% if nette_status == 'Delivered' or nette_status == 'Delivered in mailbox' or nette_status == 'Collected at parcelshop' %}
              {% set nette_status = 'Bezorgd' %}
              {% set verwacht_of_bezorgd = 'Bezorgd' %}
            {% else %}
              {% set verwacht_of_bezorgd = 'Verwacht' %}
            {% endif %}
            {% set dhl_track_url = 'https://www.dhl.com/nl-en/home/tracking.html?tracking-id=' ~ barcode ~ '&submit=1' %}

            {% set row = {
              'type': 'custom:template-entity-row',
              'entity': 'sensor.dhl_packages',
              'name': '' ~ naam ~ ' - ' ~ barcode,
              'state': nette_status,
              'secondary': '' ~ verwacht_of_bezorgd ~': ' ~ tijd,
              'icon': 'phu:dhl',
              'color': '#ffcc00',
              'tap_action': {
                'action': 'url',
                'url_path': dhl_track_url
              },
              'sort_tijd': tijd_ts
            } %}

            {% if 'delivered' in status or 'collected' in status %}
              {% if pakket.receivedDaysAgo is not none and pakket.receivedDaysAgo <= 3 %}
                {% set dhl_recent_afgeleverd.list = dhl_recent_afgeleverd.list + [row] %}
              {% endif %}
            {% else %}
              {% set dhl_onderweg.list = dhl_onderweg.list + [row] %}
            {% endif %}
          {% endfor %}

          {# PostNL ophalen #} {% set postnl_enroute =
          state_attr('sensor.postnl_delivery', 'enroute') or [] %} {% set
          postnl_delivered = state_attr('sensor.postnl_delivery', 'delivered')
          or [] %} {% set postnl_onderweg = namespace(list=[]) %} {% set
          postnl_recent_afgeleverd = namespace(list=[]) %}

          {# PostNL onderweg pakketten #} {% for pakket in postnl_enroute %}
            {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
            {% set barcode = pakket.key %}
            {% set nette_status = pakket.status_message | default('Status onbekend') %}
            {% if 'nog niet door PostNL ontvangen of verwerkt' in nette_status %}
              {% set nette_status = 'Aangemeld' %}
            {% endif %}
            {% if 'is ontvangen door PostNL' in nette_status %}
              {% set nette_status = 'Verzonden' %}
            {% endif %}
            {% if 'is gesorteerd' in nette_status %}
              {% set nette_status = 'Gesorteerd' %}
            {% endif %}
            {% if 'is onderweg' in nette_status %}
              {% set nette_status = 'Onderweg' %}
            {% endif %}
            {% if 'Je hebt betaald' in nette_status %}
              {% set nette_status = 'Inklaringskosten betaald' %}
            {% endif %}
            {% set tijd_raw = pakket.planned_from %}
            {% set tijd = 'Onbekend' %}
            {% set tijd_ts = 9999999999 %}
            {% if tijd_raw %}
              {% set tijd_ts = as_timestamp(tijd_raw) %}
              {% set tijd = tijd_ts | timestamp_custom('%d-%m-%Y %H:%M') %}
            {% endif %}

            {% set postnl_track_url = pakket.url if pakket.url is defined else 'https://www.postnl.nl/tracktrace' %}
            {% set row = {
              'type': 'custom:template-entity-row',
              'entity': 'sensor.postnl_delivery',
              'name': '' ~ naam ~ ' - ' ~ barcode,
              'state': nette_status,
              'secondary': 'Verwacht: ' ~ tijd,
              'icon': 'phu:postnl',
              'color': '#FB6200',
              'tap_action': {
                'action': 'url',
                'url_path': postnl_track_url
              },
              'sort_tijd': tijd_ts
            } %}
            {% set postnl_onderweg.list = postnl_onderweg.list + [row] %}
          {% endfor %}

          {# PostNL recent afgeleverd pakketten (max 3 dagen) #} {% for pakket
          in postnl_delivered %}
            {% set tijd_raw = pakket.delivery_date %}
            {% set tijd = 'Onbekend' %}
            {% set tijd_ts = 0 %}
            {% set dagen_verschil = 999 %}
            {% if tijd_raw %}
              {% set tijd_ts = as_timestamp(tijd_raw) %}
              {% set dagen_verschil = (now().timestamp() - tijd_ts) / 86400 %}
              {% set tijd_datetime = tijd_raw|as_datetime %}
              {% set dag = ['Maandag','Dinsdag','Woensdag','Donderdag','Vrijdag','Zaterdag','Zondag'] %}
              {% set dag = dag[tijd_datetime.weekday()] %}
              {% set tijd = dag + ' ' + as_timestamp(tijd_datetime)|timestamp_custom('%H:%M') %}
            {% endif %}
            
            {% if dagen_verschil <= 3 %}
              {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
              {% set barcode = pakket.key %}
              {% set nette_status = pakket.status_message | default('Status onbekend') %}
              {% if 'Pakket is bezorgd' in nette_status %}
                {% set nette_status = 'Bezorgd' %}
              {% endif %}
              {% set postnl_track_url = pakket.url if pakket.url is defined else 'https://www.postnl.nl/tracktrace' %}
              {% set row = {
                'type': 'custom:template-entity-row',
                'entity': 'sensor.postnl_delivery',
                'name': '' ~ naam ~ ' - ' ~ barcode,
                'state': nette_status,
                'secondary': tijd,
                'icon': 'phu:postnl',
                'color': '#FB6200',
                'tap_action': {
                  'action': 'url',
                  'url_path': postnl_track_url
                },
                'sort_tijd': tijd_ts
              } %}
              {% set postnl_recent_afgeleverd.list = postnl_recent_afgeleverd.list + [row] %}
            {% endif %}
          {% endfor %}

          {# Eindlijst bouwen #} {% set all_onderweg_items = [] %} {% if
          dhl_onderweg.list %}
            {% set all_onderweg_items = all_onderweg_items + dhl_onderweg.list %}
          {% endif %} {% if postnl_onderweg.list %}
            {% set all_onderweg_items = all_onderweg_items + postnl_onderweg.list %}
          {% endif %} {% set all_onderweg_items_sorted = all_onderweg_items |
          sort(attribute='sort_tijd') %}

          {% set all_recent_afgeleverd_items = [] %} {% if
          dhl_recent_afgeleverd.list %}
            {% set all_recent_afgeleverd_items = all_recent_afgeleverd_items + dhl_recent_afgeleverd.list %}
          {% endif %} {% if postnl_recent_afgeleverd.list %}
            {% set all_recent_afgeleverd_items = all_recent_afgeleverd_items + postnl_recent_afgeleverd.list %}
          {% endif %} {% set all_recent_afgeleverd_items_sorted =
          all_recent_afgeleverd_items | sort(attribute='sort_tijd',
          reverse=true) %}

          [
            {% if all_onderweg_items_sorted | count > 0 %}
              {
                "type": "section",
                "label": "Onderweg"
              }
              {% if all_onderweg_items_sorted | count > 0 %}, {{ all_onderweg_items_sorted | join(',') }}{% endif %}
            {% endif %}
           
            {# Add a comma between sections ONLY if both exist #}
            {% if (all_onderweg_items_sorted | count > 0) and (all_recent_afgeleverd_items_sorted | count > 0) %},{% endif %}

            {% if all_recent_afgeleverd_items_sorted | count > 0 %}
              {
                "type": "section",
                "label": "Recent afgeleverd"
              }
              {% if all_recent_afgeleverd_items_sorted | count > 0 %}, {{ all_recent_afgeleverd_items_sorted | join(',') }}{% endif %}
            {% endif %}
          ]
      show_empty: true

1 Like

By putting together some code (PostNL integration, DHL curl command, sensor script, etc.), most of it now works (thanks for sharing).
However, not everything appears on the screen with DHL. I don’t see packages starting with JJD, while those starting with JVGL are visible.
Is this also the case for you?

hi all, got the PostNL working, however, I still get status 0 back for the DHL sensor. I tried several approaches and no history is shown. If using Multiscrape, what does work for you? I do see the json output of all packages and history at https://my.dhlecommerce.nl/receiver-parcel-api/parcels - when I login via https://my.dhlecommerce.nl but when using the url https://my.dhlecommerce.nl/api/user/login to login get a ā€œMethod Not Allowedā€ error. Can someone post a working setup? (YAML?) What url and what method you use. Think multiscrape should work, but wonder why this give a 0 back as response but no history. (0 is correct as no packages are underway).

multiscrape:
  - resource: "https://my.dhlecommerce.nl/api/user/login"
    scan_interval: 1800
    method: "post"
    headers:
      Content-Type: "application/json"
    payload: '{"email":"email","password":"pwd"}'
  - resource: "https://my.dhlecommerce.nl/receiver-parcel-api/parcels"
    scan_interval: 1800
    method: "get"
    headers:
      Content-Type: "application/json"
    sensor:
      - unique_id: dhl_packages
        name: DHL Pakketten
        value_template: "{{ value_json.parcels | selectattr('category', 'search', '(PROBLEM|CUSTOMS|DATA_RECEIVED|EXCEPTION|INTERVENTION|IN_DELIVERY|LEG|UNDERWAY|UNKNOWN)') | list | count }}"
        attributes:
          - name: parcels
            value_template: "{{ value_json.parcels | selectattr('category', 'search', '(PROBLEM|CUSTOMS|DATA_RECEIVED|EXCEPTION|INTERVENTION|IN_DELIVERY|LEG|UNDERWAY|UNKNOWN)') | list }}"

for the life of me , if i try the same to check if its deliverd or collected, it just gives me empty card , it seems that whenever i add the (OR ) logical condition in the if statement , my cards get borked

type: custom:auto-entities
card:
  type: entities
  title: Pakketjes
filter:
  template: >
    {# DHL ophalen #} 
 {% set dhl_pakketjes = state_attr('sensor.dhl_packages',
    'parcels') or [] %} 
{% set dhl_onderweg = namespace(list=[]) %} {% set
    dhl_recent_afgeleverd = namespace(list=[]) %}

    {% for pakket in dhl_pakketjes %}
      {% set status = pakket.status | lower %}
      {% set tijd_raw = pakket.receivingTimeIndication.start if pakket.receivingTimeIndication.start is defined else pakket.receivingTimeIndication.moment %}
      {% if tijd_raw %}
        {% set tijd = as_timestamp(tijd_raw) | timestamp_custom('%d-%m-%Y %H:%M') %}
      {% else %}
        {% set tijd = 'Onbekend' %}
      {% endif %}
      {% set naam = pakket.sender.name if pakket.sender.name else 'Onbekende afzender' %}
      {% set barcode = pakket.barcode %}
      {% set nette_status = pakket.status | replace('_', ' ') | lower() | capitalize() %}
      {% set row = {
        'type': 'custom:template-entity-row',
        'entity': 'sensor.dhl_packages',
        'name': '' ~ naam ~ ' - ' ~ barcode,
        'state': nette_status,
        'secondary': 'Bezorgtijd: ' ~ tijd,
        'icon': 'phu:dhl',
        'color': '#ffcc00'
      } %}

      {% if 'delivered' not in status or 'collected' not in status %}
        {% set dhl_onderweg.list = dhl_onderweg.list + [row] %}
      {% else %}
        {% if pakket.receivedDaysAgo is not none and pakket.receivedDaysAgo <= 40 %}
          {% set dhl_recent_afgeleverd.list = dhl_recent_afgeleverd.list + [row] %}
        {% endif %}
      {% endif %}
    {% endfor %}

    {# PostNL ophalen #} {% set postnl_enroute =
    state_attr('sensor.postnl_delivery', 'enroute') or [] %} {% set
    postnl_delivered = state_attr('sensor.postnl_delivery', 'delivered') or []
    %} {% set postnl_onderweg = namespace(list=[]) %} {% set
    postnl_recent_afgeleverd = namespace(list=[]) %}

    {# PostNL onderweg pakketten #} {% for pakket in postnl_enroute %}
      {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
      {% set barcode = pakket.key %}
      {% set nette_status = pakket.status_message | default('Status onbekend') %}
      {% set tijd_raw = pakket.planned_from %}
      {% if tijd_raw %}
        {% set tijd = as_timestamp(tijd_raw) | timestamp_custom('%d-%m-%Y %H:%M') %}
      {% else %}
        {% set tijd = 'Onbekend' %}
      {% endif %}
      {% set row = {
        'type': 'custom:template-entity-row',
        'entity': 'sensor.postnl_delivery',
        'name': '' ~ naam ~ ' - ' ~ barcode,
        'state': nette_status,
        'secondary': 'Verwacht: ' ~ tijd,
        'icon': 'phu:postnl',
        'color': '#FB6200',
      } %}
      {% set postnl_onderweg.list = postnl_onderweg.list + [row] %}
    {% endfor %}

    {# PostNL recent afgeleverd pakketten (max 3 dagen) #} {% for pakket in
    postnl_delivered %}
      {% set tijd_raw = pakket.delivery_date %}
      {% if tijd_raw %}
        {% set tijd_ts = as_timestamp(tijd_raw) %}
        {% set nu = now().timestamp() %}
        {% set dagen_verschil = (nu - tijd_ts) / 86400 %}
      {% else %}
        {% set dagen_verschil = 999 %}
      {% endif %}
      {% if dagen_verschil <= 10 %}
        {% set naam = pakket.name if pakket.name else 'Onbekende afzender' %}
        {% set barcode = pakket.key %}
        {% set nette_status = pakket.status_message | default('Status onbekend') %}
        {% set tijd = tijd_ts | timestamp_custom('%d-%m-%Y %H:%M') %}
        {% set row = {
          'type': 'custom:template-entity-row',
          'entity': 'sensor.postnl_delivery',
          'name': '' ~ naam ~ ' - ' ~ barcode,
          'state': nette_status,
          'secondary': 'Bezorgd op: ' ~ tijd,
          'icon': 'phu:postnl',
          'color': '#FB6200',
        } %}
        {% set postnl_recent_afgeleverd.list = postnl_recent_afgeleverd.list + [row] %}
      {% endif %}
    {% endfor %}

    {# Eindlijst bouwen #} [
      {% if (dhl_onderweg.list | count > 0) or (postnl_onderweg.list | count > 0) %}
        {
          "type": "section",
          "label": "🚚 Onderweg"
        },
        {{ dhl_onderweg.list | join(',') }},
        {{ postnl_onderweg.list | join(',') }},
      {% endif %}
      {% if (dhl_recent_afgeleverd.list | count > 0) or (postnl_recent_afgeleverd.list | count > 0) %}
        {
          "type": "section",
          "label": "āœ… Recent afgeleverd"
        },
        {{ dhl_recent_afgeleverd.list | join(',') }},
        {{ postnl_recent_afgeleverd.list | join(',') }}
      {% endif %}
    ]
show_empty: true
grid_options:
  columns: full

i managed to have it fixed , but i ntoiced something , for me if any of the lists for (dhl/postnl_onderweg/afgelvered ) is emtpy , then the whole card doesn’t show

so i made a nested if to control the join JSON function to avoid adding an empty list to the section

 {% if (dhl_onderweg.list | count > 0) or (postnl_onderweg.list | count > 0) %}
    {
      "type": "section",
      "label": "🚚 Onderweg"
    }
    {% if dhl_onderweg.list | count > 0 %},
      {{ dhl_onderweg.list | join(',') }}
    {% endif %}
    {% if postnl_onderweg.list | count > 0 %},
      {{ postnl_onderweg.list | join(',') }}
    {% endif %}
{% endif %}

 {% if (dhl_recent_afgeleverd.list | count > 0) or (postnl_recent_afgeleverd.list | count > 0) %}
    {
      "type": "section",
      "label": "āœ… Recent afgeleverd"
    }
    {% if dhl_recent_afgeleverd.list | count > 0 %},
      {{ dhl_recent_afgeleverd.list | join(',') }}
    {% endif %}
    {% if postnl_recent_afgeleverd.list | count > 0 %},
      {{ postnl_recent_afgeleverd.list | join(',') }}
    {% endif %}
{% endif %}


]

Now, what is the most recent source code to view the PostNL and DHL parcels in the sensor data?
I bought the parcel-app and would like to have an overview on my HA as @Lxxrxns has, which is great!

1 Like

Hello,
How does your code looks nowadays? I can’t get the result for PostNL which you have made for DHL (delivery windows)