Notification créneau de vaccination disponible (doctolib)

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 »

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