17Track l'interface qui manque

Bonjour, c’est encore moi…
l’intégration 17Track (Seventeen track) a été intégrée dans HA. Je l’utilisais avant, mais j’avais le même soucis que maintenant.

17Track mais quoi qu’est-ce ???

c’est un outil de tracking de colis, international, accessible par le web ou par des app pour smartphones.
il suffit d’un login et d’un password pour pouvoir suivre jusqu’à 40 colis, avec plein de transporteurs différents. au-delà de 40, c’est payant. mais j’ai jamais dépassé 40, tout ce qui est « livré » je clique sur archivage et ce n’est plus comptabilisé.

on colle le numéro de tracking via le web ou son smartphone, on le voit dans toutes les autres devices.

ca marche pour les colis ali-express avec cainao, la poste, dpd, ups, asendia, fedex et la plupart des transporteurs des différents pays. il n’y a que mondial relais qui’il n’a pas trouvé…

mais coté interface HA, c’est pas terrible

type: markdown
title: Packages in transit
content: >
  {% for package in
  states.sensor.seventeentrack_packages_in_transit.attributes.packages %}

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

  {% endfor %}

et basta.
mais impossible d’afficher plusieurs colonnes avec des colis en attente, en livraison etc…

j’ai testé l’état

mais impossible d’intégrer ca dans une carte conditionnelle:

le state doit être 0 ou 1(ou plus), pas unavailable ou unknown… je pige pas là ???

Oui ça fait malheureusement partie des intégrations abandonnées depuis longtemps :frowning: Elle a jamais évoluée vraiment et reste très rustique et surtout le fait de pas pouvoir ajouter des colis depuis HA c’est super pénible je trouve :frowning:

Bon, qu’elle ne permette pas d’ajouter les entrées depuis HA, c’est dommage, mais qu’elle me pourrisse les logs parceque je n’arrive pas à parser ses données et afficher un tableau récapitulatif trié par état, ca me gonfle…

ca m’a quand même permis d’aller récupérer un colis à la poste centrale qui allait être renvoyé à l’expéditeur aux States car le facteur a eu peur de se faire engueuler parce qu’il y avait des droits de douane à demander. il a préféré dire que je n’avais pas voulu du colis, alors qu’il n’a même pas sonné à la porte…

j’ai peut être cette carte qui a l’air de marcher… si le cœur vous en dit !!!

type: vertical-stack
cards:
  - type: conditional
    conditions:
      - condition: state
        entity: sensor.seventeentrack_packages_not_found
        state_not: '0'
    card:
      type: markdown
      content: >-
        {% for package in
        states.sensor.seventeentrack_packages_not_found.attributes.packages %}
        >- <ha-icon icon="mdi:timer-sand"></ha-icon><font color= grey> **{{
        package.friendly_name }} ({{ package.tracking_number }})</font>:** {{
        package.info_text }} {% endfor %}
      title: En attente
  - type: conditional
    conditions:
      - condition: state
        entity: sensor.seventeentrack_packages_in_transit
        state_not: '0'
    card:
      type: markdown
      content: >-
        {% for package in
        states.sensor.seventeentrack_packages_in_transit.attributes.packages %}
        >- <ha-icon icon="mdi:airplane"></ha-icon><font color= Deepskyblue> **{{
        package.friendly_name }} ({{ package.tracking_number }})</font>:** {{
        package.info_text }} {% endfor %}
      title: En Transit
  - type: conditional
    conditions:
      - condition: state
        entity: sensor.seventeentrack_packages_ready_to_be_picked_up
        state_not: '0'
    card:
      type: markdown
      content: >-
        {% for package in
        states.sensor.seventeentrack_packages_ready_to_be_picked_up.attributes.packages
        %} >- <ha-icon icon="mdi:flag-outline"></ha-icon><font color= royalblue>
        **{{ package.friendly_name }} ({{ package.tracking_number }})</font>:**
        {{ package.info_text }} {% endfor %}
      title: En livraison
  - type: conditional
    conditions:
      - condition: state
        entity: sensor.seventeentrack_packages_delivered
        state_not: '0'
    card:
      type: markdown
      content: >-
        {% for package in
        states.sensor.seventeentrack_packages_delivered.attributes.packages %}
        >- <ha-icon icon="mdi:check"></ha-icon><font color= limegreen> **{{
        package.friendly_name }} ({{ package.tracking_number }})</font>:** {{
        package.info_text }} {% endfor %}
      title: Livré
  - type: conditional
    conditions:
      - condition: state
        entity: sensor.seventeentrack_packages_undelivered
        state_not: '0'
    card:
      type: markdown
      content: >-
        {% for package in
        states.sensor.seventeentrack_packages_undelivered.attributes.packages %}
        >- <ha-icon icon="mdi:alert-box"></ha-icon><font color= red> **{{
        package.friendly_name }} ({{ package.tracking_number }})</font>:** {{
        package.info_text }} {% endfor %}
      title: Erreur de Livraison

