Pronota es una aplicación brillante de la empresa Index Education que equipa a la mayoría de las escuelas.

Si no lo sabes, sigue tu camino, no necesitas integrarlo en tu domótica.
|
Tenga cuidado, este Retex está desactualizado, de hecho desde junio de 2023, un integración (gracias viene Delphiki) cuidar de todo lo que se describe a continuación. Es posible que algunos enlaces o archivos de mi HA ya no coincidan con el resto de este texto. Por supuesto, recomendaría usar la integración. Aquí está el último Retex: Estoy trabajando en las tarjetas HA de Pronote. |
Esta integración se basa en el script Dathosim (¡Muchas gracias!)
https://github.com/dathosim/Pronote2Homeassistant
Modifiqué algunas líneas del código, ya sea para adaptarme a mi uso o para adaptarme a los nuevos estándares HA (plataforma: plantilla/sensores: convertirse en plantilla:/sensor, por ejemplo)
Instalación de la biblioteca PronotePy
Es una biblioteca python desarrollada en código abierto: pronotepy
Para instalar esta biblioteca, ejecute en la línea de comandos:
pip instalar pronotepy
o para tener la última versión (no recomendada):
pip install https://github.com/bain3/pronotepy/archive/refs/heads/master.zip
De vez en cuando, tienes que pensar en lanzar una pequeña foto de:
pip install –upgrade pronotepy
Instalación de la secuencia de comandos Dathosim python
Vaya a la carpeta /config de su HA y cree una nueva carpeta que se pueda llamar _scripts de pitón y que contendrá sus scripts personalizados.

En esta carpeta /config/python_scripts, coloque los archivos pronote.py y config.ini de distribución Pronote2Homeassistant.

Configurar el script de Python
Es necesario editar el archivo config.ini y añadir información específica.
Configuración específica Sigalou
Tuve problemas para identificarme con el atrio Otorrinolaringológico _sud. Por alguna razón, tuve que cambiar el script de Python. Voy a pasar esta información a Dathosim para ver qué pasa. Doy aquí mis modificaciones, pueden ser útiles. He modificado la línea 57.
# client = (pronotepy.ParentClient if type _account == 'parent' else pronotepy.Client)(url, username, password, ent) client = (pronotepy.ParentClient if type _account == 'parent' else pronotepy.Client)('https://0xx0xxxx.index-education.net/pronote/mobile.parent.html', username = 'xxxxxx', password='yyyyyy', ent=atrium _sud)
- Para obtener la URL, fui a pronote para mirar la URL propuesta cuando parpadeaba el código QR.
- Para xxxx tienes que introducir el nombre de usuario y yyyy la contraseña.
Con esto, el guión funciona perfectamente. Si eres un poco más afortunado que yo, todo debería funcionar bien con el script proporcionado completando el archivo de configuración con tus credenciales.
Inicie el script
Aquí es donde tienes que cruzar los dedos para asegurarte de que todo va bien.
Debe conectarse a la línea de comandos SSH, vaya a la carpeta phyton_scripts creada anteriormente con una de las siguientes opciones:
cd /config/python_scripts
cd /usr/share/hassio/homeassistant/python_scripts/ (en Dathosim)
luego ejecute el script con:
python3 pronote.py
Si no sucede nada especial, ningún mensaje de error es que está bien, el script salió bien.

Cuando todo salió bien, un archivo 20 de noviembre de 2008: _prenomenfant.json se crea en /config/www
Es este archivo el que será consultado por HA para recuperar la información.
Automatizar el lanzamiento del script
Existe el método clásico, probablemente preferido por los puristas de Linux, es decir, agregar un crontab
*/10 * * * /usr/bin/python3 /usr/share/hassio/homeassistant/python_scripts/pronote.py > /tmp/pronote.log 2>&1
o dependiendo de su sistema:
*/10 * * * * /config/python_scripts/pronote.py > /tmp/pronote.log 2>&1
Este no es el método que he elegido, me gustaría usar 100% Home Assistant y en mi fase de aprendizaje, miré cómo lanzar un cron y cómo lanzar un script de Python.
Adición de una automatización que lanza un comando shell
HA llama a esto un patrón de temporizador
Añado un archivo shell _command.yaml a mi archivo configuration.yaml
![]()
Añado en este archivo de shell _command.yaml:
Update_pronote (en inglés): python3 /config/python_scripts/pronote.py
En Automatizaciones, añado una nueva automatización que lanzará la actualización del script_pronote

El gatillo es un gatillo cada 10 minutos

y la acción es un comando shell que lanza update_pronote

