Notification créneau de vaccination disponible (doctolib)

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 »

Bonjour @j5lien. Merci pour ton travail, J’ai pu intégrer tes capteurs sur mon installation.
Lors de mes tests, j’ai pu identifier un créneau pour mon fils et deux jours plus tard, c’est une remontée d’informations qui m’a permis de m’inscrire.
Bravo à toi.

des conseils pour ceux qui veulent implémenter ces éléments

  • dans l’alerte, ne pas placer les horaires. je trouve personnellement que ce n’est pas très utile.
  • dans l’alerte, il faudrait placer l’url de connexion pour qu’en sélectionnant la notification, on se retrouve directement sur la bonne page. je ne sais pas si c’est faisable.
  • si vous voulez partager cela avec des amis, il faut passer par le module Signal ou WhatsApp

bon courage à tous et surtout vaccinez vous !
Laurent

super , j’espère que ca marche ;p pas moyen de faire un test .?
peut tu suivre plusieurs centre de test ?
Merci

slt , tu peux m’aider ? au niveau de la notif ?
Meric

un exemple de mes sensors

#Antony
# https://www.doctolib.fr/availabilities.json?start_date=2021-05-12&visit_motive_ids=2687950&agenda_ids=454956-468305-455745-454959-450749-450520-450523-450517-454957-436450&insurance_sector=public&practice_ids=175970&destroy_temporary=true&limit=1
# https://www.doctolib.fr/vaccination-covid-19/antony-antony
# https://www.doctolib.fr/vaccination-covid-19/antony?ref_visit_motive_ids[]=6970&ref_visit_motive_ids[]=7005&force_max_limit=2

  - platform: rest
    resource_template: >-
      {{
        'https://www.doctolib.fr/availabilities.json?'
        ~ 'start_date=' ~ states('sensor.date')
        ~ '&visit_motive_ids=2687950'
        ~ '&agenda_ids=454956-468305-455745-454959-450749-450520-450523-450517-454957-436450'
        ~ '&practice_ids=175970'
        ~ '&insurance_sector=public'
        ~ '&destroy_temporary=true'
        ~ '&limit=3'
      }}
    method: GET
    name: Vaccination disponibilites Antony 
    value_template: "{{ value_json.total }}"
    scan_interval: 60
    timeout: 10
    unit_of_measurement: appointments
    json_attributes:
      - next_slot
      - availabilities
      - reason
      - message

#Clamart
# https://www.doctolib.fr/availabilities.json?start_date=2021-05-12&visit_motive_ids=2546765&agenda_ids=461477-466339-461481-461476&insurance_sector=public&practice_ids=164369&destroy_temporary=true&limit=4
# https://www.doctolib.fr/centre-de-sante/clamart/centre-de-vaccination-covid-de-la-ville-de-clamart?highlight%5Bspeciality_ids%5D%5B%5D=5494

  - platform: rest
    resource_template: >-
      {{
        'https://www.doctolib.fr/availabilities.json?'
        ~ 'start_date=' ~ states('sensor.date')
        ~ '&visit_motive_ids=2546765'
        ~ '&agenda_ids=410086-410087-466361-410085-466337-410349-466169-466339-461477-461473-461470-466336-461481-461476-410080-410083'
        ~ '&practice_ids=164369'
        ~ '&insurance_sector=public'
        ~ '&destroy_temporary=true'
        ~ '&limit=3'
      }}
    method: GET
    name: Vaccination disponibilites Clamart
    value_template: "{{ value_json.total }}"
    scan_interval: 60
    timeout: 10
    unit_of_measurement: appointments
    json_attributes:
      - next_slot
      - availabilities
      - reason
      - message

un exemple de mes binary sensors

