[Article] Intégration Pronote : cours, devoirs, notes, etc

Effectivement, j’ai la même chose que @BBE, sans le filtre sur le nom de l’enfant, c’est voulu que tu l’aies ajouté ?

Salut, est-ce que tu as continué à développer des cartes pour Pronote?

Yes, j’ai la carte des évaluations en cours de développement actuellement, mais j’avoue que je focus pas mal sur la fuite mémoire en ce moment.

4 « J'aime »

En attendant tu peux utiliser des cartes markdown

J’utilise les markdowns suivants qui si j’ai bonne mémoire sont plus ou moins dérivées de celles de @vingerha .

Evaluations :


type: markdown
content: >-
  <table>  {% if state_attr('sensor.pronote_xxx_thibault_evaluations',
  'lessons')[0] is defined %} {% set items =
  state_attr('sensor.pronote_xxx_thibault_evaluations','evaluations')%} {%
  for i in range(0, items | count, 1) %} <tr><td colspan="3"><b>{{
  items[i].date.strftime("%d-%m") }} {{ items[i].subject }}</td> {% set
  acquisitions = items[i].acquisitions %} {% for j in
  range(0,acquisitions|count,1) %} <tr> <td>{{ acquisitions[j].name }}</td>
  <td>{{ acquisitions[j].domain }}</td> <td width="8%"> {% if
  acquisitions[j].level == 'Très bonne maîtrise' %} 🟢+ {% elif
  acquisitions[j].level == 'Maîtrise satisfaisante' %} 🟢 {% elif
  acquisitions[j].level == "Début de maîtrise" %} 🟡 {% elif
  acquisitions[j].level == 'Maîtrise fragile'  %} 🟠 {% elif
  acquisitions[j].level == 'Presque maîtrisé'  %} 🟡 {% else %} ?  {% endif
  %}</td> </tr> {% endfor %} </tr> {% endfor %} {% else %} Pas d'évaluation {%
  endif %}
title: Evaluations
card_mod:
  style:
    .: |
      ha-card ha-markdown {
                padding:0px
                border-top: 1px groove var(--divider-color);
                overflow-y: scroll;
                height: 100px;
              }
      ha-card ha-markdown.no-header {
        padding:0px
      }
    $: |
      h1.card-header {
        background-color:rgb(100, 100, 100);
          padding: 0px 0px 0px 12px !important;
          color: white !important;
          font-weight: normal;
          font-size: 1.5em !important;
          border-top-left-radius: 5px; 
          border-top-right-radius: 5px; 
          height: 100%;
      }        
    ha-markdown $: |
      h1 {
          font-weight: normal;
          font-size: 24px;
      }
      div {
          background-color:rgb(100, 100, 100);
          padding: 12px 12px;
          color:white;
          font-weight:normal;
          font-size:1.2em;
            border-top-left-radius: 5px; 
            border-top-right-radius: 5px; 
      }
      table{
        border-collapse: collapse;
        font-size: 0.9em;
        font-family: Roboto;
        width: 100%;
        outline: 0px solid #393c3d;
        margin-top: 10px;
      } caption {
          text-align: center;
          font-weight: bold;
          font-size: 1.2em;
      } td {
          padding: 5px 5px 5px 5px;
          text-align: left;
          border-bottom: 0px solid #1c2020;
      }
      tr {
          border-bottom: 0px solid #1c2020;
      }
      tr:last-of-type {
          border-bottom: transparent;
      }
      tr:nth-of-type(even) {
          background-color: rgb(54, 54, 54, 0.3);
      }
      mark {
          background: lightgreen;
          border-color: green;
          border-radius: 10px;
          padding: 5px;
      }
      span {
          background: orange;
          color: #222627;
          border-radius: 5px;
          padding: 5px;
      }
      tr:nth-child(n+2) > td:nth-child(2) {
        text-align: left;
      }

Absences:

