Notification créneau de vaccination disponible (doctolib)

En utilisant le code complet de ta carte Lovelace, ça fonctionne. Merci

Salut @j5lien , merci pour ce tuto.
Pour ma part, HA me retourne l’erreur suivante dès la création du sensor
Template variable error: 'value_json' is undefined when rendering '{{ value_json.total }}'

Pour information, ça ne devrait pas avoir d’impact avec l’erreur ci-dessus, d’après ce que je voie dans les données brut du JSON issue de Doctolib de mon centre, ce n’est pas le même formattage que celui de ton exemple. Voici le retour du JSON de mon centre (j’ai limité à 3 jours pour l’affichage ici) :

{
  "total": 0,
  "availabilities": [
    {
      "date": "2021-05-10",
      "slots": []
    },
    {
      "date": "2021-05-11",
      "slots": []
    },
    {
      "date": "2021-05-12",
      "slots": []
    }
  ],
  "next_slot": "2021-05-26"
}

Aussi, j’ai testé pour mon centre, le fichier JSON n’est pas pointé directement par https://www.doctolib.fr mais par https://partners.doctolib.fr. Mais ça ne change rien, puis que si je remplace l’un par l’autre, les valeur du JSON son identique.

Hello @Tank, ton retour est correct. Les données sont formatées ainsi quand il n’y a pas de créneau sur la période demandée mais qu’ils en existent en dehors (visible au niveau du next_slot).

Par contre c’est étrange que le value_json ne fonctionne pas, c’est censé être une variable automatique qui parse les données d’entrée au format json : Templating - Home Assistant

Est-ce que tu peux partager la configuration de ton sensor ?

Voici mon sensor issue du fichier sensors.yaml :

# Vaccination Doctolib
  - platform: rest
    resource_template: >-
      {{
        'https://www.doctolib.fr/availabilities.json?'
        ~ 'start_date=' ~ states('sensor.date')
        ~ '&visit_motive_ids=2622608'
        ~ '&agenda_ids=424738'
        ~ '&practice_ids=170990'
        ~ '&insurance_sector=public'
        ~ '&destroy_temporary=true'
        ~ '&limit=7'
      }}
    method: GET
    name: Vaccination available slots Arena
    value_template: "{{ value_json.total }}"
    scan_interval: 60
    timeout: 10
    unit_of_measurement: appointments
    json_attributes:
      - next_slot
      - availabilities
      - reason
      - message

J’ai simplement remplacé les différents éléments comme tu l’avais indiqué plus haut.
D’ailleurs, j’ai le même problème un faisant un simple copier/coller du sensor de ton tuto, sans rien changer.

Est-ce que tu as bien ajouté l’entité sensor.date ?

sensor:
  - platform: time_date
    display_options:
      - 'date'

Un message a été scindé en un nouveau sujet : Alert vs Automation

Ahh, ça change tout… Ca fonctionne ainsi ! Mais qu’est-ce qui t’a fait dire à partir de l’erreur que c’était cette entité qui n’était pas présente ?

Je pensais que c’était de base dans HA et que ce sensor n’était que si on voulait afficher des éléments (date/heure) en particulier.

EDIT : désormais j’ai une erreur en mettant le template dans le fichier configuration, qui me dit :

Invalid config for [template]: [binary_sensor] is an invalid option for [template]. Check: template->binary_sensor

Certainement un problème d’inclusion ou d’indentation, partage ton code…

Voici mon code, mais il n’a rien de différent de celui de j5lien, ce n’est qu’un copier/coller

# Vaccination Doctolib
alert:
  appointment_available_arena:
    name: Rendez-vous vaccination disponible
    entity_id: binary_sensor.appointment_available_arena
    state: "on"
    repeat:
      - 5
      - 30
      - 60
    skip_first: false
    can_acknowledge: true
    notifiers:
      - mobile_app_***
    message: >-
      {%- set days = state_attr('binary_sensor.appointment_available_arena', 'days') -%}
      {%- for day in days -%}
      {{ day.date }} :
      {%- for slot in day.slots %}
        - {{ slot }}
      {%- endfor -%}
      {%- endfor -%}

