API TAN Nantes : création d'un capteur Rest

Bonjour,

Mon problème

Je cherche à créer un sensor REST à l’aide de l’API de la TAN qui informe des temps d’attente des bus du réseau de transport de Nantes s’arrêtant à un arrêt précis.

Par exemple, pour l’arrêt Gare Maritime : l’URL de l’API (OpenAPI) est :
https://openv2-preprod.tan.fr/ewp/tempsattente.json/GMAR
le retour de l’API donne le Json suivant :

[
  {
    "sens": 2,
    "terminus": "Gare Maritime",
    "infotrafic": false,
    "temps": "6mn",
    "dernierDepart": "false",
    "tempsReel": "true",
    "ligne": {
      "numLigne": "81",
      "typeLigne": 3
    },
    "arret": {
      "codeArret": "MIND2"
    }
  },
  {
    "sens": 1,
    "terminus": "Mendès France - Bellevue",
    "infotrafic": false,
    "temps": "16mn",
    "dernierDepart": "false",
    "tempsReel": "true",
    "ligne": {
      "numLigne": "81",
      "typeLigne": 3
    },
    "arret": {
      "codeArret": "MIND1"
    }
  },
  {
    "sens": 1,
    "terminus": "Couëron Bougon",
    "infotrafic": false,
    "temps": "",
    "dernierDepart": "false",
    "tempsReel": "false",
    "ligne": {
      "numLigne": "91",
      "typeLigne": 3
    },
    "arret": {
      "codeArret": "MIND2"
    }
  },
  {
    "sens": 1,
    "terminus": "Couëron Océan",
    "infotrafic": false,
    "temps": "",
    "dernierDepart": "false",
    "tempsReel": "false",
    "ligne": {
      "numLigne": "91",
      "typeLigne": 3
    },
    "arret": {
      "codeArret": "MIND2"
    }
  },
  {
    "sens": 1,
    "terminus": "Mairie de Couëron",
    "infotrafic": false,
    "temps": "",
    "dernierDepart": "false",
    "tempsReel": "false",
    "ligne": {
      "numLigne": "91",
      "typeLigne": 3
    },
    "arret": {
      "codeArret": "MIND2"
    }
  },
  {
    "sens": 2,
    "terminus": "Mendès France - Bellevue",
    "infotrafic": false,
    "temps": "",
    "dernierDepart": "false",
    "tempsReel": "false",
    "ligne": {
      "numLigne": "91",
      "typeLigne": 3
    },
    "arret": {
      "codeArret": "MIND1"
    }
  },
  {
    "sens": 2,
    "terminus": "François Mitterrand",
    "infotrafic": false,
    "temps": "",
    "dernierDepart": "false",
    "tempsReel": "false",
    "ligne": {
      "numLigne": "91",
      "typeLigne": 3
    },
    "arret": {
      "codeArret": "MIND1"
    }
  }
]

Il semblerait que le format Json retourné ne soit pas « lisible » par le sensor REST. Y a t il une solution pour exploiter l’API ?

Merci d’avance pour votre aide.

Ma configuration


System Information

version core-2024.12.3
installation_type Home Assistant OS
dev false
hassio true
docker true
user root
virtualenv false
python_version 3.13.0
os_name Linux
os_version 6.6.51-haos-raspi
arch aarch64
timezone Europe/Paris
config_dir /config
Home Assistant Community Store
GitHub API ok
GitHub Content ok
GitHub Web ok
HACS Data ok
GitHub API Calls Remaining 4988
Installed Version 2.0.1
Stage running
Available Repositories 1549
Downloaded Repositories 11
Home Assistant Cloud
logged_in false
can_reach_cert_server ok
can_reach_cloud_auth ok
can_reach_cloud ok
Home Assistant Supervisor
host_os Home Assistant OS 14.0
update_channel stable
supervisor_version supervisor-2024.12.0
agent_version 1.6.0
docker_version 27.2.0
disk_total 28.6 GB
disk_used 14.5 GB
healthy true
supported true
host_connectivity true
supervisor_connectivity true
ntp_synchronized true
virtualization
board rpi5-64
supervisor_api ok
version_api ok
installed_addons Spotify Connect (0.13.0), Advanced SSH & Web Terminal (19.0.0), Linky (1.5.0), Mosquitto broker (6.4.1), Studio Code Server (5.17.3), Nginx Proxy Manager (1.0.1), Duck DNS (1.18.0), Zigbee2MQTT (1.42.0-2), Matter Server (6.6.1)
Dashboards
dashboards 4
resources 2
views 12
mode storage
Recorder
oldest_recorder_run 8 décembre 2024 à 00:47
current_recorder_run 17 décembre 2024 à 16:55
estimated_db_size 77.74 MiB
database_engine sqlite
database_version 3.45.3