type: markdown
content: >-
  {% if state_attr('sensor.pronote_xxx_thibault_absences', 'absences')[0] is
  defined %} <table>  {% set items = 
  state_attr('sensor.pronote_xxx_thibault_absences','absences') %} {% for i
  in range(0, items | count, 1) %} <tr> {%- if items[i].justified == True -%}
  <td> <mark> {{ items[i].from.strftime("%d-%m") }}</mark></td> {% else %} <td>
  <span>{{ items[i].from.strftime("%d-%m") }}</span></td>  {%- endif -%}  <td>{{
  items[i].hours }}</td> <td>{{ items[i].reason }}</td> {% endfor %} {% else %}
  Pas d'absences ce trimestre {% endif %}
title: Absences
card_mod:
  style:
    .: |
      ha-card ha-markdown {
                padding:0px
                border-top: 1px groove var(--divider-color);
                overflow-y: scroll;
                height: 100px;
              }
      ha-card ha-markdown.no-header {
        padding:0px
      }
    $: |
      h1.card-header {
        background-color:rgb(100, 100, 100);
          padding: 0px 0px 0px 12px !important;
          color: white !important;
          font-weight: normal;
          font-size: 1.5em !important;
          border-top-left-radius: 5px; 
          border-top-right-radius: 5px; 
          height: 100%;
      }        
    ha-markdown $: |
      h1 {
          font-weight: normal;
          font-size: 24px;
      }
      div {
          background-color:rgb(100, 100, 100);
          padding: 12px 12px;
          color:white;
          font-weight:normal;
          font-size:1.2em;
            border-top-left-radius: 5px; 
            border-top-right-radius: 5px; 
      }
      table{
        border-collapse: collapse;
        font-size: 0.9em;
        font-family: Roboto;
        width: 100%;
        outline: 0px solid #393c3d;
        margin-top: 10px;
      } caption {
          text-align: center;
          font-weight: bold;
          font-size: 1.2em;
      } td {
          padding: 5px 5px 5px 5px;
          text-align: left;
          border-bottom: 0px solid #1c2020;
      }
      tr {
          border-bottom: 0px solid #1c2020;
      }
      tr:last-of-type {
          border-bottom: transparent;
      }
      tr:nth-of-type(even) {
          background-color: rgb(54, 54, 54, 0.3);
      }
      mark {
          background: lightgreen;
          border-color: green;
          border-radius: 10px;
          padding: 5px;
      }
      span {
          background: orange;
          color: #222627;
          border-radius: 5px;
          padding: 5px;
      }
      tr:nth-child(n+2) > td:nth-child(2) {
        text-align: left;
      }

Retard:

type: markdown
content: >-
  {% if state_attr('sensor.pronote_xxx_thibault_delays', 'delays')[0] is
  defined %} <table> 
    <tr>
    <td><h4>Date</td>
    <td><h4>Min.</td>
    <td><h4>Justification/Raison</td>
    </tr>
    {% set items = state_attr('sensor.pronote_xxx_thibault_delays','delays')
  %}

  {% for i in range(0, items | count, 1) %}

  <tr>

  {%- if items[i].justified == True -%}

  <td> <mark> {{ items[i].date.strftime("%d-%m") }}</mark></td>

  {% else %}

  <td> <span>{{ items[i].date.strftime("%d-%m") }}</span></td> 

  {%- endif -%} 

  <td>{{ items[i].minutes }}</td>

  <td>({{ items[i].justification }}){{ items[i].reasons }} {% endfor %}   {%
  else %}Pas de retard ce Trimestre {% endif %}