template:
  - binary_sensor:
    - name: Appointment available Arena
      state: >-
        {%- set days = state_attr('sensor.vaccination_available_slots_arena', 'availabilities') -%}
        {%- set max_date = (now() + timedelta(days=2)).replace(hour=0, minute=0, second=0, microsecond=0)|as_timestamp -%}
        {%- set ns = namespace() -%}
        {%- set ns.slots = [] -%}
        {%- for day in days if day.slots|length > 0 -%}
          {%- set ns.slots =
            ns.slots +
            day.slots|map(attribute='start_date')|map('as_timestamp')|select('<', max_date)|list
          -%}
        {%- endfor -%}
        {{ ns.slots|length > 0 }}
      attributes:
        days: >-
          {%- set days = state_attr('sensor.vaccination_available_slots_arena', 'availabilities') -%}
          {%- set max_date = (now() + timedelta(days=2)).replace(hour=0, minute=0, second=0, microsecond=0)|as_timestamp -%}
          {%- set ns = namespace() -%}
          {%- set ns.days = [] -%}
          {%- for day in days if day.slots|length > 0 -%}
            {%- set slots = day.slots
                  |map(attribute='start_date')
                  |map('as_timestamp')
                  |select('<', max_date)
                  |map('timestamp_custom', '%H:%M', true)
                  |list
            -%}
            {%- if slots|length > 0 -%}
              {%- set ns.days = ns.days + [{
                "date": day.date,
                "slots": slots
              }] -%}
            {%- endif -%}
          {%- endfor -%}
          {{ ns.days }}

La ligne en erreur correspond à celle où il est écrit template:

D’ailleurs, il n’y a rien à activer / installer pour se servir des templates ? Je demande ça, vu que j’étais passé à côté du sensor.date

Tu n’as pas la dernière version de HA ! J’ai eu la même erreur jusqu’à ce que je mette la dernière version de HA

Cette phrase :

Car dans le code, seule l’entité sensor.date est pré-requis.

@j5lien, peut être remplacer sensor.date par now().strftime("%Y-%m-%d") pour ne plus avoir de dépendance ?

ce qui donne :

# Vaccination Doctolib
  - platform: rest
    resource_template: >-
      {{
        'https://www.doctolib.fr/availabilities.json?'
        ~ 'start_date=' ~ now().strftime("%Y-%m-%d")
        ~ '&visit_motive_ids=2622608'
        ~ '&agenda_ids=424738'
        ~ '&practice_ids=170990'
        ~ '&insurance_sector=public'
        ~ '&destroy_temporary=true'
        ~ '&limit=7'
      }}
    method: GET
    name: Vaccination available slots Arena - temp
    value_template: "{{ value_json.total }}"
    scan_interval: 60
    timeout: 10
    unit_of_measurement: appointments
    json_attributes:
      - next_slot
      - availabilities
      - reason
      - message

Comme le dit @JournaldeThomas , il faut l’une des dernière version pour cela ( 2021.4 je crois).
Si tu es en ancienne, tu peux l’écrire ainsi :

binary_sensor:
  - platform: template
    sensors:
      appointment_available_arena:
        friendly_name: "Appointment available Arena"
        value_template: >-
          {%- set days = state_attr('sensor.vaccination_available_slots_arena', 'availabilities') -%}
          {%- set max_date = (now() + timedelta(days=2)).replace(hour=0, minute=0, second=0, microsecond=0)|as_timestamp -%}
          {%- set ns = namespace() -%}
          {%- set ns.slots = [] -%}
          {%- for day in days if day.slots|length > 0 -%}
            {%- set ns.slots =
              ns.slots +
              day.slots|map(attribute='start_date')|map('as_timestamp')|select('<', max_date)|list
            -%}
          {%- endfor -%}
          {{ ns.slots|length > 0 }}
        attribute_templates:
          days: >-
            {%- set days = state_attr('sensor.vaccination_available_slots_arena', 'availabilities') -%}
            {%- set max_date = (now() + timedelta(days=2)).replace(hour=0, minute=0, second=0, microsecond=0)|as_timestamp -%}
            {%- set ns = namespace() -%}
            {%- set ns.days = [] -%}
            {%- for day in days if day.slots|length > 0 -%}
              {%- set slots = day.slots
                    |map(attribute='start_date')
                    |map('as_timestamp')
                    |select('<', max_date)
                    |map('timestamp_custom', '%H:%M', true)
                    |list
              -%}
              {%- if slots|length > 0 -%}
                {%- set ns.days = ns.days + [{
                  "date": day.date,
                  "slots": slots
                }] -%}
              {%- endif -%}
            {%- endfor -%}
            {{ ns.days }}

