Awesome 17Track card!

Hello everyone!

My web design creativity is a little bit limp :yum:
So does anyone have a good looking card for 17Track sensor with package details?

Looking forward for your examples.

Why not just use a simple monster card?

Screenshot%20from%202019-01-28%2020-04-31

type: 'custom:monster-card'
card:
  type: entities
  title: 17track.net
  show_header_toggle: false
filter:
  include:
    - entity_id: sensor.seventeentrack_package_*

Could be beautified, but for the moment it’s working and displaying any newly added packages from my 17track account

1 Like

Will take a look.

This is what I have been using

type: markdown
content: |2-
    {% if is_state('sensor.seventeentrack_packages_in_transit', '0') %}
  **Nothing Is In Transit**
    {% else %}
  **In Transit**
    {% for package in
    states.sensor.seventeentrack_packages_in_transit.attributes.packages %}

    >- **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{
    package.info_text }}

    {% endfor %}
    {% endif %}
    
    {% if is_state('sensor.seventeentrack_packages_ready_to_be_picked_up', '0') %}
  **Nothing Is Out For Delivery**
    {% else %}
  **Out For Delivery**
   
    {% for package in
    states.sensor.seventeentrack_packages_ready_to_be_picked_up.attributes.packages %}

    >- **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{
    package.info_text }}

    {% endfor %}
    {% endif %}

    {% if is_state('sensor.seventeentrack_packages_delivered', '0') %}
  **Nothing Is Delivered**
    {% else %}
  **Delivered**
    {% for package in
    states.sensor.seventeentrack_packages_delivered.attributes.packages %}

    >- **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{
    package.info_text }}

    {% endfor %}
    {% endif %}
title: 17Track Packages

I added some icons.

type: markdown
content: |2-

      {% if is_state('sensor.seventeentrack_packages_in_transit', '0') %}
    <ha-icon icon="mdi:transit-connection-variant"></ha-icon>  - **Nothing Is In Transit**
      {% else %}
    <ha-icon icon="mdi:transit-connection-variant"></ha-icon>  - **In Transit**
      {% for package in
      states.sensor.seventeentrack_packages_in_transit.attributes.packages %}

  >- **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{
      package.info_text }}

      {% endfor %}
      {% endif %}
      
      {% if is_state('sensor.seventeentrack_packages_ready_to_be_picked_up', '0') %}
    **<ha-icon icon="mdi:truck-delivery"></ha-icon>  - Nothing Is Out For Delivery**
      {% else %}
    **<ha-icon icon="mdi:truck-delivery"></ha-icon>  - Out For Delivery**
     
      {% for package in
      states.sensor.seventeentrack_packages_ready_to_be_picked_up.attributes.packages %}

  >- **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{
      package.info_text }}

      {% endfor %}
      {% endif %}

      {% if is_state('sensor.seventeentrack_packages_delivered', '0') %}
    **<ha-icon icon="mdi:package-variant-closed-check"></ha-icon> - Nothing Is Delivered**
      {% else %}
    **<ha-icon icon="mdi:package-variant-closed-check"></ha-icon> - Delivered**
      {% for package in
      states.sensor.seventeentrack_packages_delivered.attributes.packages %}

      >- **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{
      package.info_text }}

      {% endfor %}
      {% endif %}

      
title: Deliveries

1 Like

I added some code for not found

