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

Tiens je viens de remarquer que tu as fait une faute de frappe dans le no de version sur HACS: la version c’est désormais la 1.13.6 !

On est donc passé en version 1 :champagne:

@delphiki
J’ai désactivé ce matin mes 3 comptes Pronote, je n’ai plus aucun probleme de Ram Core qui monte avec restart HA obligé après 2 jours… Ca vient bien de Pronote donc…

Ce soir toujours encéphalogramme plat de la ram avec PRONOTE désactivé

Arg ! oui ! il doit y avoir une petite fuite mémoire :scream:
Devinez quand j’ai installé l’intégration Pronote ? :stuck_out_tongue_winking_eye:


@delphiki : si tu peux faire quelque chose rapidement ?:pray:t2:

Bon en attendant la correction du bug de mémoire, j’ai repris tous le design que j’avais fait sur mon intégration d’origine (Pronote2HomeAssistant) et j’ai rappliqué tout ça au modèle qu’avait fourni @delphiki un peu plus haut (qui lui même s’était inspiré du mien il me semble :wink:)

Le design ça donne ça :

Voila le contenu complet du fichier /homeassistant/custom_templates/pronote.jinja :

{%- macro absences_markdown(firstname, sensor_id) -%}
{% set items = state_attr(sensor_id,'absences') %}
<div>{{ firstname }} - Absences</div>
<table>
        {%- for item in items -%}
        <tr>
            <td width="50%">
                Le {{as_timestamp(item.from) | int | timestamp_custom('%d %b à %Hh%M', true)}}
                <br>{{item.hours}} de cours manqué(s)</td>
            <td>
            {%- if item.reason == '' -%}
                Motif : inconnu<br/>
            {%- else -%}
                Motif : {{item.reason}}<br/>
            {% endif %}
            {%- if item.justified == false -%}
                <span>Absence non justifiée</span>
            {%- else -%}
                <mark>Absence justifiée</mark>
            {% endif %}</td>               
        </tr>
        {% endfor %}
</table>
{% endmacro %}

{%- macro homework_markdown(firstname, sensor_id) -%}
{% set days = ["Lun.", "Mar.", "Mer.", "Jeu.", "Ven.", "Sam.", "Dim."] %}
{% set items = state_attr(sensor_id,'homework') %}
<div>{{ firstname }} - Devoirs</div>
<table>
        {%- for item in items -%}
            <tr>
                <td>{{ days[item.date.strftime('%w')| int - 1] }} {{as_timestamp(item.date) | int | timestamp_custom('%d/%m', true)}}</td>
                <td><span></span></td>
                <td><b>{{ item.subject}}</b><br>{{ item.short_description }}</td>
                <td>{%- if item.done -%}<mark>fait</mark>{%- else -%}<span>non_fait</span>{%- endif -%}</td>
           </tr>
        {% endfor %}
</table>
{% endmacro %}

{%- macro grades_markdown(firstname, sensor_id) -%}
{% set items = state_attr(sensor_id,'grades') %}
<div>{{ firstname }} - Notes</div>
<table>
        {%- for item in items -%}
            <tr>
                <td width="20%">{{as_timestamp(item.date) | int | timestamp_custom('%d/%m', true)}}</td>
                <td><span></span></td>
                <td><b>{{ item.subject}}</b><br>{{ item.comment }}</td>
                <td width="30%"><b>{{ item.grade_out_of }} </b>
                {%- if item.coefficient != '1' -%} <i>(Coeff. : {{ item.coefficient }})</i>{% endif %}
                <ul>
                <li>Moy. cl.: {{ item.class_average }}</li>
                <li>Min-max : {{ item.min }}-{{ item.max }}</li>
                </ul>
                </td>
           </tr>
        {% endfor %}
</table>
{% endmacro %}