En effet, j’essaye d’éviter d’utiliser now() pour une date car ça a tendance à régénérer le template trop souvent mais ça ne s’applique pas pour un rest sensor.

Ça a en effet été ajouté dans la 2021.5.

Si t’as une erreur à ce niveau là, ça signifie que l’appel http a bien été effectué mais que HA n’a pas réussi à parser le résultat au format json et donc la varialbe value_json n’existe pas. Le soucis provenait surement de l’url, j’ai donc testé l’appel avec une date invalide et en effet une ça génère une erreur.

Toutes les minutes dixit la documentation → Templating - Home Assistant

Mais oui, dans le cas d’un rest, avec un scan_interval à 60… :wink:

Bonjour,
J’ai un soucis avec le binary_sensor car il ne trouve pas de « start_date »:

Template variable error: 'str object' has no attribute 'start_date' when rendering '{%- set days = state_attr('sensor.vaccination_available_slots_arena', 'availabilities') -%} {%- set max_date = (now() + timedelta(days=2)).replace(hour=0, minute=0, second=0, microsecond=0)|as_timestamp -%} {%- set ns = namespace() -%} {%- set ns.slots = [] -%} {%- for day in days if day.slots|length > 0 -%} {%- set ns.slots = ns.slots + day.slots|map(attribute='start_date')|map('as_timestamp')|select('<', max_date)|list -%} {%- endfor -%} {{ ns.slots|length > 0 }}'

Le capteur semble pourtant bien configuré car il récupère les créneaux:

availabilities: 
- date: '2021-05-12'
  slots: []
  substitution: null
- date: '2021-05-13'
  slots:
    - '2021-05-13T08:40:00.000+02:00'
    - '2021-05-13T12:10:00.000+02:00'
  substitution: null
- date: '2021-05-14'
  slots:
    - '2021-05-14T08:00:00.000+02:00'
    - '2021-05-14T08:20:00.000+02:00'
  substitution: null

unit_of_measurement: appointments
friendly_name: Vaccination available slots Arena

j’ai la dernière version (2021.5) et j’ai rajouté sensor.date au cas où.

Une idée ? Merci!

@JournaldeThomas @Clemalex @j5lien
C’était bien la mise à jour de HA qui n’était pas bonne. J’avais vu dans la doc qu’il y a l’ancienne forme d’écriture, mais je ne pensais pas que le changement était si récent.

Tout fonctionne désormais.

3 messages ont été scindés en un nouveau sujet : Modèle (Template) - Nouveau format

Tu peux partager l’url de ton sensor ? Habituellement les slots sont des objets et dans ton cas, tu récupères directement une liste de date.

Et du coup ton binary sensor devrait plutôt ressembler à quelque chose comme ça (je n’ai pas testé)