type: markdown
content: |2-

      {% if is_state('sensor.seventeentrack_packages_in_transit', '0') %}
    <ha-icon icon="mdi:transit-connection-variant"></ha-icon>  - **Nothing Is In Transit**
      {% else %}
    <ha-icon icon="mdi:transit-connection-variant"></ha-icon>  - **In Transit**
      {% for package in
      states.sensor.seventeentrack_packages_in_transit.attributes.packages %}

  >- **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{
      package.info_text }}

      {% endfor %}
      {% endif %}
      
      {% if is_state('sensor.seventeentrack_packages_ready_to_be_picked_up', '0') %}
    **<ha-icon icon="mdi:truck-delivery"></ha-icon>  - Nothing Is Out For Delivery**
      {% else %}
    **<ha-icon icon="mdi:truck-delivery"></ha-icon>  - Out For Delivery**
     
      {% for package in
      states.sensor.seventeentrack_packages_ready_to_be_picked_up.attributes.packages %}

  >- **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{
      package.info_text }}

      {% endfor %}
      {% endif %}

      {% if is_state('sensor.seventeentrack_packages_delivered', '0') %}
    **<ha-icon icon="mdi:package-variant-closed-check"></ha-icon> - Nothing Is Delivered**
      {% else %}
    **<ha-icon icon="mdi:package-variant-closed-check"></ha-icon> - Delivered**
      {% for package in
      states.sensor.seventeentrack_packages_delivered.attributes.packages %}

      >- **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{
      package.info_text }}

      {% endfor %}
      {% endif %}

      {% if is_state('sensor.seventeentrack_packages_not_found', '0') %}
    <ha-icon icon="mdi:alert"></ha-icon>  - **Nothing Not Found**
      {% else %}
    <ha-icon icon="mdi:alert"></ha-icon>  - **Not Found**
      {% for package in
      states.sensor.seventeentrack_packages_not_found.attributes.packages %}

  >- **{{ package.tracking_number }}**

      {% endfor %}
      {% endif %}
      

      
title: Deliveries

I’ll continue this chain of forum-based version management with my iteration :smile:

{% macro package_display(package) %}
  {% set detail_sensor_name = 'sensor.17track_package_' + package.tracking_number | lower %}

  {% if not is_state(detail_sensor_name, 'unknown') %}
  - **<a target="_blank" rel="noopener noreferrer" href="https://www.17track.net/?nums={{ state_attr(detail_sensor_name, 'tracking_number') }}">{{ state_attr(detail_sensor_name, 'friendly_name') }}</a>** ({{ relative_time(state_attr(detail_sensor_name, 'timestamp')) }} ago)
     {{ state_attr(detail_sensor_name, 'origin_country') }} › {{ state_attr(detail_sensor_name, 'destination_country') }}
     {{ state_attr(detail_sensor_name, 'location') }}: {{ state_attr(detail_sensor_name, 'info_text') }}
  {% endif %}
{% endmacro %}

{% if not is_state('sensor.17track_packages_in_transit', '0') %}
  <ha-icon icon="mdi:transit-connection-variant"></ha-icon> **In Transit**

  {% for package in state_attr('sensor.17track_in_transit', 'packages') %}
    {{ package_display(package) }}
  {% endfor %}
{% endif %}

{% if not is_state('sensor.17track_ready_to_be_picked_up', '0') %}
  <ha-icon icon="mdi:truck-delivery"></ha-icon> **Out For Delivery**

  {% for package in state_attr('sensor.17track_ready_to_be_picked_up', 'packages') %}
    {{ package_display(package) }}
  {% endfor %}
{% endif %}

{% if not is_state('sensor.17track_delivered', '0') %}
  <ha-icon icon="mdi:package-variant-closed-check"></ha-icon> **Delivered**

  {% for package in state_attr('sensor.17track_delivered', 'packages') %}
    {{ package_display(package) }}
  {% endfor %}
{% endif %}

{% if not is_state('sensor.17track_not_found', '0') %}
  <ha-icon icon="mdi:alert"></ha-icon> **Not Found**
  
  {% for package in state_attr('sensor.17track_not_found', 'packages') %}
    {{ package_display(package) }}
  {% endfor %}
{% endif %}

Hi guys,

Any suggestions on how to achieve this, now that sensors are deprecated and we only have the seventeentrack.get_packages action, that, as far as I can tell, can’t be called from within the template?

2 Likes

I have risen to the challenge and created an automation that fills helper variable with the content I want, which I can then use in a Markdown card.

So first, create a helper called input_text.parcels here: Link to Helpers – My Home Assistant
I have given it the icon mdi:package-variant and a maximum length of 50000.

Then, create an automation that will fill this variable. This is the raw automation yaml:

alias: Parcel Check
description: ""
trigger: []
condition: []
action:
  - action: seventeentrack.get_packages
    metadata: {}
    data:
      config_entry_id: 0123456789
      package_state:
        - in_transit
    response_variable: transit
  - action: seventeentrack.get_packages
    metadata: {}
    data:
      config_entry_id: 0123456789
      package_state:
        - not_found
    response_variable: notfound
  - action: seventeentrack.get_packages
    metadata: {}
    data:
      config_entry_id: 0123456789
      package_state:
        - ready_to_be_picked_up
    response_variable: outfordelivery
  - action: seventeentrack.get_packages
    metadata: {}
    data:
      config_entry_id: 0123456789
      package_state:
        - delivered
    response_variable: delivered
  - action: input_text.set_value
    metadata: {}
    data:
      value: |
        {% if transit.packages|length > 0 %}
        <ha-icon icon="mdi:transit-connection-variant"></ha-icon> in transit
        {% for package in transit.packages %}
        - **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{
        package.info_text }}
        {% endfor %}
        {% endif %}
        {% if outfordelivery.packages|length > 0 %}
        <ha-icon icon="mdi:truck-delivery"></ha-icon> out for delivery
        {% for package in outfordelivery.packages %}
        - **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{
        package.info_text }}
        {% endfor %}
        {% endif %}
        {% if notfound.packages|length > 0 %}
        <ha-icon icon="mdi:alert"></ha-icon> not found
        {% for package in notfound.packages %}
        - **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{
        package.info_text }}
        {% endfor %}
        {% endif %}
        {% if delivered.packages|length > 0 %}
        <ha-icon icon="mdi:package-variant-closed-check"></ha-icon> delivered
        {% for package in delivered.packages %}
        - **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{
        package.info_text }}
        {% endfor %}
        {% endif %}
    target:
      entity_id: input_text.parcels
mode: single

Of course you need to select your correct config_entry_id from the dropdown.

Then create a simple card with this content:

type: markdown
content: '{{states(''input_text.parcels'')}}'
title: Parcels

For testing, run the automation manually. If you want to update states regularly, simply add a time_platform trigger or other trigger of your choice.

I have not yet tested all states, but it seems to work fine.
Of course you can modify this to your liking, and add your enhanced version here :slight_smile:

3 Likes

Yeah, and it promptly failed today after adding a third package to be tracked. Looks like input_text helpers can only carry up to 255 characters, even though the UI doesn’t stop me from entering the 50000 I wanted :person_shrugging:

In order to limit myself to fewer characters, the action assigning the variable now looks like this:

action: input_text.set_value
metadata: {}
data:
  value: |
    {% if transit.packages|length > 0 %}
    ## 📤 in transit
    {% for package in transit.packages %}
    - **{{ package.friendly_name }}:** {{ package.info_text }}
    {% endfor %}
    {% endif %}
    {% if outfordelivery.packages|length > 0 %}
    ## 🚚 out for delivery
    {% for package in outfordelivery.packages %}
    - **{{ package.friendly_name }}:** {{ package.info_text }}
    {% endfor %}
    {% endif %}
    {% if notfound.packages|length > 0 %}
    ## ⚠️ not found
    {% for package in notfound.packages %}
    - **{{ package.friendly_name }}:** {{ package.info_text }}
    {% endfor %}
    {% endif %}
    {% if delivered.packages|length > 0 %}
    ## 📦 delivered
    {% for package in delivered.packages %}
    - **{{ package.friendly_name }}:** {{ package.info_text }}
    {% endfor %}
    {% endif %}
target:
  entity_id: input_text.parcels

This replaces the HA icons with unicode emojis, and removes the tracking number (I’m not interested in that anyway).
With my currently 3 packages I came up with about 215 characters (depending on friendly_name length and the info_text).

2 Likes

Yeah the 255 char limit is pretty bad. Apparently entity attributes can store 16kb, so maybe using something like GitHub - pmazz/ps_hassio_entities: Python script to handle state and attributes of existing sensors and entities it would be possible to store the markdown into an attribute on the helper variable instead?

1 Like