Salut,
Configuration de la carte Markdown:

{% set status = [
  {
      "sensor": "seventeentrack_packages_ready_to_be_picked_up",
      "icon": "mdi:flag",
      "order": 2
  },
  {
      "sensor": "seventeentrack_packages_not_found",
      "icon": "mdi:timer-sand-empty",
      "order": 6
  },
  {
      "sensor": "seventeentrack_packages_expired",
      "icon": "mdi:restore-alert",
      "order": 1
  },
  {
      "sensor": "seventeentrack_packages_undelivered",
      "icon": "mdi:alert-decagram",
      "order": 3
  },
  {
      "sensor": "seventeentrack_packages_in_transit",
      "icon": "mdi:truck-fast",
      "order": 4
  },
  {
      "sensor": "seventeentrack_packages_returned",
      "icon": "mdi:alert",
      "order": 5
  },
  {
      "sensor": "seventeentrack_packages_delivered",
      "icon": "mdi:package",
      "order": 1
  }
]
%}
{% set cellphone_text = '<ha-icon icon="mdi:cellphone" style="color:yellow"></ha-icon>' %}
{% set computer_text = '<ha-icon icon="mdi:laptop" style="color:yellow"></ha-icon>' %}

# **[17TRACK](https://buyer.17track.net/en/myshipment)** [{{cellphone_text}}](https://m.17track.net/en/track)

{%- for state in status|sort(attribute="order") %}

{%- if states['sensor'][state.sensor].state != '0' %}

## {{ states['sensor'][state.sensor]['attributes']['friendly_name'] }}

---
{%- for package in states['sensor'][state.sensor]['attributes']['packages']|sort(attribute="friendly_name") %}

### <ha-icon icon="{{ state.icon }}" style="color:yellow"></ha-icon> **{{ package.friendly_name }}** [{{computer_text}}](https://buyer.17track.net/en/myshipment?ob=1&Item={{package.tracking_number}}) [{{cellphone_text}}](https://m.17track.net/en/track-details?nums={{package.tracking_number}})

> **Tracking**: `{{package.tracking_number}}` 
{%- if package.info_text != None %}
> **Informations**: {{ package.info_text }} {% endif -%} 
{%- if package.location | length != 0 %} 
> **Location** : {{package.location}} {% endif -%} 
{%- if package.timestamp | string | length > 4 %} 
> **Update**: {{ relative_time(as_local(strptime(package.timestamp|string,'%Y-%m-%d %H:%M:%S%z'))) }} {% endif -%}

{% endfor %}
{% endif -%}
{%- endfor %}

17tracks

1 « J'aime »

Pourquoi utiliser « Entity State » au lieu du « Numeric State » ? … :face_with_raised_eyebrow:

Le Entity State, c’est : « unavailable » ou « unknown »
Le Numeric State, c’est de 0 à …

Ah oui, c’est joli !!!

Moi j’utilise une card markdown avec le code suivant :

{% set data = namespace(packages=[]) %}
{% set state = namespace(icon={
  "intransit":"mdi:road-variant",  "returned":"mdi:backup-restore" ,   
  "notfound":"mdi:help-rhombus-outline",
  "delivered":"mdi:mailbox-outline",
  "undelivered":"mdi:keyboard-return",
  "expired":"mdi:lock-clock",
  "readytobepickedup":"mdi:store-search-outline"
})
%}