Salut

:thinking:
Pourquoi dis-tu ça ?

J’y arrive très bien :

image

1 « J'aime »

Et bien, je suis débutant en YAML, mais lorsque je definis le capteur rest avec le script suivant cela ne marche pas :
est:

# TAN Departures from Gare Maritime
  - resource: https://open.tan.fr/ewp/tempsattente.json/GMAR
    scan_interval: 60
    sensor:
      - name: TAN Next Departure Gare Maritime
        value_template: >
          {% set departures = value_json['departures'] %}
          {% if departures | length >= 1 %}
            {% set dep1 = departures[0]['temps'] %}
            {{ map(attribute='temps') }}
          {% else %}
            No upcoming departures
          {% endif %}
        json_attributes:
          - departures

Après, je souhaiterais exploiter le capteur pour créer des cartes qui filtre les délais d’attente en fonction des numéros de bus…

Bonjour, j’utilises la platform pour interroger la Tan depuis 3 ans et cela fonctionne bien voici mon code:
il suufit de changer RDNT2 par GMAR

 - platform: rest
   value_template: >-
    {{ value_json.1.ligne.numLigne + " " + value_json.1.temps }}
    
   resource: http://open.tan.fr/ewp/tempsattente.json/RDNT2
   name: bus_tan_a
   unique_id: bus_tan_a
   json_attributes:
    - temps
    - terminus
   scan_interval: 30
   timeout: 30
   force_update: true

ensuiite j’ai créée des entrées en fonction des besoins , j’ai meme une carte

le code:

type: custom:banner-card
background: "#468239"
row_size: 2
heading:
  - mdi:bus
  - TAN - C4
  - mdi:bus
entities:
  - entity: sensor.bus_tan_depart
    name: Arrêt
    attribute: friendly_name
    size: 2
  - entity: sensor.bus_tan_a
    name: Destination
    attribute: terminus
    size: 2
  - entity: sensor.bus_tan_imm
    name: Prochain passage
  - entity: sensor.bus_tan_prochain
    name: Passage suivant
card_mod:
  style: |
    ha-card {
      --ha-card-border-radius: 10px;
    }

Bonjour à tous,

Je suis également passé par l’API de la TAN, en passant par des sensors REST côté HA.
Dans mon cas, il m’arrivait régulièrement d’avoir des erreurs, et cela venait de l’API qui parfois ne renvoyait pas d’infos ou alors l’URL mettait trop de temps à charger, même en jouant sur le timeout côté REST.

Donc j’ai abandonné cette méthode et je passe directement par le plug-in GTFS2, j’ai donc téléchargé la base de données des horaires de bus du réseau TAN et depuis plus d’erreurs/bugs. Ça reste en local donc je ne dépends plus de leur API.

Point négatif : j’ai maintenant les horaires « théoriques » et non plus ceux en temps réel. Mais si cela me manque à l’avenir, rien ne m’empêchera de créer un sensor REST basé sur leur API (même si ça bug parfois) en plus de la base de données.

Bonjour Patrick,
Merci pour ton retour.
Mais comment fais tu lorsque l’arrêt dessert plusieurs lignes ? En effet, pour mon cas, je cherche à récupérer que les temps d’attente uniquement pour le bus 81 et dans le sens 1 ?

le premier capteur Rest me permettait de récupérer l’ensemble des informations sur l’arret puis un deuxième capteur de type Template aurait pu me filtrer uniquement les temps d’attente d’une certaine ligne dans un certain sens.

Bonjour Giga,

Merci pour ta réponse.
Effectivement, je voie bien que tu as réussi à mettre dans un attribut le premier élément du json qui correspond au prochain bus qui s’arrête à l’arret de bus .
Je suis débutant. Pourrais tu me communiquer le script que tu as utilisé ?
Est ce volontairement que tu as récupérer que le premier bus ?
Est ce possible de récupérer l’ensemble des arrets retourné par le Json ?

Avant de passer directement par la base de données, j’utilisais ça comme sensor (adapté pour le 81 arrêt GMAR) :