So, I had a go at this, and it seems to be working fine. You need to enable python_scripts in your configuration.yaml as per Python Scripts - Home Assistant, then install GitHub - pmazz/ps_hassio_entities: Python script to handle state and attributes of existing sensors and entities and then I have the automation place the markdown into a markdown attribute on each helper variable I created (as I initially created one helper variable per delivery category as an initial bodge around the 255 char limit), e.g.:

  - action: python_script.hass_entities
    metadata: {}
    data:
      action: set_state_attributes
      entity_id: input_text.parcels_out_for_delivery
      state: '{{ ''Updated at ''~ now().strftime(''%H:%M'')}}'
      attributes:
      - markdown: >-
          {% if outfordelivery.packages|length > 0 %}
          **<ha-icon icon="mdi:truck-delivery"></ha-icon> - Out for delivery**
          
          {% for package in outfordelivery.packages %}
          - **{{ package.friendly_name }} ({{ package.tracking_number }}):** {{ package.info_text }}
          {% endfor %}
          {% else %}
          **<ha-icon icon="mdi:truck-delivery"></ha-icon> - Out for delivery**
          
          {% endif %}

Then in the markdown card, I just include the markdown attributes from each helper, e.g.

{{states.input_text.parcels_delivered.attributes.markdown}}

{{states.input_text.parcels_out_for_delivery.attributes.markdown}}

{{states.input_text.parcels_in_transit.attributes.markdown}}

{{states.input_text.parcels_not_found.attributes.markdown}}
1 Like

Regarding the error,
17Track package sensors are deprecated and will be removed.
Please update your automations and scripts to get data using the seventeentrack.get_packages action

Which bit do i change i am using an entities card with a filter

  • entity_id: sensor.*track_package_
    And
  • entities:
    • entity: sensor.seventeentrack_packages_in_transit

seventeentrack.get_packages

Tia

Your code worked but I was confused by the above so for anyone else that does not understand this … After the YAML is put in for the automation go back to the Visual Editor view. Then for each item you need to set the integration you are using for the 17Track service.

2 Likes

Ended up going thru the amazing replies in here and putting together a tweaked version.
It uses the python_scripts mentioned by @Lenbok here:

To use the automation you need to create 6 text helpers with the following names:

  • parcels_not_found
  • parcels_in_transit
  • parcels_out_for_delivery
  • parcels_delivered
  • parcels_undelivered
  • parcels_alert

Here is the full automation I ended up going with:

alias: 17Track
description: Automation to fetch package status from 17Track
triggers:
  - trigger: time_pattern
    minutes: /30