title: Retards
card_mod:
  style:
    .: |
      ha-card ha-markdown {
                padding:0px
                border-top: 1px groove var(--divider-color);
                overflow-y: scroll;
                height: 100px;
              }
      ha-card ha-markdown.no-header {
        padding:0px
      }
    $: |
      h1.card-header {
        background-color:rgb(100, 100, 100);
          padding: 0px 0px 0px 12px !important;
          color: white !important;
          font-weight: normal;
          font-size: 1.5em !important;
          border-top-left-radius: 5px; 
          border-top-right-radius: 5px; 
          height: 100%;
      }        
    ha-markdown $: |
      h1 {
          font-weight: normal;
          font-size: 24px;
      }
      div {
          background-color:rgb(100, 100, 100);
          padding: 12px 12px;
          color:white;
          font-weight:normal;
          font-size:1.2em;
            border-top-left-radius: 5px; 
            border-top-right-radius: 5px; 
      }
      table{
        border-collapse: collapse;
        font-size: 0.9em;
        font-family: Roboto;
        width: 100%;
        outline: 0px solid #393c3d;
        margin-top: 10px;
      } caption {
          text-align: center;
          font-weight: bold;
          font-size: 1.2em;
      } td {
          padding: 5px 5px 5px 5px;
          text-align: left;
          border-bottom: 0px solid #1c2020;
      }
      tr {
          border-bottom: 0px solid #1c2020;
      }
      tr:last-of-type {
          border-bottom: transparent;
      }
      tr:nth-of-type(even) {
          background-color: rgb(54, 54, 54, 0.3);
      }
      mark {
          background: lightgreen;
          border-color: green;
          border-radius: 10px;
          padding: 5px;
      }
      span {
          background: orange;
          color: #222627;
          border-radius: 5px;
          padding: 5px;
      }
      tr:nth-child(n+2) > td:nth-child(2) {
        text-align: left;
      }

Punitions:

type: markdown
content: |2-
   <div>Punitions</div><table> 
    {% if state_attr('sensor.pronote_xxx_thibault_punishments','punishments')[0] is defined %}
      {% set items = state_attr('sensor.pronote_xxx_thibault_punishments','punishments')%}
    <tr>
    <td><h4>Date<h3></td>
    <td><h4>Matière</td>
    <td><h4>Raison</td>
    <td><h4>Circonstances</td>
    <td><h4>Punition</td>
    <td><h4>Durée</td>
    <td><h4>Exclusion</td>
    <td><h4>En cours</td>
    </tr>
    {% for i in range(0, items | count, 1) %}
    <tr>    
    <td>{{ items[i].date }}</td>
    <td>{{ items[i].subject }}</td>
    <td>{{ items[i].reasons }}</td>
    <td>{{ items[i].circumstances }}</td>
    <td>{{ items[i].nature }}</td>
    <td>{{ items[i].duration }}</td>
    <td>{{ items[i].exclusion }}</td>
    <td>{{ items[i].during_lesson }}</td>  
   </tr>
  {% endfor %}
  {% else %} Pas de punition
  {% endif %}
card_mod:
  style:
    .: |
      ha-card ha-markdown {
                padding:0px
                border-top: 1px groove var(--divider-color);
                overflow-y: scroll;
                height: 300px;
              }
      ha-card ha-markdown.no-header {
        padding:0px
      }
    $: |
      h1.card-header {
        background-color:rgb(100, 100, 100);
          padding: 0px 0px 0px 12px !important;
          color: white !important;
          font-weight: normal;
          font-size: 1.5em !important;
          border-top-left-radius: 5px; 
          border-top-right-radius: 5px; 
          height: 100%;
      }        
    ha-markdown $: |
      h1 {
          font-weight: normal;
          font-size: 24px;
      }
      div {
          background-color:rgb(100, 100, 100);
          padding: 12px 12px;
          color:white;
          font-weight:normal;
          font-size:1.2em;
            border-top-left-radius: 5px; 
            border-top-right-radius: 5px; 
      }
      table{
        border-collapse: collapse;
        font-size: 0.9em;
        font-family: Roboto;
        width: 100%;
        outline: 0px solid #393c3d;
        margin-top: 10px;
      } caption {
          text-align: center;
          font-weight: bold;
          font-size: 1.2em;
      } td {
          padding: 5px 5px 5px 5px;
          text-align: left;
          border-bottom: 0px solid #1c2020;
      }
      tr {
          border-bottom: 0px solid #1c2020;
      }
      tr:last-of-type {
          border-bottom: transparent;
      }
      tr:nth-of-type(even) {
          background-color: rgb(54, 54, 54, 0.3);
      }
      mark {
          background: lightgreen;
          border-color: green;
          border-radius: 10px;
          padding: 5px;
      }
      span {
          background: orange;
          color: #222627;
          border-radius: 5px;
          padding: 5px;
      }
      tr:nth-child(n+2) > td:nth-child(2) {
        text-align: left;
      }

