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

Je bossais justement hier soir sur une historisation des moyennes pour pouvoir sortir des courbes quand j’ai vu les données disparaitre suite au changement de trimestre.

J’ai jeté un oeil à l’intégration du coup et ai essayé de bidouiller pour recevoir les ‹ periods › (au moins dans un premier temps pour ensuite appeler periods[xxx].averages mais je n’ai pas réussi à partir des bouts de code que j’ai identifiés.
@delphiki, pronotepy normalement met à disposition tout ça. Tu penses que tu pourrais l’ajouter à l’intégration ? les moyennes par période ?

De mon côté je peux vous partager l’automatisation pour historiser les moyennes que j’ai préparée et qui fonctionne à priori même s’il doit y avoir moyen de mieux faire…

alias: Moyennes PRENOM
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.pronote_NOM_PRENOM_averages
condition: []
action:
  - service: input_number.set_value
    data:
      value: >-
        {% set ns = namespace(moyenne=0) %} {% set items =
        state_attr('sensor.pronote_NOM_PRENOM_averages','averages')%}
          {% for i in range(0, items | count, 1) if items[i].subject == 'FRANCAIS' %}
             {% set ns.moyenne = items[i].average | replace (',','.')|float(0) %}
          {% endfor %}
          {{ ns.moyenne }}
    target:
      entity_id: input_number.moyenne_francais_PRENOM
  - service: input_number.set_value
    data:
      value: >-
        {% set ns = namespace(moyenne=0) %} {% set items =
        state_attr('sensor.pronote_NOM_PRENOM_averages','averages')%}
          {% for i in range(0, items | count, 1) if items[i].subject == 'HISTOIRE-GEOGRAPHIE' %}
             {% set ns.moyenne = items[i].average | replace (',','.')|float(0) %}
          {% endfor %}
          {{ ns.moyenne }}
    target:
      entity_id: input_number.moyenne_histoire_geo_PRENOM
  - service: input_number.set_value
    data:
      value: >-
        {% set ns = namespace(moyenne=0) %} {% set items =
        state_attr('sensor.pronote_NOM_PRENOM_averages','averages')%}
          {% for i in range(0, items | count, 1) if items[i].subject == 'PHYSIQUE-CHIMIE' %}
             {% set ns.moyenne = items[i].average | replace (',','.')|float(0) %}
          {% endfor %}
          {{ ns.moyenne }}
    target:
      entity_id: input_number.moyenne_physique_chimie_PRENOM
  - service: input_number.set_value
    data:
      value: >-
        {% set ns = namespace(moyenne=0) %} {% set items =
        state_attr('sensor.pronote_NOM_PRENOM_averages','averages')%}
          {% for i in range(0, items | count, 1) if items[i].subject == 'MATHEMATIQUES' %}
             {% set ns.moyenne = items[i].average | replace (',','.')|float(0) %}
          {% endfor %}
          {{ ns.moyenne }}
    target:
      entity_id: input_number.moyenne_mathematiques_PRENOM
  - service: input_number.set_value
    data:
      value: >-
        {% set ns = namespace(moyenne=0) %} {% set items =
        state_attr('sensor.pronote_NOM_PRENOM_averages','averages')%}
          {% for i in range(0, items | count, 1) if items[i].subject == 'ESPAGNOL LV2' %}
             {% set ns.moyenne = items[i].average | replace (',','.')|float(0) %}
          {% endfor %}
          {{ ns.moyenne }}
    target:
      entity_id: input_number.moyenne_espagnol_lv2_PRENOM
  - service: input_number.set_value
    data:
      value: >-
        {% set ns = namespace(moyenne=0) %} {% set items =
        state_attr('sensor.pronote_NOM_PRENOM_averages','averages')%}
          {% for i in range(0, items | count, 1) if items[i].subject == 'ANGLAIS LV1' %}
             {% set ns.moyenne = items[i].average | replace (',','.')|float(0) %}
          {% endfor %}
          {{ ns.moyenne }}
    target:
      entity_id: input_number.moyenne_anglais_lv1_PRENOM
  - service: input_number.set_value
    data:
      value: >-
        {% set ns = namespace(moyenne=0) %} {% set items =
        state_attr('sensor.pronote_NOM_PRENOM_averages','averages')%}
          {% for i in range(0, items | count, 1) if items[i].subject == 'ED.PHYSIQUE & SPORT.' %}
             {% set ns.moyenne = items[i].average | replace (',','.')|float(0) %}
          {% endfor %}
          {{ ns.moyenne }}
    target:
      entity_id: input_number.moyenne_ed_physique_sport_PRENOM
  - service: input_number.set_value
    data:
      value: >-
        {% set ns = namespace(moyenne=0) %} {% set items =
        state_attr('sensor.pronote_NOM_PRENOM_averages','averages')%}
          {% for i in range(0, items | count, 1) if items[i].subject == 'TECHNOLOGIE' %}
             {% set ns.moyenne = items[i].average | replace (',','.')|float(0) %}
          {% endfor %}
          {{ ns.moyenne }}
    target:
      entity_id: input_number.moyenne_technologie_PRENOM
  - service: input_number.set_value
    data:
      value: >-
        {% set ns = namespace(moyenne=0) %} {% set items =
        state_attr('sensor.pronote_NOM_PRENOM_averages','averages')%}
          {% for i in range(0, items | count, 1) if items[i].subject == 'ARTS PLASTIQUES' %}
             {% set ns.moyenne = items[i].average | replace (',','.')|float(0) %}
          {% endfor %}
          {{ ns.moyenne }}
    target:
      entity_id: input_number.moyenne_arts_plastiques_PRENOM
  - service: input_number.set_value
    data:
      value: >-
        {% set ns = namespace(moyenne=0) %} {% set items =
        state_attr('sensor.pronote_NOM_PRENOM_averages','averages')%}
          {% for i in range(0, items | count, 1) if items[i].subject == 'SCIENCES VIE & TERRE' %}
             {% set ns.moyenne = items[i].average | replace (',','.')|float(0) %}
          {% endfor %}
          {{ ns.moyenne }}
    target:
      entity_id: input_number.moyenne_sciences_vie_terre_PRENOM
  - service: input_number.set_value
    data:
      value: >-
        {% set ns = namespace(moyenne=0) %} {% set items =
        state_attr('sensor.pronote_NOM_PRENOM_averages','averages')%}
          {% for i in range(0, items | count, 1) if items[i].subject == 'EDUCATION MUSICALE' %}
             {% set ns.moyenne = items[i].average | replace (',','.')|float(0) %}
          {% endfor %}
          {{ ns.moyenne }}
    target:
      entity_id: input_number.moyenne_education_musicale_PRENOM
  - service: input_number.set_value
    data:
      value: >-
        {% set ns = namespace(moyenne=0) %} {% set items =
        state_attr('sensor.pronote_NOM_PRENOM_averages','averages')%}
          {% for i in range(0, items | count, 1) if items[i].subject == 'LCA LATIN' %}
             {% set ns.moyenne = items[i].average | replace (',','.')|float(0) %}
          {% endfor %}
          {{ ns.moyenne }}
    target:
      entity_id: input_number.moyenne_lca_latin_PRENOM
    enabled: true
  - service: input_number.set_value
    data:
      value: >-
        {% set items =
        state_attr('sensor.pronote_NOM_PRENOM_averages','averages')%} {%
        set ns = namespace(nombre=0, moyenne_generale=0) %}
          {% for i in range(0, items | count, 1) %}
             {% set ns.moyenne_generale = items[i].average | replace (',','.') | float(0) + ns.moyenne_generale %}
             {% set ns.nombre = ns.nombre + 1 %}
          {% endfor %}
        {% set ns.moyenne_generale = ns.moyenne_generale / ns.nombre %}   {{
        ns.moyenne_generale }}  
    target:
      entity_id: input_number.moyenne_generale_PRENOM
mode: single

Le plus fastidieux est de créer les input_number correspondant auparavant.

Ensuite on peut utiliser influx/grafana pour les graphs.

Voilà

Salut,

j’ai réussi comme ça :

{{as_datetime(states('sensor.pronote_camille_next_alarm')).isoformat()+'+0100'}} 

ok.
Et pour bien comprendre ta méthode (vu que tu es sur un format de type « modèle », tu en as fait un script ? Une automation ?
Preneur de ta solution pour améliorer la mienne :wink:

Salut,

une automation pour démarrer la google home à l’heure du réveil :

alias: Réveil Camille en fonction de Pronote
description: ""
trigger:
  - platform: time
    at: sensor.heure_reveil_camille
condition: []
action:
  - service: spotcast.start
    data:
      limit: 20
      force_playback: false
      random_song: false
      repeat: "off"
      shuffle: false
      offset: 0
      ignore_fully_played: false
      entity_id: media_player.google_home_camille
    enabled: true
mode: single
1 « J'aime »

Bonsoir à tous,

Je ne comprends pas trop… Tout fonctionnait très bien, et d’un coup ça n’a plus fonctionné pour l’un de mes enfants.

Bon, je me suis rendu compte qu’ils ont enfin corrigé une erreur dans son nom de famille, donc je pense que ça venait de là. Par contre, plus moyen de reconfigurer son compte (avec compte parent).

J’ai suivi la procédure de @Cedrix, j’arrive bien à me connecter depuis le site, mais impossible depuis l’intégration HA.

J’ai essayé avec le QR Code, mais ça ne fonctionne que pour 24 heures…

Auriez-vous une petite idée ?

Merci d’avance,
Rémi

Hello,

Depuis quelques temps, je ne saurais pas dire depuis quand, le sensor comportant les notes n’est plus disponible. Il n’y a plus de data retournées, en apparence, par pronote. Or il y a bien de nouvelles notes dans pronote. Comment activer un mode debug voir enregistrer le json en retour lors de l’appel à l’api pronote histoire de verifier a quel moment ca plante?

si cela peut m’aider à vous aider :slight_smile: j’ai l’erreur suivante:
homeassistant.components.recorder.db_schema : State attributes for sensor.pronote_xxx_timetable_period exceed maximum size of 16384 bytes.

Bonjour @Anas92600

Je pense que c’est le souci dont on parle un plus haut concernant les trimestres.
Je ne vois pour ma part plus que 2 notes dans le module (celles du 2nd trimestre) bien que tout soit accessible depuis Pronote.

2 « J'aime »

Bonjour,

Ce message d’erreur est sans rapport avec les notes. Il concerne l’emploi du temps mais est dores et déjà corrigé dans la dernière version du canal dev (je n’ai plus en mémoire le numéro qui lui a été attribué, peut-être 14 ou 14.5 mais j’ai des doutes). Reste à attendre la prochaine maj.

1 « J'aime »

lorsque je test l’api directement j’ai un plantage direct sur l’affichage du nombre de grades dans la période. comme si elle n’était plus accessible, et ce sur le Trimestre 1 et Trimestre 2:

python3 test.py
Traceback (most recent call last):
  File "/opt/homebrew/lib/python3.11/site-packages/pronotepy/clients.py", line 350, in post
    return self.communication.post(function_name, post_data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pronotepy/pronoteAPI.py", line 181, in post
    raise PronoteAPIError(
pronotepy.exceptions.PronoteAPIError: Unknown error from pronote: 3 | Accès refusé

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/Anas/Documents/pronotepy/test.py", line 22, in <module>
    print(len(period.grades))
              ^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pronotepy/dataClasses.py", line 528, in grades
    response = self._client.post("DernieresNotes", 198, json_data)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pronotepy/clients.py", line 367, in post
    return self.communication.post(function_name, post_data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pronotepy/pronoteAPI.py", line 181, in post
    raise PronoteAPIError(
pronotepy.exceptions.PronoteAPIError: Unknown error from pronote: 3 | Accès refusé

Hello tout le monde,

Désolé pour le manque de nouvelles/suivi ces derniers temps, je n’ai pas beaucoup de temps pour moi.
Ce week-end j’ai du temps, donc je vais essayer de reprendre les soucis un par un pour les corriger au mieux. :slight_smile:

1 « J'aime »

Je partage un petit quelque chose ici, c’est fonctionnel pour moi.
Avoir l’heure de début de journée, ainsi que celle de fin de journée plus la pause déjeuner si elle existe.
Pour le jour j
ou pour le prochain jour

1 - créer un fichier pronote.jinja dans le répertoire « custom_templates » (sous config si inexistant créer le)
2 - y insérer le code suivant

{%macro day(student) %}
{% if state_attr('sensor.pronote_' + student + '_timetable_today', 'day_end_at') != state_attr('sensor.pronote_' + student + '_timetable_today', 'day_start_at')%}
	{% if state_attr('sensor.pronote_' + student + '_timetable_today', 'lunch_break_start_at') != state_attr('sensor.pronote_' + student + '_timetable_today', 'day_end_at')%}
	{{state_attr('sensor.pronote_' + student + '_timetable_today' , 'day_start_at').strftime('%H:%M')}} - {{state_attr('sensor.pronote_' + student + '_timetable_today' , 'day_end_at').strftime('%H:%M')}} ({{state_attr('sensor.pronote_' + student + '_timetable_today' , 'lunch_break_start_at').strftime('%H:%M')}} - {{state_attr('sensor.pronote_' + student + '_timetable_today' , 'lunch_break_end_at').strftime('%H:%M')}})
	{% else %}
	{{state_attr('sensor.pronote_' + student + '_timetable_today' , 'day_start_at').strftime('%H:%M')}} - {{state_attr('sensor.pronote_' + student + '_timetable_today' , 'day_end_at').strftime('%H:%M')}}
	{% endif %}
{% endif %}
{% endmacro %}

{%macro next(student) %}
{% if state_attr('sensor.pronote_' + student + '_timetable_next_day', 'day_end_at') != state_attr('sensor.pronote_' + student + '_timetable_next_day', 'day_start_at')%}
	{% if state_attr('sensor.pronote_' + student + '_timetable_next_day', 'lunch_break_start_at') != state_attr('sensor.pronote_' + student + '_timetable_next_day', 'day_end_at')%}
	{{state_attr('sensor.pronote_' + student + '_timetable_next_day' , 'day_start_at').strftime('%H:%M')}} - {{state_attr('sensor.pronote_' + student + '_timetable_next_day' , 'day_end_at').strftime('%H:%M')}} ({{state_attr('sensor.pronote_' + student + '_timetable_next_day' , 'lunch_break_start_at').strftime('%H:%M')}} - {{state_attr('sensor.pronote_' + student + '_timetable_next_day' , 'lunch_break_end_at').strftime('%H:%M')}})
	{% else %}
	{{state_attr('sensor.pronote_' + student + '_timetable_next_day' , 'day_start_at').strftime('%H:%M')}} - {{state_attr('sensor.pronote_' + student + '_timetable_next_day' , 'day_end_at').strftime('%H:%M')}}
	{% endif %}
{% endif %}
{% endmacro %}

3 - faire une carte markdown dans lovelace et y insérer le code suivant pour les horaires du jour j
en veillant a remplacer « skywalker » par le nom et « luke » par le prénom de votre diable, attention au « _ », et puis si vous avez beaucoup de diables et bien vous refaites des nouvelles cartes

{% from 'pronote.jinja' import day %}
{{ day('skywalker_luke') }}

et pour le prochain jour:

{% from 'pronote.jinja' import next %}
{{ next('skywalker_luke') }}

Rien d’extravagant, mais si ca aide alors tant mieux.

J’ai remarqué depuis quelques temps le phénomène suivant:
Mon usage de la RAM sur mon PC augmente très progressivement, de ~20% au démarrage il augmente gentiment d’environ 5% par jour…

Je n’ai pas vraiment fait de modif depuis l’installation de l’intégration Pronote (je suis en v0.13.5) et je n’avais jamais observé ce phénomène avant.

Avez vous un comportement équivalent ?

J’avais pas mal de sensor en erreur (pas de devoirs, pas d’évaluation, pas de menu chez nous…), donc j’ai essayé de purger un peu mes cartes. Mais rien n’y fait.

Si je suis tout seul dans ce cas, c’est probablement pas Pronote, mais sinon, c’est peut être lié (en particulier l’erreur sur le sensor (sensor.pronote_xxx_timetable_period exceed maximum size of 16384 bytes.)…

1 « J'aime »

Ca me serait bien utile, merci beaucoup!
malheureusement je n’arrive pas a enregistrer le fichier pronote.jinja au bon endroit!
J’ai essayé :
/homeassistant/custom_templates/pronote.jinja puis /homeassistant/custom_components/pronote/pronote.jinja et enfin /homeassistant/custom_components/pronote/custom_templates/pronote.jinja
Dans ma carte markdown j’ai toujours cette erreur : TemplateNotFound: pronote.jinja :thinking:

Ma ram utilisée par HA CORE ne cesse d’augmenter aussi.
Je dois restart HA tous les 2-3 jours que pour ça.
Au démarrage je suis à 40%. 3 jours après je suis à + de 70%.

J’ai passé 1 semaine non stop à chassé tous les logs. Modifier mes 300 autos pour éviter les templates en déclencheurs, corrigé 100% de mes sensors templates. Tout optimisé.
Rien n’y fait.

le chemin c’est bien config/custom_templates/pronote.jinja

J’ai mis le chemin /homeassistant/config/custom_templates/pronote.jinja mais j’ai le même résultat :


Je dois me tromper ailleurs, je continue de chercher!

Avez vous redémarrer, parce que le répertoire « custom_templates » nécessite de redémarrer pour être pris en compte.

### REUSING TEMPLATES

You can write reusable Jinja templates by adding them to a `custom_templates` folder under your configuration directory. All template files must have the `.jinja` extension and be less than 5MiB. Templates in this folder will be loaded at startup. To reload the templates without restarting Home Assistant, invoke the [`homeassistant.reload_custom_templates`](https://my.home-assistant.io/redirect/developer_call_service?service=homeassistant.reload_custom_templates) service.

Oui j’ai bien redémarré home assistant

Je ne sais trop quoi vous dire mais en guise de solution mettez ca dans votre markdown en veillant à remplacer LUKE_SKYWALKER par le nom et le prénom de votre diable tel qu’indiqué dans l’id des entités pronote, le premier bloc pour le jour j, le second pour la prochaine journée de cours.

{% if state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_today', 'day_end_at') != state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_today', 'day_start_at')%}
	{% if state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_today', 'lunch_break_start_at') != state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_today', 'day_end_at')%}
	{{state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_today' , 'day_start_at').strftime('%H:%M')}} - {{state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_today' , 'day_end_at').strftime('%H:%M')}} ({{state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_today' , 'lunch_break_start_at').strftime('%H:%M')}} - {{state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_today' , 'lunch_break_end_at').strftime('%H:%M')}})
	{% else %}
	{{state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_today' , 'day_start_at').strftime('%H:%M')}} - {{state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_today' , 'day_end_at').strftime('%H:%M')}}
	{% endif %}
{% endif %}


{% if state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_next_day', 'day_end_at') != state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_next_day', 'day_start_at')%}
	{% if state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_next_day', 'lunch_break_start_at') != state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_next_day', 'day_end_at')%}
	{{state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_next_day' , 'day_start_at').strftime('%H:%M')}} - {{state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_next_day' , 'day_end_at').strftime('%H:%M')}} ({{state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_next_day' , 'lunch_break_start_at').strftime('%H:%M')}} - {{state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_next_day' , 'lunch_break_end_at').strftime('%H:%M')}})
	{% else %}
	{{state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_next_day' , 'day_start_at').strftime('%H:%M')}} - {{state_attr('sensor.pronote_SKYWALKER_LUKE_timetable_next_day' , 'day_end_at').strftime('%H:%M')}}
	{% endif %}
{% endif %}
1 « J'aime »