conditions: []
actions:
  - action: seventeentrack.get_packages
    data:
      package_state:
        - not_found
      config_entry_id: 
    response_variable: notfound
  - action: python_script.hass_entities
    metadata: {}
    data:
      action: set_state_attributes
      entity_id: input_text.parcels_not_found
      state: "{{ 'Updated at '~ now().strftime('%H:%M')}}"
      attributes:
        - markdown: >
            ## <ha-icon icon="mdi:package-variant-remove"></ha-icon> - Not Found
            ({{notfound.packages|length}})

            {% if notfound.packages|length > 0 %}

            {% for package in notfound.packages %}  

            >- **{% if package.friendly_name|length > 0 %}{{
            package.friendly_name }}{% else %}{{package.tracking_number}}{%
            endif %}:** {{ package.info_text }}

            {% endfor %}

            {% else %}

            -

            {% endif %}
  - action: seventeentrack.get_packages
    data:
      package_state:
        - in_transit
      config_entry_id: 
    response_variable: intransit
  - action: python_script.hass_entities
    metadata: {}
    data:
      action: set_state_attributes
      entity_id: input_text.parcels_in_transit
      state: "{{ 'Updated at '~ now().strftime('%H:%M')}}"
      attributes:
        - markdown: >
            ## <ha-icon icon="mdi:airplane-clock"></ha-icon> - In Transit
            ({{intransit.packages|length}})

            {% if intransit.packages|length > 0 %}

            {% for package in intransit.packages %}  

            >- **{% if package.friendly_name|length > 0 %}{{
            package.friendly_name }}{% else %}{{package.tracking_number}}{%
            endif %}:** {{ package.info_text }}

            {% endfor %}

            {% else %}

            -

            {% endif %}
  - action: seventeentrack.get_packages
    data:
      config_entry_id: 
      package_state:
        - ready_to_be_picked_up
    response_variable: outfordelivery
  - action: python_script.hass_entities
    metadata: {}
    data:
      action: set_state_attributes
      entity_id: input_text.parcels_out_for_delivery
      state: "{{ 'Updated at '~ now().strftime('%H:%M')}}"
      attributes:
        - markdown: >
            ## <ha-icon icon="mdi:truck-delivery"></ha-icon> - Out for delivery
            ({{outfordelivery.packages|length}})

            {% if outfordelivery.packages|length > 0 %}

            {% for package in outfordelivery.packages %}  

            >- **{% if package.friendly_name|length > 0 %}{{
            package.friendly_name }}{% else %}{{package.tracking_number}}{%
            endif %}:** {{ package.info_text }}

            {% endfor %}

            {% else %}

            -

            {% endif %}
  - action: seventeentrack.get_packages
    data:
      config_entry_id: 
      package_state:
        - delivered
    response_variable: delivered
  - action: python_script.hass_entities
    metadata: {}
    data:
      action: set_state_attributes
      entity_id: input_text.parcels_delivered
      state: "{{ 'Updated at '~ now().strftime('%H:%M')}}"
      attributes:
        - markdown: >
            ## <ha-icon icon="mdi:package-check"></ha-icon> - Delivered
            ({{delivered.packages|length}})

            {% if delivered.packages|length > 0 %}

            {% for package in delivered.packages %}  

            >- **{% if package.friendly_name|length > 0 %}{{
            package.friendly_name }}{% else %}{{package.tracking_number}}{%
            endif %}:** {{ package.info_text }}

            {% endfor %}

            {% else %}

            -

            {% endif %}
  - action: seventeentrack.get_packages
    data:
      config_entry_id: 
      package_state:
        - undelivered
    response_variable: undelivered
  - action: python_script.hass_entities
    metadata: {}
    data:
      action: set_state_attributes
      entity_id: input_text.parcels_undelivered
      state: "{{ 'Updated at '~ now().strftime('%H:%M')}}"
      attributes:
        - markdown: >
            ## <ha-icon icon="mdi:archive-cancel"></ha-icon> - Undelivered
            ({{undelivered.packages|length}})

            {% if undelivered.packages|length > 0 %}

            {% for package in undelivered.packages %}  

            >- **{% if package.friendly_name|length > 0 %}{{
            package.friendly_name }}{% else %}{{package.tracking_number}}{%
            endif %}:** {{ package.info_text}}

            {% endfor %}

            {% else %}

            -

            {% endif %}
  - action: seventeentrack.get_packages
    data:
      config_entry_id: 
      package_state:
        - returned
    response_variable: alert
  - action: python_script.hass_entities
    metadata: {}
    data:
      action: set_state_attributes
      entity_id: input_text.parcels_alert
      state: "{{ 'Updated at '~ now().strftime('%H:%M')}}"
      attributes:
        - markdown: >
            ## <ha-icon icon="mdi:archive-alert"></ha-icon> - Alert
            ({{alert.packages|length}})

            {% if alert.packages|length > 0 %}

            {% for package in alert.packages %}  

            >- **{% if package.friendly_name|length > 0 %}{{
            package.friendly_name }}{% else %}{{package.tracking_number}}{%
            endif %}:** {{ package.info_text}}

            {% endfor %}

            {% else %}

            -

            {% endif %}
mode: single

I set mine to update every 30 minutes, feel free to change that around so that it suits you.

After adding the code, you need to go into visual mode and select your 17Track integration here for every action (thanks to @felafel for pointing it out):

Once that is done, just add these six individually on your lovelace as markdown cards:

{{states.input_text.parcels_undelivered.attributes.markdown}}
{{states.input_text.parcels_alert.attributes.markdown}}

End result looks something like this:

Hope this helps someone!

Edit: added counters
Edit 2: added tracking number for packages without a note
Edit 3: added Undelivered and Alert statuses

2 Likes