template:
  - binary_sensor:
    - name: Appointment available Arena
      state: >-
        {%- set days = state_attr('sensor.vaccination_available_slots_arena', 'availabilities') -%}
        {%- set max_date = (now() + timedelta(days=2)).replace(hour=0, minute=0, second=0, microsecond=0)|as_timestamp -%}
        {%- set ns = namespace() -%}
        {%- set ns.slots = [] -%}
        {%- for day in days if day.slots|length > 0 -%}
          {%- set ns.slots =
            ns.slots +
            day.slots|map('as_timestamp')|select('<', max_date)|list
          -%}
        {%- endfor -%}
        {{ ns.slots|length > 0 }}
      attributes:
        days: >-
          {%- set days = state_attr('sensor.vaccination_available_slots_arena', 'availabilities') -%}
          {%- set max_date = (now() + timedelta(days=2)).replace(hour=0, minute=0, second=0, microsecond=0)|as_timestamp -%}
          {%- set ns = namespace() -%}
          {%- set ns.days = [] -%}
          {%- for day in days if day.slots|length > 0 -%}
            {%- set slots = day.slots
                  |map('as_timestamp')
                  |select('<', max_date)
                  |map('timestamp_custom', '%H:%M', true)
                  |list
            -%}
            {%- if slots|length > 0 -%}
              {%- set ns.days = ns.days + [{
                "date": day.date,
                "slots": slots
              }] -%}
            {%- endif -%}
          {%- endfor -%}
          {{ ns.days }}

J’ai retiré |map(attribute='start_date') qui permet de récupérer la date des objets slot, ce qui n’est pas nécessaire donc ton cas.

J’ai testé cette automatisation avec un centre au pif car il n’y a rien à coté de chez moi avant juin. URL:
https://www.doctolib.fr/availabilities.json?start_date=2021-05-13&visit_motive_ids=2713086&agenda_ids=473721-473722-473723-454230-456257-456258-454233-454234-456260-473720-456259-454231&practice_ids=177445&insurance_sector=public&destroy_temporary=true&limit=7
Tu pourras constater qu’il y a effectivement directement la liste des créneaux disponibles.

Suite à ce que tu as dit, pour tester, j’ai modifié la « start_date » dans la requête du capteur pour obtenir les créneaux à partir de juin dans le centre à côté de chez moi. Les slots contiennent cette fois plus d’information que précédemment, notamment le start_date qui posait problème au binary_sensor.

availabilities: 
- date: '2021-06-09'
  slots:
    - agenda_id: 411330
      practitioner_agenda_id: null
      start_date: '2021-06-09T10:20:00.000+02:00'
      end_date: '2021-06-09T10:25:00.000+02:00'
      steps:
        - agenda_id: 411330
          practitioner_agenda_id: null
          start_date: '2021-06-09T10:20:00.000+02:00'
          end_date: '2021-06-09T10:25:00.000+02:00'
          visit_motive_id: 2550316
        - agenda_id: 447201
          practitioner_agenda_id: null
          start_date: '2021-07-21T10:45:00.000+02:00'
          end_date: '2021-07-21T10:50:00.000+02:00'
          visit_motive_id: 2550317

Du coup, je suppose que le template fonctionnera pour moi, mais il semble y avoir un formattage de réponse différent d’un centre à un autre.
Merci de ton aide en tout cas !

C’est genial ::::!!!
ca marche nickel chez moi ,
y a t’il ^possibilité d’avoir une notification ?
Merci

Cette partie Ajout d’une alerte permet de créer une notification.

Pour info, l’alerte est un composant qui va faire de la notification, il écoute l’état d’une entité, ici binary_sensor.appointment_available_arena et lorsqu’il passe à on génère une notification qui sera répétée tant que l’état n’a pas changé :

alert:
  appointment_available_arena:
    name: Rendez-vous vaccination disponible
    # Entité à suivre
    entity_id: binary_sensor.appointment_available_arena
    # Etat de l'entité activant l'alerte
    state: "on"
    # Répéter l'alerte au bout de 5 minutes, puis 30, puis toutes les 60m
    repeat:
      - 5
      - 30
      - 60
    # Permet de lancer la notification au moment où l'alerte s'active (ne pas attendre les 5m du repeat)
    skip_first: false
    # Possibilité de désactivé l'alerte même si l'entité suivie est toujours à on
    can_acknowledge: true
    # la liste des services envoyant la notification (il ne faut pas renseigner le domaine notifier.)
    notifiers:
      - mobile_app_***
    # Le contenu de la notification
    message: >-
      {%- set days = state_attr('binary_sensor.appointment_available_arena', 'days') -%}
      {%- for day in days -%}
      {{ day.date }} :
      {%- for slot in day.slots %}
        - {{ slot }}
      {%- endfor -%}
      {%- endfor -%}
1 « J'aime »