{%- macro timetable_markdown(firstname, sensor_id) -%}
    {%- if as_timestamp(now())|int <= as_timestamp((state_attr(sensor_id, 'lessons')|last).end_at)|int + (3*3600) -%}
        {% set days = ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"] %}
        {% set items = state_attr(sensor_id,'lessons') %}
        <div>
            {{ firstname }} - {{ days[items[0].start_at.strftime('%w')| int - 1] }} {{as_timestamp(items[0].start_at) | int | timestamp_custom('%d/%m', true)}}
            - Début à {{ as_timestamp(state_attr(sensor_id,'day_start_at'))| int | timestamp_custom('%-Hh%M', true) }}
        </div>
        <table>
            {%- for item in items -%}
                {%- set canceled = item.canceled == True -%}
                <tr>
                    <td>
                        {{ item.start_time }}<br />
                        {{ item.end_time }}
                    </td>
                    <td>
                        <span></span>
                    </td>
                    <td>
                        {%- if canceled -%}<del>{%- endif -%}
                        <b>{{ item.lesson }}</b>
                        {%- if canceled -%}</del>{%- endif -%}
                        <br />
                        Salle {{ item.classroom }}
                    </td>
                    <td>
                        {%- if canceled -%}
                            <mark>{{ item.status }}</mark>  
                        {%- elif item.status != None -%}
                            <span>{{ item.status }}</span>
                        {%- endif -%}
                    </td>
                </tr>
            {%- endfor -%}
        </table>
    {%- endif -%}
{% endmacro %}

{%- macro pronote_styles(sensor_id) -%}
    div {
        background-color:rgb(50, 50, 50);
        padding: 12px;
        color:white;
        font-weight:normal;
        font-size:1.2em;
        border-top-left-radius: 5px; 
        border-top-right-radius: 5px;
    }
    table{
        font-size: 0.9em;
        font-family: Roboto;
        width: 100%;
        outline: 0px solid #393c3d;
        margin-top:5px;
        border-collapse: collapse;
    }
    td {
        vertical-align: middle;
    }
    tr td:last-child span {
        background-color: #EC4B34;
        padding: 4px;
        border-radius: 4px;
        white-space: nowrap;
    }
    mark {
        background-color: #009767;
        padding: 4px;
        border-radius: 4px;
        white-space: nowrap;
        margin-top:3px
    }
    @media (prefers-color-scheme: dark) {
        tr:nth-child(even) {background-color: #242424;}
    }
    @media (prefers-color-scheme: light) {
        tr:nth-child(odd) {background-color: #e9e9e9;}
    }    
    tr td:nth-child(2) {
        width: 4px;
        padding: 5px 0;
    }

    {%- if sensor_id == "sensor.pronote_xxxxxxxxx_timetable_next_day" -%}
     
        tr td:nth-child(2) > span {
            display:inline-block;
            width: 4px;
            height: 3rem;
            border-radius:4px;
        }
    
        tr td:first-child {
            width: 13%;
            text-align:right;
        }
        {%- set items = state_attr(sensor_id, 'lessons') -%}
        {%- for i in range(0, items | count, 1) -%}
            {%- if items[i].canceled and not loop.last and items[i].start_at == items[i+1].start_at -%}
                tr:nth-child({{ loop.index }}) {
                    display:none;
                }
            {%- else -%}
                tr:nth-child({{ loop.index }}) td:nth-child(2) > span {
                    background-color: {{items[i].background_color}};
                }
                {% if as_timestamp(now()) > as_timestamp(items[i].end_at) %}
                    tr:nth-child({{ loop.index }}) {
                        opacity: 0.3;
                    }
                {% endif %}
            {%- endif -%}
        {%- endfor -%}
    {% endif %}
    
    {%- if sensor_id == "sensor.pronote_xxxxxxxxx_homework" -%}
        tr td:nth-child(2) > span {
            display:inline-block;
            width: 4px;
            height: 3rem;
            border-radius:4px;
        }
        
        tr td:first-child {
            width: 13%;
            text-align:center;
            white-space: nowrap;
        }

        {%- set items = state_attr(sensor_id, 'homework') -%}
        {%- for i in range(0, items | count, 1) -%}
            tr:nth-child({{ loop.index }}) td:nth-child(2) > span {
                background-color: {{items[i].background_color}};
            }

        {%- endfor -%}
    {% endif %}


    {%- if sensor_id == "sensor.pronote_xxxxxxxxxxx_grades" -%}
        tr td:nth-child(2) > span {
            display:inline-block;
            width: 4px;
            height: 3rem;
            border-radius:4px;
        }
        tr td:first-child {
            width: 15%;
            text-align:center;
            white-space: nowrap;
        }
        tr td:last-child {
            width: 30%;
            white-space: nowrap;
        }
        
        {%- set items = state_attr(sensor_id, 'grades') -%}
        {%- for i in range(0, items | count, 1) -%}
            {%- if items[i].grade >= items[i].class_average -%}
                tr:nth-child({{ loop.index }}) td:nth-child(2) > span {
                    background-color: #009767;
                }
            {%- else -%}    
                tr:nth-child({{ loop.index }}) td:nth-child(2) > span {
                    background-color: #EC4B34;
                }
            {%- endif -%}    
        {%- endfor -%}
    {% endif %}

    ul{
        padding: 0px 0px 0px 0px;
        margin: 0px;
        list-style-type:none;
    }
    li{
        padding: 0px 0px 0px 0px;
        font-style: italic;
        color: grey;
    }
    tr.canceled td {
        color: orange;
    }
    td {
        padding: 5px 10px 5px 10px;
        text-align: left;
        vertical-align: top;
    }
{%- endmacro -%}

Et voici le Lovelace de chaque bloc

L’emploi du temps du prochain jour :

type: markdown
content: >-
  {%- from 'pronote.jinja' import timetable_markdown -%} {{-
  timetable_markdown('Pronote',
  'sensor.pronote_simon_timetable_next_day') -}}
card_mod:
  style:
    .: |
      ha-card ha-markdown {
        padding:0px
      }
      ha-card ha-markdown.no-header {
        padding:0px
      }
    ha-markdown$: >
      {%- from 'pronote.jinja' import pronote_styles -%} {{-
      pronote_styles('sensor.pronote_simon_timetable_next_day') -}}

le bloc des devoirs :

type: markdown
content: >-
  {%- from 'pronote.jinja' import homework_markdown -%} 
  {{-homework_markdown('Pronote','sensor.pronote_simon_homework')-}}
card_mod:
  style:
    .: |
      ha-card ha-markdown {
        padding:0px
      }
      ha-card ha-markdown.no-header {
        padding:0px
      }
    ha-markdown$: >
      {%- from 'pronote.jinja' import pronote_styles -%} {{-
      pronote_styles('sensor.pronote_simon_homework') -}}

Les notes :

type: markdown
content: >-
  {%- from 'pronote.jinja' import grades_markdown -%} 
  {{-grades_markdown('Pronote','sensor.pronote_simon_grades')-}}
card_mod:
  style:
    .: |
      ha-card ha-markdown {
        padding:0px
      }
      ha-card ha-markdown.no-header {
        padding:0px
      }
    ha-markdown$: >
      {%- from 'pronote.jinja' import pronote_styles -%} {{-
      pronote_styles('sensor.pronote_simon_grades') -}}

Les absences :

type: markdown
content: >-
  {%- from 'pronote.jinja' import absences_markdown -%} 
  {{-absences_markdown('Pronote','sensor.pronote_simon_absences')-}}
card_mod:
  style:
    .: |
      ha-card ha-markdown {
        padding:0px
      }
      ha-card ha-markdown.no-header {
        padding:0px
      }
    ha-markdown$: >
      {%- from 'pronote.jinja' import pronote_styles -%} {{-
      pronote_styles('sensor.pronote_simon_absences') -}}

Voila ! j’espère que ça servira a ceux qui n’ont pas le design d @herveaurel et qui veulent qqchose de rapide

3 « J'aime »

Merci beaucoup; je vais tester cela.
Il y a besoin de creer ou installer qqchose de specifique pour la partie pronote.jinga? Hormis creer le rep custom_templates et pronote.jinga et coller ton code?

1 « J'aime »

non rien de spécial sauf installer card_mod - et jinja et pas jinga

Hello à tous (et joyeuses fêtes !),

Concernant la fuite mémoire j’ai déjà commencé à regarder pour l’instant sans trop de résultats probants (la piste du dépassement de la limite de taille des attributs des sensors n’a rien donné pour le moment).
Je suis en congés sans pc cette semaine mais je m’y remet quand je rentre :slight_smile:

2 « J'aime »

Il faut installer qqhcose pour jinja?

C’est inclus dans HA

https://jinja.palletsprojects.com

Intégration Pronote (0.13.6) : cours, devoirs, notes, etc - Home Assistant - Tutoriels & Partages / Intégration - Home Assistant Communauté Francophone (hacf.fr)

Salut,

C’est top.
Quelques remarques :
pour les absences et cours today si le sensor est indisponible (par exemple vacances) on a :
image

Pour les devoirs chez moi ça se présente comme ça :

Enfin ce serait top d’avoir la même chose pour la moyenne générale et les évaluations.
Merci d’avance

La Table

{%- macro averages_markdown(firstname, sensor_id) -%}
{% set items = state_attr(sensor_id,'averages') %}
<div>{{ firstname }} - Moyennes</div>
<table>
        {%- for item in items -%}
            <tr>
                <td><span></span></td>
                <td ><b>{{ item.subject}}</b></td>
                <td width="30%"><b>{{ item.average }} </b>
                <ul>Classe {{ item.class }} ({{ item.min }} / {{ item.max }})</ul>
                </td>     
           </tr>
        {% endfor %}
</table>
{% endmacro %}

La mise en forme

    {%- if sensor_id == "sensor.pronote_XXX_XXX_averages" -%}
        tr td:first-child > span {
            display: inline-block;
            width: 4px;
            max-width: 4px;
            height: 3rem;
            border-radius: 4px;
        }


        tr td:nth-child(2)  {
            display: inline-block;
            width: auto;
            height: 3rem;
            border-radius: 4px;
        }
        tr td:last-child {
            
            white-space: nowrap;
        }
        tr td:last-child > ul {
            color: var(--primary-text-color);
            text-align: right;
        }
        
        {%- set items = state_attr(sensor_id, 'averages') -%}
        {%- for i in range(0, items | count, 1) -%}
            {%- if items[i].average >= items[i].class -%}
                tr:nth-child({{ loop.index }}) td:first-child > span{
                    background-color: #009767;
                }
            {%- else -%}    
                tr:nth-child({{ loop.index }}) td:first-child > span {
                    background-color: #EC4B34;
                }
                tr:nth-child({{ loop.index }}) td:last-child {
                    color: #EC4B34;
                }
                tr:nth-child({{ loop.index }}) td:last-child > ul {
                    color: var(--primary-text-color);
                }
            {%- endif -%}    
        {%- endfor -%}
    {% endif %}

1 « J'aime »

Super c’est au top.
Une idée pourquoi avec le code au dessus les devoirs sont présentés ainsi :

Désolé mais là, je suis perdu…j’avais des intégrations plus ou moins fonctionnelles, mais la avec le « jinja », j’ai bien créé le fichier pronote.jinja dans le sous repertoire, j’ai collé le code mais apres, je sais pas comment créér les tables + style pour que ca fonctionne correctement: j’ai bien essayé des cards markdown (mais le style marche pas, enfin je sais pas quoi en faire). De plus, je comprend pas trop l’intéret de passer par ce fichier jinja, ca change quelque chose par rapport à avant ?
Le top serait d’avoir une synthèse comme avait fait Sigalou mais a jour.
La, je suis perdu…

Il suffit d’ajouter un if dans le code de la carte Markdown

Exemple

type: markdown
content: >-
  {% if states('sensor.pronote_xxxxx_simon_timetable_today')  != 'unavailable' %}
    {%- from 'pronote.jinja' import timetable_markdown -%} {{-
    timetable_markdown('Pronote Simon',
  'sensor.pronote_xxxxxx_simon_timetable_today') -}}
  {% endif %}
card_mod:
  style:
.....etc....

Voici les étapes :

Etape 1 : Installation de l’intégration Pronote
ça a priori tu dois savoir faire - ça se fait via HACS

Etape 2 - Vérification que l’intégration fonctionne
Se rendre dans les outils de deveveloppement et tester la valeur d’un sensor
Dans outils de développement > onglet état
Ensuit définir état et saisir sensor.pronote_XXXXX_XXXXXX
Et valider
cela doit afficher des choses en dessous…si c’est le pas le cas c’est que l’installation / configuration n’a pas fonctionné

Etape 3 : copie du fichier de macro avant la création des cartes
Copier le contenu complet du fichier /homeassistant/custom_templates/pronote.jinja fourni dans de tread Intégration Pronote (0.13.6) : cours, devoirs, notes, etc - #1078 par Dathosim
ATTENTION : remplacer les « sensor.pronote_xxxxxxxxx » par votre nom_prenom a plusieurs endroits dans le fichier (devant des if)

Etape 4 : recharger la configuration des templates
Il faut aller dans outils de développement > services
Et lancer le service : homeassistant.reload_custom_templates

Etape 5 : Création des cartes Lovelace de type markdown
se mettre en mode modification de dashboard, puis ajouter carte de type markdown
Et copier coller le contenu d’une des cartes fournies dans ce message Intégration Pronote (0.13.6) : cours, devoirs, notes, etc - #1078 par Dathosim
les blocs de code qui commence par markdown
ATTENTION : remplacer le nom des sensor (simon dans mon exemple sans le nom) par votre nom_prenom - a 2 endroits dans chaque carte

1 « J'aime »

oui j’ai eu ce problème aussi…
joue avec l’indentation dans la macro homework_markdown
Par exemple essaye d’aligner le for avec le TR

<table>
        {%- for item in items -%}
        <tr>
            <td>{{ days[item.date.strftime('%w')| int - 1] }} {{as_timestamp(item.date) | int | timestamp_custom('%d/%m', true)}}</td>
            <td><span></span></td>
            <td><b>{{ item.subject}}</b><br>{{ item.short_description }}</td>
            <td>{%- if item.done -%}<mark>fait</mark>{%- else -%}<span>non_fait</span>{%- endif -%}</td>
        </tr>
        {% endfor %}

aussi avec l’inspecteur du navigateur (tu connais ?) tu peux voir ce qui se glisse dans cet espace

Peut être préciser de dupliquer les if dans la partie 3 par enfant :wink:

Merci c’est ce que j’ai fini par faire au top.

Je vais tester ça. Merci d’avoir pointé la bonne direction.