{%
  set packages_raw = states['sensor'] | selectattr('attributes.attribution', 'defined') | selectattr("entity_id", "search", "^sensor.seventeentrack_package_")
%}

{% for package_raw in packages_raw %}

  {% set element = namespace(attributes=[], urgent=0, new=0) %}

  {% set icon_found = state.icon[package_raw.state|lower|replace(" ", "")] %}

  {% if "info_text" in package_raw.attributes %}
    {% if "airline" in package_raw.attributes.info_text|string %}
      {% set icon_found = 'mdi:airplane' %}
    {% elif "Export clearance" in package_raw.attributes.info_text|string %}
      {% set icon_found = 'mdi:account-tie-hat-outline' %}
    {% elif "Arrive attransit country" in package_raw.attributes.info_text|string %}
      {% set icon_found = 'mdi:truck-check' %}
    {% elif "local delivery company" in package_raw.attributes.info_text|string %}
      {% set icon_found = 'mdi:truck-fast-outline' %}
      {% set element.urgent = 1 %}
   {% endif %}

  {% endif %}

  {% set content = '"package_icon":"' + (icon_found) + '"' %}
  {% set element.attributes = element.attributes + [content|string] %}

  {% set content = '"entity_id":"' + (package_raw.entity_id|string) + '"' %}
  {% set element.attributes = element.attributes + [content|string] %}

  {% set content = '"status":"' + (package_raw.state|string) + '"' %}
  {% set element.attributes = element.attributes + [content|string] %}

  {% set content = '"last_updated":"' + (package_raw.last_updated|string) + '"' %}
  {% set element.attributes = element.attributes + [content|string] %}

  {% set content = '"last_changed":"' + (package_raw.last_changed|string) + '"' %}
  {% set element.attributes = element.attributes + [content|string] %}

  {% for attribute in package_raw.attributes %}
    {% set content = '"' + attribute + '":"' + (package_raw.attributes[attribute]|string).replace('"','') + '"' %}
    {% set element.attributes = element.attributes + [content|string] %}

    {% if attribute == 'timestamp' and package_raw.attributes['timestamp'] is none %}
      {% set element.urgent = 1 %}

    {% elif attribute == 'timestamp' %}

        {% if (states('sensor.timestamp')|int - as_timestamp(package_raw.attributes['timestamp'])|int) < 3600*24 %}
          {% set element.new = 1 %}
        {% endif %}

    {% endif %}

  {% endfor %}

  {% set data.packages = data.packages + [("{" + (element.attributes|join(', ')) + ', "urgent":' + element.urgent|string + ', "new":' + element.new|string + '}') | from_json ] %}
    
{% endfor %}

{% if data.packages is not none %}

{% set current_idx = namespace(value=0) %}

{% for package in data.packages|sort(attribute="urgent,timestamp", reverse=True) %}

  ### <center>{{ package.tracking_number }} : {{ package.friendly_name.replace('Seventeentrack Package:', '') }}</center>

  {% if package.status == '--Not Found' %}
  <ha-alert alert-type="error">Package is {{ package.status|lower }}. Please verify with the package sender and check back later. </ha-alert>
  {% else %}

  {% set parcel_time = "undeterminated" %}

  {% if package.timestamp != 'None' %}
    {% set parcel_time = as_timestamp(package.timestamp, '%Y-%m-%d %H:%M:%S+00:00') | timestamp_custom("%Y-%m-%d %H:%M") %}
  {% endif %}

  {% set new_icon = '' %}

  {% if package.new == 1 %}
    {% set new_icon = '<font color="#CD5C5C"><ha-icon icon="mdi:new-box"></ha-icon></font>' %}
  {% endif %}

  <font color="#40749C"><ha-icon icon="mdi:calendar"></ha-icon></font> [{{ parcel_time }}] {{ new_icon }}

  <font color="#40749C"><ha-icon icon="{{ package.package_icon }}"></ha-icon></font> {{ package.status }} - {{ package.info_text }}

  {% endif %}

  ##### <p style="text-align: right">Suivi : <a href="https://parcelsapp.com/en/tracking/{{ package.tracking_number }}">parcelsapp.com</a></p>

  {% set current_idx.value = current_idx.value|int + 1 %}

  {% if current_idx.value < (data.packages|length) %}
  ---
  {% endif %}