Devoirs:

type: markdown
content: >-
  <table> {% if  
  state_attr('sensor.pronote_xxx_thibault_homework_period','homework') ==
  'is defined' %} {% set items =
  state_attr('sensor.pronote_xxx_thibault_homework_period','homework') %} {%
  for i in range(0, items | count, 1) %} {% if i == 0 %} <tr><td
  colspan="2"><b>{{ items[i].date.strftime("%A %d") }}</td></tr> {% endif %} {%
  if items[i].date > items[i-1].date %}  <tr><td colspan=2><p><b>{{
  items[i].date.strftime("%A %d") }}</p></td></tr>  {% endif %} <tr> {%- if
  items[i].done == true -%} <td>   <mark> {{ items[i].subject }}</mark></td> {%
  else %} <td>   <span> {{ items[i].subject }}</span></td> {%- endif -%} <td>{{
  items[i].description }}</td> <td></td> </tr> {% endfor %} {% else %} Pas de
  Devoirs {% endif %}
title: Devoirs
card_mod:
  style:
    .: |
      ha-card ha-markdown {
                padding:0px
                border-top: 1px groove var(--divider-color);
                overflow-y: scroll;
                height: 100px;
              }
      ha-card ha-markdown.no-header {
        padding:0px
      }
    $: |
      h1.card-header {
        background-color:rgb(100, 100, 100);
          padding: 0px 0px 0px 12px !important;
          color: white !important;
          font-weight: normal;
          font-size: 1.5em !important;
          border-top-left-radius: 5px; 
          border-top-right-radius: 5px; 
          height: 100%;
      }        
    ha-markdown $: |
      h1 {
          font-weight: normal;
          font-size: 24px;
      }
      div {
          background-color:rgb(100, 100, 100);
          padding: 12px 12px;
          color:white;
          font-weight:normal;
          font-size:1.2em;
            border-top-left-radius: 5px; 
            border-top-right-radius: 5px; 
      }
      table{
        border-collapse: collapse;
        font-size: 0.9em;
        font-family: Roboto;
        width: 100%;
        outline: 0px solid #393c3d;
        margin-top: 10px;
      } caption {
          text-align: center;
          font-weight: bold;
          font-size: 1.2em;
      } td {
          padding: 5px 5px 5px 5px;
          text-align: left;
          border-bottom: 0px solid #1c2020;
      }
      tr {
          border-bottom: 0px solid #1c2020;
      }
      tr:last-of-type {
          border-bottom: transparent;
      }
      tr:nth-of-type(even) {
          background-color: rgb(54, 54, 54, 0.3);
      }
      mark {
          background: lightgreen;
          border-color: green;
          border-radius: 10px;
          padding: 5px;
      }
      span {
          background: orange;
          color: #222627;
          border-radius: 5px;
          padding: 5px;
      }
      tr:nth-child(n+2) > td:nth-child(2) {
        text-align: left;
      }

Il suffira de mettre à jour au fur et à mesure lorsque les cartes pour chaque type de sensor seront dispo avec le même look et le même niveau que les cartes emploi du temps / notes et moyennes…

Oui j’ai 2 enfants dans Pronote. Lorsqu’il y a des nouvelles notes, j’envoie une notif sur le téléphone de l’enfant concerné, et une sur mon téléphone et celui de ma femme. C’est pour ça que j’avais filtré au niveau du trigger, plus simple.

tu peux garder un trigger unique et faire un bloc conditionnel dans les actions et tout faire dans une seule automatisation:

notifier maman
notifier papa
si enfant 1 => notifier enfant1
si enfant 2 => notifier enfant2

Mais encore une fois il n’est pas sûr que le problème vienne de là…

c’est juste une différence entre une notif qui marche, et ta notif qui a marché et ne marche plus…

Oui pas bête, ça ne me ferait qu’une seule automation pour les 2. Je vais tester comme ça.

Je l’avais aussi sur ma todo list… alors je viens de tenter ça…
Réponse à la prochaine note…