- binary_sensor:
    - name: Disponibilités Antony
      state: >-
        {%- set days = state_attr('sensor.Vaccination_disponibilites_Antony', '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_disponibilites_Antony', '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 }}
    - name: Disponibilités Clamart
      state: >-
        {%- set days = state_attr('sensor.Vaccination_disponibilites_Clamart', '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_disponibilites_Clamart', '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 }}

et pour finir les notifications

- id: Covid_19_Notification_Antony
  alias: "Disponibilités Vaccin Antony"
  trigger:
  - platform: state
    entity_id: binary_sensor.Disponibilites_Antony
    from: 'off'
    to: 'on'
  action:
  - service: notify.DIFFUSION_LAURENT
    data:
      title: "Disponibilité Vaccin Antony à {{ now().strftime('%H:%M') }}"
      message: >
        {%- set days = state_attr('binary_sensor.Disponibilites_Antony', 'days') -%}
        {%- for day in days -%}
        {{ day.date }} :
        {%- for slot in day.slots %}
            - {{ slot.start_date|as_timestamp|timestamp_custom('%H:%M', true)  }}
        {%- endfor -%}
        {%- endfor -%}
      data:
        color: red
        sticky: 'true'
  - service: notify.logfilenotify
    data_template:
      message: >
        {{ now().strftime('%H:%M:%S') }};Disponibilité Vaccin Antony.

- id: Covid_19_Notification_Massy
  alias: "Disponibilités Vaccin Massy"
  trigger:
  - platform: state
    entity_id: binary_sensor.Disponibilites_Massy
    from: 'off'
    to: 'on'
  action:
  - service: notify.DIFFUSION_LAURENT
    data:
      title: "Disponibilité Vaccin Massy à {{ now().strftime('%H:%M') }}"
      message: >
        {%- set days = state_attr('binary_sensor.Disponibilites_Massy', 'days') -%}
        {%- for day in days -%}
        {{ day.date }} :
        {%- for slot in day.slots %}
            - {{ slot.start_date|as_timestamp|timestamp_custom('%H:%M', true)  }}
        {%- endfor -%}
        {%- endfor -%}
      data:
        color: red
        sticky: 'true'
  - service: notify.logfilenotify
    data_template:
      message: >
        {{ now().strftime('%H:%M:%S') }};Disponibilité Vaccin Massy.

Mon code n’est pas optimisé, j’ai dupliqué le code pour lancer des notifications pour chaque centre.
Bon courage

genial

mais sait tu ce que je dois mettre , pour utiliser les notifications sur app iOS ?
Merci

Bonjour, si tu as installer l’application Companion( Home Assistant) et tu l’a configurer. Tu dois mettre notify.mobile_app_nomdetonportable .

Exemple pour moi :

C’est top !!!
Merci bcp
Ça marche à merveille

Bonjour,

Merci pour cette notification.

Elle a très bien fonctionné pour moi, j’ai réussi a choper un rdv.
Mais depuis hier, mon binary_sensor revient indisponible.

Une idée?

Exactement le même cas pour ma part.
J’ai pu avoir un rendez-vous grace à cette intégration, mais depuis hier dans la journée mon binary_sensor est indisponible.
Je suppose que des choses ont changé du côté de doctolib. J’ai remarqué que le agenda_ids avait changé dans le lien depuis doctolib, mais même en le changeant dans mon sensor, ça n’a pas remis mon sensor en route après redémarrage.
Du coup, j’ai tout désactivé, vu que je n’en ai plus besoin.

En tout cas, merci pour l’intégration qui m’a bien aidé.

Bonjour bonjour,

Ca fonctionnait chez moi pendant quelques jours et depuis hier, plus rien :frowning:
J’ai l’erreur suivante : Template variable error: 'value_json' is undefined when rendering '{{ value_json.total }}' alors que ça fonctionnait et que j’avais pu avoir quelques alertes sur mon centre « test ».

Une idée d’où ça peut venir ?

Voila mes sensors REST pour info :

sensor:
  - platform: rest
    resource_template: >-
      {{
        'https://www.doctolib.fr/availabilities.json?'
        ~ 'start_date=' ~ now().strftime('%Y-%m-%d')
        ~ '&visit_motive_ids=2821077'
        ~ '&agenda_ids=461901-448979-471302-471313-448974-448975-448976-448977-448980-448978-461899-448973-444293-461902'
        ~ '&practice_ids=178662'
        ~ '&insurance_sector=public'
        ~ '&destroy_temporary=true'
        ~ '&limit=7'
      }}
    method: GET
    name: Robert Poirier available Vaccination slots
    value_template: "{{ value_json.total }}"
    scan_interval: 30
    timeout: 10
    unit_of_measurement: appointments
    json_attributes:
      - next_slot
      - availabilities
      - reason
      - message
  - platform: rest
    resource_template: >-
      {{
        'https://www.doctolib.fr/availabilities.json?'
        ~ 'start_date=' ~ now().strftime('%Y-%m-%d')
        ~ '&visit_motive_ids=2827840'
        ~ '&agenda_ids=468060'
        ~ '&practice_ids=163886'
        ~ '&insurance_sector=public'
        ~ '&destroy_temporary=true'
        ~ '&limit=7'
      }}
    method: GET
    name: test saint etienne
    value_template: "{{ value_json.total }}"
    scan_interval: 30
    timeout: 10
    unit_of_measurement: appointments
    json_attributes:
      - next_slot
      - availabilities
      - reason
      - message
  - platform: rest
    resource_template: >-
      {{
        'https://www.doctolib.fr/availabilities.json?'
        ~ 'start_date=' ~ now().strftime("%Y-%m-%d")
        ~ '&visit_motive_ids=2548527'
        ~ '&agenda_ids=429575-449554-417726-473602-473601-473600-417731-473604-471900-410821-436811-436809-410820-410823-417727-417728-417725-436265-429639-436810-472886'
        ~ '&practice_ids=164684'
        ~ '&insurance_sector=public'
        ~ '&destroy_temporary=true'
        ~ '&limit=7'
      }}
    method: GET
    name: Le Liberte available vaccination slots
    value_template: "{{ value_json.total }}"
    scan_interval: 30
    timeout: 10
    unit_of_measurement: appointments
    json_attributes:
      - next_slot
      - availabilities
      - reason
      - message

En tout cas merci beaucoup, c’est une super idée cette notification !

2 messages ont été scindés en un nouveau sujet : Installer Signal

J’ai aussi eu ce problème, j’ai l’impression que le temps de réponse de l’API est bien moins rapide du coup il faudrait peut être augmenter le timeout (et du coup le scan_interval). Je n’ai pas encore pu tester cela.

sensor:
  - platform: rest
    resource_template: >-
      {{
        'https://www.doctolib.fr/availabilities.json?'
        ~ 'start_date=' ~ now().strftime("%Y-%m-%d")
        ~ '&visit_motive_ids=2821077'
        ~ '&agenda_ids=466712-466714-466715-466718-466722-466725-466713-466708-466717-466710-467838-466721-466724-466720'
        ~ '&practice_ids=185169'
        ~ '&insurance_sector=public'
        ~ '&destroy_temporary=true'
        ~ '&limit=7'
      }}
    method: GET
    name: Vaccination available slots Arena
    value_template: "{{ value_json.total }}"
    scan_interval: 120
    timeout: 30
    unit_of_measurement: appointments
    json_attributes:
      - next_slot
      - availabilities
      - reason
      - message

Changer le timeout ne corrige pas le problème, il faut ajouter un header User-Agent, par exemple :

sensor:
  - platform: rest
    resource_template: >-
      {{
        'https://www.doctolib.fr/availabilities.json?'
        ~ 'start_date=' ~ now().strftime("%Y-%m-%d")
        ~ '&visit_motive_ids=2821077'
        ~ '&agenda_ids=466712-466714-466715-466718-466722-466725-466713-466708-466717-466710-467838-466721-466724-466720'
        ~ '&practice_ids=185169'
        ~ '&insurance_sector=public'
        ~ '&destroy_temporary=true'
        ~ '&limit=7'
      }}
    method: GET
    name: Vaccination available slots Arena
    value_template: "{{ value_json.total }}"
    scan_interval: 120
    timeout: 10
    headers:
      User-Agent: "Mozilla/5.0 Gecko/20100101 Firefox/88.0"
    unit_of_measurement: appointments
    json_attributes:
      - next_slot
      - availabilities
      - reason
      - message
2 « J'aime »

Effectivement ça remarche, merci beaucoup !!

Je confirme, ça refonctionne avec le header !

Merci :slight_smile:

J’ai vu cette vidéo où le créateur de vitemadose parle de doctolib. Il dit qu’ils changent régulièrement la mise en forme des données, etc sans jamais prévenir.
Alors autant nous il ne nous connaissent pas, autant covidtracker est hyper connu, et ils n’en ont rien à faire. Alors que ca arrange tout le monde s’ils faisaient un truc plus ouvert

1 « J'aime »