๐ฌ Questions or feedback? Join the discussion on the Home Assistant community.
A Home Assistant custom integration that rolls up parcel counts, next-delivery timestamps, and parcel-event notifications from the DHL, PostNL, DPD and GLS integrations into a single set of sensors and a single unified event stream.
- Use cases
- How it works
- Supported sources
- Requirements
- Installation
- Configuration
- Options
- Removal
- Sensors
- Parcel status reference
- Events
- Examples
- Known limitations
- Disclaimer
- Contributing
- License
- A single dashboard card that shows how many parcels you expect today across DHL, PostNL, DPD and GLS without juggling per-carrier sensors.
- Carrier-agnostic automations โ write one trigger like "when any parcel is out for delivery" instead of three per-carrier copies.
- Automations like "announce when a parcel is awaiting pickup at a service point" or "remind me an hour before the earliest delivery" that you write once and they cover every carrier.
- A unified parcel list you can iterate over in templates or custom cards.
The aggregator does not talk to any carrier API itself. It reads the sensors and events the per-carrier integrations already publish and exposes:
- Summed count sensors with a per-carrier breakdown on the attributes
- A unified
parcel_aggregator_parcel_*event stream so one automation can react to any carrier
Carriers you have not installed are silently skipped. If you add a carrier integration later, the aggregator picks up its sensors automatically โ no reload needed.
| Integration | Repository |
|---|---|
| DHL NL | peternijssen/ha-dhl-nl |
| PostNL | peternijssen/ha-postnl |
| DPD | peternijssen/ha-dpd |
| GLS | peternijssen/ha-gls |
- Home Assistant 2024.7 or newer
- At least one of the supported carrier integrations installed and authenticated
- Open HACS โ Integrations โ โฎ โ Custom repositories
- Add this repository URL and select category Integration
- Search for Parcel Aggregator and install it
- Restart Home Assistant
- Copy the
parcel_aggregatorfolder into yourconfig/custom_components/directory - Restart Home Assistant
- Go to Settings โ Devices & Services โ Add Integration
- Search for Parcel Aggregator
- The entry is created immediately โ no credentials needed
The aggregator discovers source entities at setup time and keeps watching the entity registry, so carrier integrations you add or remove later are picked up automatically.
This integration has no configurable options. It auto-discovers carrier source sensors (also when a carrier is installed later) and listens for state-change events from them.
Standard HA removal applies: Settings โ Devices & Services โ Parcel Aggregator โ โฎ โ Delete. No external cleanup is needed; deleting the config entry stops the state-change subscriptions and the event re-emit. The per-carrier integrations are not affected.
| Entity | Description |
|---|---|
sensor.parcel_aggregator_incoming_parcels |
Sum of active incoming parcels across all carriers; merged parcel list on the parcels attribute |
sensor.parcel_aggregator_outgoing_parcels |
Sum of active outgoing parcels across all carriers; merged list on the parcels attribute |
sensor.parcel_aggregator_delivered_parcels |
Sum of recently delivered incoming parcels across all carriers (uses each carrier's own filter window); merged list on parcels |
sensor.parcel_aggregator_outgoing_delivered_parcels |
Sum of recently delivered outgoing parcels across all carriers; merged list on parcels |
sensor.parcel_aggregator_awaiting_pickup |
Sum of active incoming parcels destined for a pickup point (ServicePoint / PostNL Point / ParcelShop); merged list on parcels |
sensor.parcel_aggregator_next_delivery |
Earliest expected delivery datetime across all carriers; the matching parcel on the parcel attribute |
Every sensor exposes a by_carrier attribute with the per-carrier breakdown โ handy for dashboard cards like "5 incoming (2 DHL ยท 3 PostNL)".
The parcels attribute on each summary sensor contains every parcel from every installed carrier in the carrier-agnostic shape:
| Key | Type | Meaning |
|---|---|---|
carrier |
string | "DHL", "PostNL", "DPD", or "GLS" |
barcode |
string | Parcel tracking number |
sender |
string | null | Sender name (e.g. webshop) |
receiver |
string | null | Recipient name |
status |
ParcelStatus |
Canonical status โ see the status reference |
raw_status |
string | null | Original carrier-specific status string |
delivered |
bool | Whether the parcel has been delivered |
delivered_at |
ISO 8601 | null | Delivery moment, if known |
planned_from |
ISO 8601 | null | Expected delivery window start |
planned_to |
ISO 8601 | null | Expected delivery window end |
pickup |
bool | Destined for a pickup point rather than a home address |
pickup_point |
string | null | ServicePoint / Point / ParcelShop name when pickup is true |
url |
string | null | Deep link to the parcel's tracking page |
weight |
float | null | Parcel weight in kilograms. May be null depending on what the carrier exposes. |
dimensions |
dict | null | Parcel dimensions in centimeters: {length, width, height, text} where text is a pre-formatted "L x W x H cm" string. May be null depending on the carrier. |
history |
list | null | Ordered status timeline (oldest โ newest), each entry {timestamp, status, raw_status}. null unless the source carrier integration has its Parcel history option enabled โ it is opt-in and off by default on each carrier. |
The carrier-specific raw payload is omitted to keep attribute size small. Open the per-carrier sensor if you need the original payload.
status on every parcel is one of the canonical ParcelStatus values below. Use these in your automations rather than carrier-specific raw strings โ the raw value stays available on raw_status for power users.
status |
Meaning |
|---|---|
registered |
Carrier knows about the label but the parcel is not yet in transit |
in_transit |
Picked up; somewhere in the carrier's network |
out_for_delivery |
On the delivery vehicle today |
at_pickup_point |
Arrived at the chosen ServicePoint / PostNL Point / ParcelShop, ready to be collected |
delivered |
Handed over to the recipient, mailbox, neighbour, or picked up |
returning |
Failed delivery, on the way back to the sender |
problem |
Carrier reports an exception, intervention, or other issue |
unknown |
Raw status/category the carrier integration has not mapped yet |
Each carrier has its own raw-status mapping โ see the per-carrier READMEs.
Unified events on the HA event bus let one automation react to changes from any carrier.
| Event | When | Payload |
|---|---|---|
parcel_aggregator_parcel_registered |
A carrier announces a new parcel | The full parcel dict (see the table above) |
parcel_aggregator_parcel_status_changed |
A known parcel's status value changes |
Same payload plus old_status and new_status |
parcel_aggregator_parcel_delivery_time_changed |
A known parcel's expected delivery time changes to a new value | Same payload plus old_planned_from, new_planned_from, old_planned_to, new_planned_to |
parcel_aggregator_outgoing_parcel_status_changed |
A known outgoing parcel (something you sent) changes status, except the final hop to delivered | Same payload plus old_status and new_status |
parcel_aggregator_outgoing_parcel_delivered |
An outgoing parcel reaches the recipient | The full parcel dict |
See examples/automations/ for ready-to-paste carrier-agnostic event automations.
Ready-to-paste carrier-agnostic automations live in examples/.
Third-party cards that work with these sensors:
- The
next_deliverytimestamp is only as precise as the underlying carrier exposes. DPD gives a day window (midnight to midnight) until Follow My Parcel fires shortly before delivery โ then it narrows to an hour window. Use it for "today/tomorrow" alerts rather than counting on precise hour windows being available all day. - The
awaiting_pickupsensor counts every parcel destined for a pickup point, including ones that are still en route. DHL exposes a distinctat_pickup_pointstatus on the parcel dict for parcels that have actually arrived at the pickup point โ DPD's API does not surface this signal yet. The sensor stays on the lowest-common-denominator semantics for now.
This is an independent, community-built project with no affiliation, endorsement, or connection to DHL, PostNL, DPD, GLS, or any of their subsidiaries.
Pull requests and issues are welcome. Please open an issue before submitting a large change.
MIT