En el modo YAML, esto da:

Cada 10 minutos, tengo el archivo /config/www/pronote_enfant.json generado.
Recuperar datos
Es entonces HA quien lanzará las consultas REST para obtener los datos
Dathosim da todas las solicitudes para lanzar, están en:
https://github.com/dathosim/Pronote2Homeassistant/blob/main/configuration.yaml
Por supuesto, es necesario sustituir:
- demo por el nombre del menor
- 192.168.XX.XX por la dirección IP de HA
He modificado algunas sintaxis o sensores (las plantillas), ver mi archivo templates.yaml
Crear pantalla de Pronote
El último paso es mostrar los sensores que comienzan con el pronote … en los mapas para hacer una pantalla hermosa.
Aquí está el código de la pantalla de Dathosim: https://github.com/dathosim/Pronote2Homeassistant/blob/main/lovelace.yaml
Aquí está mi código:
Tipo: columnas horizontales: 2 cuadrados: Tarjetas falsas: - tipo: tarjetas de pila vertical: - tipo: contenido de la reducción: | -
<div>Horario de hoy </div>
<table>
<tbody>
{%-para attr en states.sensor.pronote_edt_coralie_today.attributes.edt_today -%}
<tr style="background-color:#FF0000"><td>
{%- if state_attr('sensor.pronote_edt_coralie_today', 'edt_today')[loop.index-1]['cancellation'] == false -%}
<mark>
{{state _attr('sensor.pronote_edt_coralie_today', 'edt_today')[loop.index-1]['hour']}}
</mark>
{%- de lo contrario -%}
<span>
{{state _attr('sensor.pronote_edt_coralie_today', 'edt_today')[loop.index-1]['hour']}}
</span>
{% endif %}</td>
<td>{{state _attr('sensor.pronote_edt_coralie_today', 'edt_today')[loop.index-1]['_fin time']}}</td>
<td>
{{state _attr('sensor.pronote_edt_coralie_today', 'edt_today')[loop.index-1]['course']}} {% si no se indica _attr('sensor.pronote_edt_coralie_today', 'edt_today')[loop.index-1]['status'] == Ninguno %}<span>{{state _attr('sensor.pronote_edt_coralie_today', 'edt_today')[loop.index-1]['status']}}</span>
{% endif %}</td>
<td>{{state _attr('sensor.pronote_edt_coralie_today', 'edt_today')[loop.index-1]['room']}}</td>
</tr>
{% endfor %}
</tbody>
</table>
tarjeta_mod: estilo: .: | ha-card ha-markdown { relleno:0px } ha-card ha-markdown.no-header { relleno:0px } ha-markdown$: | div { fondo-color:rgb(100, 100, 100); relleno: 12px 12px; color: blanco; peso de la fuente:normal; tamaño de fuente:1.2em; radio frontera-arriba-izquierda: 5px; frontera-arriba-derecha-radio: 5px; } tabla{ frontera-colapso: colapso; tamaño de fuente: 0.9em; familia de fuentes: Roboto; anchura: 100%; esbozo: 0px sólido #393c3d; margen superior: 5px; } subtítulo { text-align: centro; peso de fuente: negrita; tamaño de fuente: 1.2em; } td { relleno: 5px 10px 5px 10px; Alineación de texto: izquierda; frontera inferior: 0px sólido #1 quater de 2020; } tr { borde inferior: 0px sólido #1 quater de 2020; } tr:nth-of-type(even) { color de fondo: rgb(54, 54, 54, 0.3); } tr:último de tipo { border-bottom: transparente; }* marca { fondo: #009767; color: #222627; radio fronterizo: 5px; relleno: 5px; } span { fondo: #EC4B34; color: #222627; radio fronterizo: 5px; relleno: 5px; } span { relleno: 5px; } tr:nth-child(n+2) > td:nth-child(2) { texto-alineación: izquierda; } - tipo: contenido de la reducción: >-
<div>Uso del tiempo de: {{state _attr('sensor.pronote_edt_coralie_nextday', 'edt_nextday')[0]['date']}}</div>
<table>
<tbody>
{%-para attr en states.sensor.pronote_edt_coralie_nextday.attributes.edt_nextday -%}
<tr style="background-color:#FF0000"><td>
{%- if state_attr('sensor.pronote_edt_coralie_nextday', 'edt_nextday')[loop.index-1]['cancellation'] == false -%}
<mark>
{{state _attr('sensor.pronote_edt_coralie_nextday', 'edt_nextday')[loop.index-1]['hour']}}
</mark>
{%- de lo contrario -%}
<span>
{{state _attr('sensor.pronote_edt_coralie_nextday', 'edt_nextday')[loop.index-1]['hour']}}
</span>
{% endif %}</td>
<td>{{state _attr('sensor.pronote_edt_coralie_nextday', 'edt_nextday')[loop.index-1]['_fin time']}}</td>
<td>
{{{state _attr('sensor.pronote_edt_coralie_nextday', 'edt_nextday')[loop.index-1]['curso']}} {% si no se indica _attr('sensor.pronote_edt_coralie_nextday', 'edt_nextday')[loop.index-1]['status'] == Ninguno %}<span>{{state _attr('sensor.pronote_edt_coralie_nextday', 'edt_nextday')[loop.index-1]['status']}}</span>
{% endif %}</td>
<td>{{state _attr('sensor.pronote_edt_coralie_nextday', 'edt_nextday')[loop.index-1]['room']}}</td>
</tr>
{% endfor %}
</tbody>
</table>
tarjeta_mod: estilo: .: | ha-card ha-markdown { relleno:0px } ha-card ha-markdown.no-header { relleno:0px } ha-markdown$: | div { fondo-color:rgb(100, 100, 100); relleno: 12px 12px; color: blanco; peso de la fuente:normal; tamaño de fuente:1.2em; radio frontera-arriba-izquierda: 5px; frontera-arriba-derecha-radio: 5px; } tabla{ frontera-colapso: colapso; tamaño de fuente: 0.9em; familia de fuentes: Roboto; anchura: 100%; esbozo: 0px sólido #393c3d; margen superior: 5px; } subtítulo { text-align: centro; peso de fuente: negrita; tamaño de fuente: 1.2em; } td { relleno: 5px 10px 5px 10px; Alineación de texto: izquierda; frontera inferior: 0px sólido #1 quater de 2020; } tr { borde inferior: 0px sólido #1 quater de 2020; } tr:nth-of-type(even) { color de fondo: rgb(54, 54, 54, 0.3); } tr:último de tipo { border-bottom: transparente; }* marca { fondo: #009767; color: #222627; radio fronterizo: 5px; relleno: 5px; } span { fondo: #EC4B34; color: #222627; radio fronterizo: 5px; relleno: 5px; } span { relleno: 5px; } tr:nth-child(n+2) > td:nth-child(2) { texto-alineación: izquierda; } - tipo: contenido de la reducción: | -
<div>Deberes</div>
<table>
<tbody>
{%-para attr en states.sensor.pronote_devoir_coralie.attributes.devoir -%}
<tr>
<td>
{%- if state_attr('sensor.pronote_devoir_coralie', 'duty')[loop.index-1]['done'] == true -%}
<mark>
{{state _attr('sensor.pronote_devoir _coralie', 'deber')[loop.index-1]['date']}}
</mark>
{%- de lo contrario -%}
<span>
{{state _attr('sensor.pronote_devoir _coralie', 'deber')[loop.index-1]['date']}}
</span>
{% endif %}</td>
<td>{{state _attr('sensor.pronote_devoir _coralie', 'deber')[loop.index-1]['title']}}</td>
<td>{{state _attr('sensor.pronote_devoir _coralie', 'duty')[loop.index-1]['description']}}</td>
</tr>
{% endfor %}
</tbody>
</table>
tarjeta_mod: estilo: .: | ha-card ha-markdown { relleno:0px } ha-card ha-markdown.no-header { relleno:0px } ha-markdown$: | h1 { peso de fuente: normal; tamaño de fuente: 24px; } div { color de fondo: rgb (100, 100, 100); relleno: 12px 12px; color: blanco; peso de la fuente:normal; tamaño de fuente:1.2em; radio frontera-arriba-izquierda: 5px; frontera-arriba-derecha-radio: 5px; } tabla{ frontera-colapso: colapso; tamaño de fuente: 0.9em; familia de fuentes: Roboto; anchura: auto; esbozo: 0px sólido #393c3d; margen máximo: 10px; } subtítulo { text-align: centro; peso de fuente: negrita; tamaño de fuente: 1.2em; } td { relleno: 5px 5px 5px 5px; Alineación de texto: izquierda; frontera inferior: 0px sólido #1 quater de 2020; } tr { borde inferior: 0px sólido #1 quater de 2020; } tr:nth-of-type(even) { color de fondo: rgb(54, 54, 54, 0.3); } tr:último de tipo { border-bottom: transparente; } marca { fondo: #009767; color: #222627; radio fronterizo: 5px; relleno: 5px; } span { fondo: #EC4B34; color: #222627; radio fronterizo: 5px; relleno: 5px; } span { relleno: 5px; } tr:nth-child(n+2) > td:nth-child(2) { texto-alineación: izquierda; } - tipo: contenido de la reducción: | -
<div>Evaluaciones</div>
<table width='100%'>
<tbody>
{%-para attr en states.sensor.pronote_eval_coralie.attributes.evaluation -%} {% si loop.index < 40 %}
<tr>
<td width='10%'>{{attr['date _courte']}}</td>
<td width='70%'>{{attr['eval']}}</td>
<td width='20%'>
{%fo attr2 en attr.adquisiciones-%}{% if attr2['adquisición _level'] == "A+" %} 💚 {% elif attr2['adquisición _level'] == "A" %} 🟢 {% elif attr2['adquisición _level'] == "B+" %} ⚪ + {% elif attr2['adquisición _level'] == "B" %} ⚪ {% elif attr2['adquisición _level'] == "C+" %} 🟡+ {% elif attr2['adquisición _level'] == "C" %} 🟡 {% elif attr2['adquisición _level'] == "D+" %} ⚪ + {% elif attr2['adquisición _level'] == "D" %} ⚪ {% elif attr2['adquisición _level'] == "E" %} 🔴 {% de lo contrario %{{ attr2['adquisición _level']}} {% endif %} {% endfor %}
</td>
</tr>
{% endif %} {% endfor %}
</tbody>
</table>
tarjeta_mod: estilo: .: | ha-card ha-markdown { relleno:0px } ha-card ha-markdown.no-header { relleno:0px } ha-markdown$: | h1 { peso de fuente: normal; tamaño de fuente: 24px; } div { color de fondo: rgb (100, 100, 100); relleno: 12px 12px; color: blanco; peso de la fuente:normal; tamaño de fuente:1.2em; radio frontera-arriba-izquierda: 5px; frontera-arriba-derecha-radio: 5px; } tabla{ frontera-colapso: colapso; tamaño de fuente: 0.9em; familia de fuentes: Roboto; anchura: auto; esbozo: 0px sólido #393c3d; margen máximo: 10px; } subtítulo { text-align: centro; peso de fuente: negrita; tamaño de fuente: 1.2em; } td { relleno: 5px 5px 5px 5px; Alineación de texto: izquierda; frontera inferior: 0px sólido #1 quater de 2020; } tr { borde inferior: 0px sólido #1 quater de 2020; } tr:nth-of-type(even) { color de fondo: rgb(54, 54, 54, 0.3); } tr:último de tipo { border-bottom: transparente; } marca { fondo: #009767; color: #222627; radio fronterizo: 10px; relleno: 5px; } span { fondo: #EC4B34; color: #222627; radio fronterizo: 10px; relleno: 5px; } span { relleno: 5px; } tr:nth-child(n+2) > td:nth-child(2) { texto-alineación: izquierda; }

Tenga en cuenta:
Cambié el color de los puntos porque la correspondencia no era buena con la configuración del pronote del establecimiento de mi hija. Para el verde plus, puse un corazón verde.
Bonificación
Agregar un mapa de actualización

Con el fin de reducir la actualización de cada 10 minutos a cada 4 horas, he añadido el mapa en la imagen de arriba.
Así, tenemos el retraso desde la última actualización y si queremos una actualización inmediata, la pulsamos e iniciamos EJECUCIÓN

Código de la tarjeta:
- tipo: custom:auto-entities tarjeta: Tipo: Filtro de entidades: incluir: - entidad _id: Automation.mise _a _jour _pronote opciones: _info secundario: activado por última vez
Limitar la actualización a días laborables
Después de cambiar el tempo de actualización de 10 minutos a 4 horas, intenté limitar esta actualización a días laborables.
Hay una integración que crea un _sensor binario que nos da esta información: Día de trabajo.
No entro en su instalación, el documento es archi-simple.
Acabo de añadir una condición en la automatización:

Aquí está el código de automatización completo:
alias: Descripción actualizada de la nota: Activador "": - plataforma: horario_pattern horas: /4 condición: - tipo: a condición de _on: dispositivo dispositivo _id: 64bbc75616d4864596e1fd861c865904 entidad_id: dominio binary_sensor.workday: accion binaria _sensor: - servicio: shell_command.update_datos de la nota: Modo {}: soltero

Editar : uno nuevo tutorial le permite activar la actualización de Pronote solo en días laborables y fuera de las vacaciones escolares.
Vinculación de Pronote y activación del despertador Alexa
Este será el siguiente paso
Pero voy a programar esto un domingo para tener una hora de inicio de clase mañana


