What does Settings > System > Logs > Show Raw logs (3dots) say?
See below
2025-12-14 13:06:00.465 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: No first item, sequence was empty. when rendering '{% set pakket = state_attr('sensor.postnl_delivery', 'enroute') | first or [] %} {% if as_timestamp(now()) > as_timestamp(pakket.planned_from) %}
{% if as_timestamp(now()) < as_timestamp(pakket.planned_to) %}expecting
{% else %}overdue
{% endif %}
{% else %}notexpecting {% endif %}'
2025-12-14 13:06:00.465 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'list object' has no attribute 'planned_from' when rendering '{% set pakket = state_attr('sensor.postnl_delivery', 'enroute') | first or [] %} {% if as_timestamp(now()) > as_timestamp(pakket.planned_from) %}
{% if as_timestamp(now()) < as_timestamp(pakket.planned_to) %}expecting
{% else %}overdue
{% endif %}
{% else %}notexpecting {% endif %}'
2025-12-14 13:06:00.465 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'list object' has no attribute 'planned_from' when rendering '{% set pakket = state_attr('sensor.postnl_delivery', 'enroute') | first or [] %} {% if as_timestamp(now()) > as_timestamp(pakket.planned_from) %}
{% if as_timestamp(now()) < as_timestamp(pakket.planned_to) %}expecting
{% else %}overdue
{% endif %}
{% else %}notexpecting {% endif %}'
2025-12-14 13:06:00.465 ERROR (MainThread) [homeassistant.helpers.sensor] Error rendering attributes.expect_now template for sensor.postnl_packages_onderweg: ValueError: Template error: as_timestamp got invalid input '' when rendering template '{% set pakket = state_attr('sensor.postnl_delivery', 'enroute') | first or [] %} {% if as_timestamp(now()) > as_timestamp(pakket.planned_from) %}
{% if as_timestamp(now()) < as_timestamp(pakket.planned_to) %}expecting
{% else %}overdue
{% endif %}
{% else %}notexpecting {% endif %}' but no default was specified
2025-12-14 13:06:00.466 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: No first item, sequence was empty. when rendering '{% set pakket = state_attr('sensor.postnl_delivery', 'enroute') | first or [] %} {% set tijd_raw = pakket.planned_from if pakket.planned_from is defined else [] %} {% if tijd_raw %}
{{ as_timestamp(pakket.planned_from) | timestamp_custom('%H:%M') }} - {{ as_timestamp(pakket.planned_to) | timestamp_custom('%H:%M') }}
{% else %}Onbekend {% endif %}'
2025-12-14 13:06:00.466 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: No first item, sequence was empty. when rendering '{% set pakket = state_attr('sensor.postnl_delivery', 'enroute') | first or [] %} {% set tijd_raw = pakket.planned_from if pakket.planned_from is defined else [] %} {% if tijd_raw %}
{{ as_timestamp(pakket.planned_from) | timestamp_custom('%d-%m-%Y %H:%M') }}
{% else %}Onbekend {% endif %}'
2025-12-14 13:06:00.466 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: No first item, sequence was empty. when rendering '{% set pakket = state_attr('sensor.postnl_delivery', 'enroute') | first or [] %} {% set tijd_raw = pakket.expected_datetime if pakket.expected_datetime is defined else [] %} {% if tijd_raw %}
{{ as_timestamp(pakket.expected_datetime) | timestamp_custom('%d-%m-%Y %H:%M') }}
{% else %}Onbekend {% endif %}'
2025-12-14 13:06:00.466 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: No first item, sequence was empty. when rendering '{% set pakket = state_attr('sensor.postnl_delivery', 'enroute') | first or [] %} {% set tijd_raw = pakket.planned_to if pakket.planned_to is defined else [] %} {% if tijd_raw %}
{{ as_timestamp(pakket.planned_to) | timestamp_custom('%d-%m-%Y %H:%M') }}
{% else %}Onbekend {% endif %}'
2025-12-16 14:32:00.079 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: No first item, sequence was empty. when rendering '{% set pakket = state_attr('sensor.postnl_delivery', 'enroute') | first or [] %} {% if as_timestamp(now()) > as_timestamp(pakket.planned_from) %}
{% if as_timestamp(now()) < as_timestamp(pakket.planned_to) %}expecting
{% else %}overdue
{% endif %}
{% else %}notexpecting {% endif %}'
2025-12-16 14:32:00.079 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'list object' has no attribute 'planned_from' when rendering '{% set pakket = state_attr('sensor.postnl_delivery', 'enroute') | first or [] %} {% if as_timestamp(now()) > as_timestamp(pakket.planned_from) %}
{% if as_timestamp(now()) < as_timestamp(pakket.planned_to) %}expecting
{% else %}overdue
{% endif %}
{% else %}notexpecting {% endif %}'
2025-12-16 14:32:00.079 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'list object' has no attribute 'planned_from' when rendering '{% set pakket = state_attr('sensor.postnl_delivery', 'enroute') | first or [] %} {% if as_timestamp(now()) > as_timestamp(pakket.planned_from) %}
{% if as_timestamp(now()) < as_timestamp(pakket.planned_to) %}expecting
{% else %}overdue
{% endif %}
{% else %}notexpecting {% endif %}'
I got similar logs.
I have requested some assistance from openAI, And I got it working now, There was also a malformed argument warning. But I have this working right now. The code also checks if there is any information filled in the object, before processing. If it’s empty, it’s not gonna use it, reducing faults.
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: Packages
heading_style: title
badges:
- type: entity
show_state: true
show_icon: true
entity: sensor.postnl_delivery
icon: phu:postnl
- type: entity
show_state: true
show_icon: true
entity: sensor.dhl_packages
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: -33px;
}
filter:
template: >
{% set dhl_packages = state_attr('sensor.dhl_raw_json_data','parcels') or [] %}
{% set postnl_enroute = state_attr('sensor.postnl_delivery','enroute') or [] %}
{% set postnl_delivered = state_attr('sensor.postnl_delivery','delivered') or [] %}
{% set enroute_list = namespace(items=[]) %}
{% set delivered_list = namespace(items=[]) %}
{# --- PROCESS DHL --- #}
{% for package in dhl_packages %}
{% set status_raw = package.status | lower %}
{% set barcode = package.barcode %}
{% set name = package.sender.name | default('Unknown sender') %}
{% set time_raw = package.receivingTimeIndication.start
if package.receivingTimeIndication is defined and package.receivingTimeIndication.start is defined else
package.receivingTimeIndication.moment
if package.receivingTimeIndication is defined and package.receivingTimeIndication.moment is defined else none %}
{% set time_end = package.receivingTimeIndication.end
if package.receivingTimeIndication is defined and package.receivingTimeIndication.end is defined else time_raw %}
{% set time_ts = time_raw | default(0) | as_timestamp %}
{% set time_str = 'Unknown' %}
{% if time_raw %}
{% set time_str = time_ts | timestamp_custom('%d-%m-%Y %H:%M') %}
{% if time_raw != time_end %}
{% set time_str = time_str ~ ' - ' ~ (time_end | as_timestamp | timestamp_custom('%H:%M')) %}
{% endif %}
{% endif %}
{% set clean_status = status_raw | replace('_',' ') | lower | capitalize %}
{% if 'prenotification' in clean_status %} {% set clean_status = 'Registered' %} {% endif %}
{% if 'shipment picked up' in clean_status %} {% set clean_status = 'Received by DHL' %} {% endif %}
{% if 'parcel sorted' in clean_status %} {% set clean_status = 'Sorted' %} {% endif %}
{% if 'in transit' in clean_status %} {% set clean_status = 'In transit' %} {% endif %}
{% if 'local depot' in clean_status %} {% set clean_status = 'At local depot' %} {% endif %}
{% if 'out for delivery' in clean_status %} {% set clean_status = 'Out for delivery' %} {% endif %}
{% if 'delivered' in clean_status or 'collected' in clean_status %}
{% set sub_label = 'Delivered' %}
{% set target_list = delivered_list.items %}
{% else %}
{% set sub_label = 'Expected' %}
{% set target_list = enroute_list.items %}
{% endif %}
{% set dhl_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_raw_json_data',
'name': name ~ ' - ' ~ barcode,
'state': clean_status,
'secondary': sub_label ~ ': ' ~ time_str,
'icon': 'phu:dhl',
'color': '#ffcc00',
'tap_action': {'action':'url','url_path': dhl_url},
'sort_time': time_ts
} %}
{% if sub_label == 'Delivered' %}
{% set delivered_list.items = delivered_list.items + [row] %}
{% else %}
{% set enroute_list.items = enroute_list.items + [row] %}
{% endif %}
{% endfor %}
{# --- PROCESS POSTNL ENROUTE --- #}
{% for package in postnl_enroute %}
{% set barcode = package.key %}
{% set name = package.name | default('Unknown sender') %}
{% set status_raw = package.status_message | default('') %}
{% set clean_status = 'Expected' %}
{% if 'nog niet door PostNL' in status_raw %} {% set clean_status = 'Registered' %} {% endif %}
{% if 'is ontvangen' in status_raw %} {% set clean_status = 'Received by PostNL' %} {% endif %}
{% if 'is gesorteerd' in status_raw %} {% set clean_status = 'Sorted' %} {% endif %}
{% if 'is onderweg' in status_raw %} {% set clean_status = 'Out for delivery' %} {% endif %}
{% if 'afgehaald' in status_raw or 'pakketautomaat' in status_raw %} {% set clean_status = 'Ready for pickup' %} {% endif %}
{% if 'betaald' in status_raw %} {% set clean_status = 'Clearance fees paid' %} {% endif %}
{% set time_raw = package.planned_from if package.planned_from is defined else none %}
{% set time_ts = time_raw | default(0) | as_timestamp %}
{% set time_str = 'Unknown' %}
{% if time_raw %} {% set time_str = time_ts | timestamp_custom('%d-%m-%Y %H:%M') %} {% endif %}
{% set postnl_url = package.url | default('https://www.postnl.nl/tracktrace') %}
{% set row = {
'type': 'custom:template-entity-row',
'entity': 'sensor.postnl_delivery',
'name': name ~ ' - ' ~ barcode,
'state': clean_status,
'secondary': 'Expected: ' ~ time_str,
'icon': 'phu:postnl',
'color': '#FB6200',
'tap_action': {'action':'url','url_path': postnl_url},
'sort_time': time_ts
} %}
{% set enroute_list.items = enroute_list.items + [row] %}
{% endfor %}
{# --- PROCESS POSTNL DELIVERED --- #}
{% for package in postnl_delivered %}
{% set time_raw = package.delivery_date if package.delivery_date is defined else none %}
{% set time_ts = time_raw | default(0) | as_timestamp %}
{% set days_diff = (now().timestamp() - time_ts)/86400 %}
{% if days_diff <= 3 %}
{% set barcode = package.key %}
{% set status_raw = package.status_message | default('') %}
{% set clean_status = 'Delivered' %}
{% set postnl_url = package.url | default('https://www.postnl.nl/tracktrace') %}
{% set time_str = time_ts | timestamp_custom('%d-%m-%Y %H:%M') %}
{% set row = {
'type': 'custom:template-entity-row',
'entity': 'sensor.postnl_delivery',
'name': barcode,
'state': clean_status,
'secondary': 'Delivered: ' ~ time_str,
'icon': 'phu:postnl',
'color': '#FB6200',
'tap_action': {'action':'url','url_path': postnl_url},
'sort_time': time_ts
} %}
{% set delivered_list.items = delivered_list.items + [row] %}
{% endif %}
{% endfor %}
{# --- SORT AND RENDER JSON --- #}
{% set enroute_sorted = enroute_list.items | sort(attribute='sort_time') %}
{% set delivered_sorted = delivered_list.items | sort(attribute='sort_time', reverse=true) %}
{% set final_list = [] %}
{% if enroute_sorted | count > 0 %}
{% set final_list = final_list + [{"type": "section", "label": "🚚 Enroute"}] %}
{% set final_list = final_list + enroute_sorted %}
{% endif %}
{% if delivered_sorted | count > 0 %}
{% set final_list = final_list + [{"type": "section", "label": "📦 Delivered"}] %}
{% set final_list = final_list + delivered_sorted %}
{% endif %}
{{ final_list | tojson }}
show_empty: true
Has anyone got the issue where their PostNL authentication has expired and they cannot get it to work? I click the “Send” button, which redirects my to PostNL login. I login, and then I get stuck on:
Did you add the browser app installed.
You need this to get this to work
Hi Jonathan.
Great guide. Question about DPD, GLS etc, is that the same approach as you did for DHL?
I’ve vibe coded a Lovelace card to track packages: Package Tracker Card. It currently supports both parcel-ha and ha-postnl. Created it for personal use, but it might come in handy for others too.
Wow nice one !
thanks for the contribution!!
Also very interested in the code for DPD, GLS etc. @Jonathanx597 ![]()
Unfortunately I don’t get the header very clean with this configuration.
Any idea how this is possible?
Oei just noticed that the DHL intergration doesn't work anymore..
The API url (https://my.dhlecommerce.nl/receiver-parcel-api/parcels) is out of the air.
any one know a new api url?
Or is't temperately
Yes, it stopped for me too.
DHL now expects the x-xsrf-token header to be set. The value for this header is returned as a cookie in the login process. Not sure yet how to move the value from a cookie to a header ![]()
EDIT: I just vibe coded a custom component together. I only have no packages on my way so no clue if parcels are returned nicely. Log in though works
Nice work @ptnijssen .
Hope it works!
I can't test also because no dhl packages are in transit.
Let me (us) know how the new code works for you.
I'm willing to test also
Waiting for the fix ASAP, we can’t live without it anymore ![]()
This is completely vibe coded by handing the API endpoints, responses etc to AI. Based upon that it created this integration. Not a single line is created by me, so beware ![]()
Yes got it up and running!
Just waiting for time update and see if it goes to my kalender and rest will goes right.
For now looking good!
Awesome! Just noticed that the "ready for pick up" is to optimistic as the parcel is still on its way.
This looks great and works perfect.
It doesn't show history does it?