alias: Pronote - notification nouvelle note
description: >-
  Notification smartphone parents en cas de nouvelle note sur le pronote d'un
  enfant
trigger:
  - platform: event
    event_type: pronote_event
    event_data:
      type: new_grade
action:
  - service: notify.mobile_app_smartphone_doudou
    data:
      message: >-
        {{ trigger.event.data.data.subject }} : {{
        trigger.event.data.data.grade_out_of }} ({{
        trigger.event.data.data.comment }})
      title: Nouvelle note pour {{ trigger.event.data.child_name }}
      data:
        clickAction: /lovelace-smartphone/pronote
        url: /lovelace-smartphone/pronote
  - service: notify.mobile_app_smartphone_jeanne
    data:
      message: >-
        {{ trigger.event.data.data.subject }} : {{
        trigger.event.data.data.grade_out_of }} ({{
        trigger.event.data.data.comment }})
      title: Nouvelle note pour {{ trigger.event.data.child_name }}
      data:
        clickAction: /lovelace-smartphone/pronote
        url: /lovelace-smartphone/pronote
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ trigger.event.data.child_name == 'Louise' }}"
        sequence:
          - service: notify.mobile_app_sm_a137f
            data:
              message: >
                {{ trigger.event.data.data.subject }} : {{
                trigger.event.data.data.grade_out_of }} ({{
                trigger.event.data.data.comment }})
              title: Nouvelle note pour {{ trigger.event.data.child_name }}
              data:
                clickAction: /lovelace-smartphone/pronote
                url: /lovelace-smartphone/pronote
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ trigger.event.data.child_name == 'Thibault' }}"
        sequence:
          - service: notify.mobile_app_smartphone_a14_thibault
            data:
              message: >
                {{ trigger.event.data.data.subject }} : {{
                trigger.event.data.data.grade_out_of }} ({{
                trigger.event.data.data.comment }})
              title: Nouvelle note pour {{ trigger.event.data.child_name }}
              data:
                clickAction: /lovelace-smartphone/pronote
                url: /lovelace-smartphone/pronote

Pas besoin je l’ai déjà tu a parlé tros vite. Lol

Alors oui la fuite de mémoire est plus importante que les cartes, ça fait plaisir de voire que tu avance Petit a petit peu .

Bonjour à tous…
je ne comprends pas les éléments des absences… Celles ci- montrent parfois days: 1 ou days:4 alors qu’il n’a pas été absent si longtemps…?? Je ne comprends pas comment est calculé days :o
Auriez vous une explication?

bonjour, j ai bien installé, j ai bien mes sensors, emploi du temps ok, notes ok… mais homework et homework_period ne remonte rien, je suis sur Toulouse et je me suis connecté via le QRCode.
Quelqu’un a déjà eu ce problème ?

bon appartement ce n est pas un problème de config… sur PRONOTE je n ai pas de devoir, sur ENT si !

J’ai le même soucis… les profs chez nous utilisent ENT, donc rien ne remonte dans Pronote…

C’est un problème de l’éducation nationale… mais je n’ai pas trouvé le github pour remonter ce bug :rofl:

1 « J'aime »

Hello, merci pour le super article qui résume tout, j’ai pu réinstaller tout pronote en 15 minutes c’est niquel.
Les profs ne l’avaient pas utilisé jusqu’à maintenant chez nous mais y’a t’il moyen de récupéré les « Prochains DS »
image

J’avais aussi deux autres petites quesions :

  • Est il possible d’ajouter les devoirs à un calendrier (autre que celui des cours) ?
  • Y’a t’il une commande pour forcer un refresh de l’emploi du temps ?

ent.ecollege78 viens de me forcer a changer le mot de passe avec ce message affiché sur le site. Obligé de reconfigurer l’intégration

Bonjour,
Pour ceux qui, comme moi, ont de vieux yeux (ne savent plus lire) et se demande pourquoi un copier-coller des deux codes de ce post ne fonctionnent pas immédiatement comme espéré, regardez bien la différence de syntaxe du début de chacun.

  • Dans le premier (comme pour ceux publiés sur sur son github) :