{% endfor %}

{% else %}
    <ha-alert alert-type="success">No package to monitor.</ha-alert>
{% endif %}

Il y a sans doute du code redondant et plus d’actualité.

Peut être parce que je savais pas quoi mettre ??? :crazy_face:

je connais mieux le shell que le jinja :ninja:

Ca avance !!!


j’ai sorti quelques entrées de l’archivage pour avoir plus de data à moudre !!!

{% for package in states.sensor.seventeentrack_packages_in_transit.attributes.packages %} >- <ha-icon icon="mdi:airplane"></ha-icon><font color= Deepskyblue> **{{ package.friendly_name }} ({{ package.tracking_number }})</font>:** {{ package.info_text }} {% endfor %}

la premiere ligne commence bien avec un . car il interprète bien le >- mais il n’est pas interprété par les lignes suivantes : warehouse >- M5 C

- friendly_name: Lilygo
  info_text: 'Received by warehouse, Carrier note: Received by warehouse'
  timestamp: '2024-04-15T06:18:00+00:00'
  status: In Transit
  location: ''
  tracking_number: CNFR9000000000096HD
- friendly_name: M5 C
  info_text: Processing at warehouse, Carrier note
  timestamp: '2024-04-15T08:11:00+00:00'
  status: In Transit
  location: ''
  tracking_number: CNFR9000000000057HD

comment je pourrais insérer un CR ou un LF avant le {% endfor %} ???

Salut,
j’ai fais un tableau avec flex-card au début, puis j’ai utiliser une carte markdown après.

@bentou
Hum un M5 Core ?

non, un M5 Cadran … :wink:
image

1 « J'aime »

J’ai trouvé ce github pour le M5 Dial avec ESPHome :wink:
Du coup, je me laisserais bien tenter par ce M5 Dial.

Ah, ca peut être intéressant…

faudra attendre qu’un designer un peu moins « teuton » se mette sur l’affaire :rofl:

bon, sinon je suis sur la carte flex-table. mais je suis comme avec une huitre, d’un coté j’ai un include et de l’autre une colonne… où c’est que je mets le couteau ???

Voici le code de ma carte, si ca peu t’aider .

                      type: custom:flex-table-card
                      max_rows: 4
                      sort_by: timestamp-
                      clickable: true
                      entities:
                        include: sensor.seventeentrack_package_*
                      columns:
                        - data: tracking_number
                          icon: mdi:package-variant-closed
                          align: center
                          name: ' Numéro de suivi'
                        - name: Produits
                          data: friendly_name
                          align: center
                        - data: origin_country
                          name: Pays Origine
                          align: center
                        - data: destination_country
                          name: Pays Destination
                          align: center
                        - data: state
                          align: center
                          name: Statut
                        - data: info_text
                          name: Infos
                          align: center
                        - data: timestamp
                          align: center
                          name: Mise à jour
                          modify: >-
                            const hourDiff = (Date.now() - Date.parse(x)); const
                            secDiff = hourDiff / 1000; const minDiff = hourDiff
                            / 60 / 1000; const hDiff = hourDiff / 3600 / 1000;
                            const hours = Math.floor(hDiff); const minutes =
                            minDiff - 60 * hours; const minr =
                            Math.floor(minutes); hours + " hours " + minr + "
                            minutes"
                          prefix: 'Depuis '
                      css:
                        thead th:nth-child(2): 'background-color: #44739e'
                        thead th:nth-child(3): 'background-color: #44739e'
                        thead th:nth-child(4): 'background-color: #44739e'
                        thead th:nth-child(5): 'background-color: #44739e'
                        thead th:nth-child(6): 'background-color: #44739e'
                        thead th:nth-child(7): 'background-color: #44739e'

Ah oui, pas mal le sensor.seventeentrack_package_*
j’y aurais pas pensé…

Merci :+1:

Juste un truc, il y a moyen de supprimer
le texte « Seventeentrack Package: » (qui vient de friendly_name: Seventeentrack Package: M5 Cadran)

sous unix, j’aurais fait un | sed s/Seventeentrack\ Package\:// et c’était joué, mais là…
ou définir le : en séparateur et ne prendre que le second argument ???

image

voila mon dashboard.
un clic long sur le logo pour l’ouverture web en mode mobile, un clic court pour l’ouvrir en mode PC.

type: vertical-stack
cards:
  - type: picture
    image: /local/images/divers/17track_296x48.svg
    tap_action:
      action: url
      url_path: https://buyer.17track.net/en/myshipment
    hold_action:
      action: url
      url_path: https://m.17track.net/en/track
  - type: conditional
    conditions:
      - condition: numeric_state
        entity: sensor.seventeentrack_packages_not_found
        above: 0
    card:
      type: markdown
      content: >-
        {% for package in
        states.sensor.seventeentrack_packages_not_found.attributes.packages %}
        >- <ha-icon icon="mdi:timer-sand"></ha-icon><font color= grey> **{{
        package.friendly_name }} ({{ package.tracking_number }})</font>:** {{
        package.info_text }} {{'\n'}} {% endfor %}
  - type: conditional
    conditions:
      - condition: numeric_state
        entity: sensor.seventeentrack_packages_in_transit
        above: 0
    card:
      type: markdown
      content: >-
        {% for package in
        states.sensor.seventeentrack_packages_in_transit.attributes.packages %}
        >- <ha-icon icon="mdi:airplane"></ha-icon><font color= Deepskyblue> **{{
        package.friendly_name }} ({{ package.tracking_number }})</font>:** {{
        package.info_text }}  {{'\n'}} {% endfor %}
  - type: conditional
    conditions:
      - condition: numeric_state
        entity: sensor.seventeentrack_packages_ready_to_be_picked_up
        above: 0
    card:
      type: markdown
      content: >-
        {% for package in
        states.sensor.seventeentrack_packages_ready_to_be_picked_up.attributes.packages
        %} >- <ha-icon icon="mdi:flag-outline"></ha-icon><font color= royalblue>
        **{{ package.friendly_name }} ({{ package.tracking_number }})</font>:**
        {{ package.info_text }} {{'\n'}} {% endfor %}
  - type: conditional
    conditions:
      - condition: numeric_state
        entity: sensor.seventeentrack_packages_delivered
        above: 0
    card:
      type: markdown
      content: >-
        {% for package in
        states.sensor.seventeentrack_packages_delivered.attributes.packages %}
        >- <ha-icon icon="mdi:check"></ha-icon><font color= limegreen> **{{
        package.friendly_name }} ({{ package.tracking_number }})</font>:** {{
        package.info_text }} {{'\n'}} {% endfor %}
  - type: conditional
    conditions:
      - condition: numeric_state
        entity: sensor.seventeentrack_packages_returned
        above: 0
    card:
      type: markdown
      content: >-
        {% for package in
        states.sensor.seventeentrack_packages_returned.attributes.packages %} >-
        <ha-icon icon="mdi:alert-box"></ha-icon><font color= red> **{{
        package.friendly_name }} ({{ package.tracking_number }})</font>:** {{
        package.info_text }} {{'\n'}} {% endfor %}
  - type: conditional
    conditions:
      - condition: numeric_state
        entity: sensor.seventeentrack_packages_undelivered
        above: 0
    card:
      type: markdown
      content: >-
        {% for package in
        states.sensor.seventeentrack_packages_undelivered.attributes.packages %}
        >- <ha-icon icon="mdi:alert-box"></ha-icon><font color= red> **{{
        package.friendly_name }} ({{ package.tracking_number }})</font>:** {{
        package.info_text }} {{'\n'}} {% endfor %}
  - type: conditional
    conditions:
      - condition: numeric_state
        entity: sensor.seventeentrack_packages_expired
        above: 0
    card:
      type: markdown
      content: >-
        {% for package in
        states.sensor.seventeentrack_packages_expired.attributes.packages %} >-
        <ha-icon icon="mdi:alert-box"></ha-icon><font color= red> **{{
        package.friendly_name }} ({{ package.tracking_number }})</font>:** {{
        package.info_text }} {{'\n'}} {% endfor %}

et pour l’image, c’est celle du site (full_owt_296x48.svg) renommée.

1 « J'aime »

Lilygo :+1: :heart_eyes:
Tu vois avoir du boulot.