- platform: rest
  resource_template: https://open.tan.fr/ewp/tempsattentelieu.json/GMAR/1/81
  scan_interval: 60
  timeout: 120
  method: GET
  sensor:
    - name: "Bus 81 - Sens 1"
      value_template: OK
      json_attributes_path: "$.0"
      json_attributes:
        - "terminus"
        - "temps"
    - name: "Bus 81 - Sens 2"
      value_template: OK
      json_attributes_path: "$.1"
      json_attributes:
        - "terminus"
        - "temps"

Parfois l’API inverse le sens 1 et 2 (donc les terminus), en tout cas c’est ce que j’avais remarqué.

pour retrouver le code arret je suis allé sur https://open.tan.fr/

j’ai utilisé la requete préconisée `

https://open.tan.fr/ewp/tempsattentelieu.json/{codeArret}/{nombrePassages}/{numLigne})

ce qui donne dans ton cas

https://open.tan.fr/ewp/tempsattentelieu.json/GMAR/1/81)

la réponse obtenue est :

[
  {
    "sens": 1,
    "terminus": "Mendès France - Bellevue",
    "infotrafic": true,
    "temps": "3mn",
    "dernierDepart": "false",
    "tempsReel": "false",
    "ligne": {
      "numLigne": "81",
      "typeLigne": 3
    },
    "arret": {
      "codeArret": "GMAR3"
    }
  },
  {
    "sens": 2,
    "terminus": "Gare Maritime",
    "infotrafic": true,
    "temps": "21mn",
    "dernierDepart": "true",
    "tempsReel": "true",
    "ligne": {
      "numLigne": "81",
      "typeLigne": 3
    },
    "arret": {
      "codeArret": "GMAR3"
    }
  }
]

dans ton cas le code arret est GMAR3
a mettre dans le nouveau rest (j’ y rajouté le sens)

 - platform: rest
   value_template: >-
    {{ value_json.1.ligne.numLigne + " " + value_json.1.temps }}
    
   resource: http://open.tan.fr/ewp/tempsattente.json/GMAR3
   name: bus_tan_a
   unique_id: bus_tan_a
   json_attributes:
    - temps
    - terminus
    - sens
   scan_interval: 30
   timeout: 30
   force_update: true

ensuite il te faut creer une entrée template pour extraire ce que tu veux
ex:

{% if state_attr('sensor.bus_tan_a','sens')=="1"  %}
            {{ state_attr('sensor.bus_tan_a','temps') }}
            {% else %}
             {{ 'Attente Horaire' }} 
            {% endif %}

Actuellement il n’ ya pas d’horaire , mais peut etre que la ligne ne fonctionne pas tout le temps.

Bonjour,
je vois que tu a été plus rapide que moi, ta solution me parait plus élégante que la mienne
car elle permet de jouer avec la fonction si d’une card.

pour etre sur du sens j’ai carremment fait un if sur le terminus.dans une entrée template

{% if state_attr('sensor.bus_tan_a','terminus')=="Greneraie"  %}
            {{ state_attr('sensor.bus_tan_a','temps') }}
            {% else %}
             {{ 'Attente Horaire' }} 
            {% endif %}
2 « J'aime »

Bonjour @Patrick44fr,

Ah bien vu l’idée d’une entrée template pour confirmer le sens et donner le temps d’attente.

Comme parfois les sens sont inversés dans le résultat de la requête, il existe très certainement un moyen pour donner le sens (terminus) en état de l’entrée template (state) et le temps d’attente en attribut (state_attr).

1 « J'aime »

Merci @Integra et @Patrick44fr pour vos réponses.

Ce que je ne saisis pas, c’est que il est possible d’enregistrer l’ensemble d’un Json dans un seul attribut d’un capteur REST dans le cas de l’API SNCF comme le montre le sujet de Akunia

Puis ce post montre comment filtrer l’attribut afin de filtrer les informations recherchées. Pourquoi je n’arrive pas à faire la même chose avec l’API Tan ?

Il faut changer vers curl ou utiliser JQ pou arriver à ça. Je ne vais pas expliquer JQ mais p.e. :

command_line:
  - sensor: 
        name: something
        scan_interval: 1500
        command: >
             echo "{\"somekey\":" $(
             curl 'https://openv2-preprod.tan.fr/ewp/tempsattente.json/GMAR' ) "}"
        value_template: > 
            {{ "OK" }}
        json_attributes:
            - somekey

Salut Vingerha,

Ta solution marche : j’ai enfin un attribut avec l’ensemble du JSON comme attribut
Maintenant je n’ai plus qu’à trouver comment réaliser un capteur template qui puisse exploiter tout cela.

Merci beaucoup !!!

1 « J'aime »