template:
  - sensor:
  • Dans le second (que je suppose présenté pour être écrit dans configuration.yaml) :
sensor:
  - platform: template
    sensors:

Tout en remerciant infiniement @herveaurel (entre autres !) pour ses capteurs si bien pensés, j’ai essayé de clarifier la syntaxe globale dans ce résumé :

  • la différence entre ancien et nouveau format pour déclarer les capteurs ;
  • comment les déclarer dans plusieurs fichiers .yaml pour ceux qui aiment encore se passer de ui.

L’avantage d’avoir plusieurs fichiers dans le cas spécifique de cette géniale intégration Pronote, c’est qu’il suffit de copier-coller le fichier du 1er enfant (aîné par exemple) et de faire un rechercher-remplacer dans notepad++ pour remplacer par les noms corrects des cadets.

Au passage, une question : vous croyez que l’intégration pourrait fonctionner pour un compte « prof » (donc ni « élève » ni « parent »…) ? Ok, j’exagère… Sauf aux USA où ils sont souvent notés mais pas sur Pronote, seul l’emploi du temps pourrait leur être utile.

1 « J'aime »

Bonsoir.
Je souhaite utiliser l’attribut day_end_at comme déclencheur d’automatisation (pour aller chercher à lécole évidemment).

Vu que c’est les vacances ici aussi, je fais mes tests pour l’instant avec mon capteur sensor.pronote_none_timetable_next_day, qui sera remplacé par sensor.pronote_none_timetable_today à la rentrée.

J’y ajouterai d’ailleurs un offset pour que l’évènement (notification sonore) se déclenche 20 min avant l’évènement sensor.pronote_none_timetable_today.day_end_at

Et en essayant de comprendre ce que m’avait expliqué @Clemalex dans ce post sur les timestamp, j’ai essayé ça :

{{as_timestamp(state_attr('sensor.pronote_none_timetable_today', 'day_end_at'))}}

Ouaip… Mais évidemment, ça renvoie une erreur pour le jour de vacances qu’est aujourd’hui, donc l’automatisation risque de bien planter aussi.

Alors je pense à un truc alambriqué, un truc comme ça qui, au moins, semble fonctionner dans l’éditeur de modèle :

{% if state_attr('sensor.pronote_none_timetable_today', 'day_end_at') is defined %}
{{as_timestamp(state_attr('sensor.pronote_none_timetable_today', 'day_end_at'))}}
{% else %}
946681200
{% endif %}

(le nombre « 946681200 » correspond au timestamp du 1/1/2000, choisi ainsi car déjà passé).

Mais, quand je saisi ce code en tant que déclencheur, ça n’a pas l’air d’être accepté du tout. Le code YAML du déclencheur est :

platform: time
at: >-
  {% if state_attr('sensor.pronote_none_timetable_today', 'day_end_at')[0] is defined %}
  {{as_timestamp(state_attr('sensor.pronote_none_timetable_today','day_end_at'))}}
  {% else %} 946681200 {% endif %}

Une idée de ce qu’il faut modifier pour avoir un déclencheur fonctionnel sur l’attribut day_end_at ?

Hello,

j’ai modifié le template pour préciser le nom de l’examen les note min-moy-max, avec la date de l’examen:

service: notify.mobile_app_XXX
data:
  message: >-
    Date : {{ trigger.event.data.data.date }} {{ '\n' -}} Matiere: {{
    trigger.event.data.data.subject }} {{ '\n' -}} Controle : {{
    trigger.event.data.data.comment }} {{ '\n' -}} Note :
    {{trigger.event.data.data.grade_out_of }} {{ '\n' -}} Moyenne Classe :
    {{trigger.event.data.data.class_average }} {{ '\n' -}} Note Min:
    {{trigger.event.data.data.min }} {{ '\n' -}} Note Max :
    {{trigger.event.data.data.max }}
  title: Nouvelle note pour {{ trigger.event.data.child_name }}

le : {{ ‹ \n › -}} permet de retourner à la ligne car sur l’iPhone il y a un comportement différent avec le /n.
si cela peut aider :slight_smile: