Home Assistant : Jours d’école

Home Assistant : Jours d’école

La vie d’une petite famille tourne autour des jours d’école. Du coup, certains automatismes d’une maison connectée vont dépendre du mode de vie des marmots.

Impensable, par exemple, d’ouvrir automatiquement tous les volets de la maison quand on se lève un dimanche matin si les enfants, eux, ne sont pas levés.

 

Un jour d’école, c’est quoi ?

Un jour d’école, c’est :

  • Pas un jour ferié
  • Pas un mecredi/samedi/dimanche (rayez la mention inutile)
  • Pas un jour de vacances

 

Les approches possibles sous Home Assistant

J’ai dégagé pour ma part deux façons différentes d’aborder le problème : via les « Local Calendar », et via les « Restful templates ».

Local Calendar

Local Calendar est une intégration native de Home Assistant. Elle permet d’utiliser des fichiers de format ICS stockés en local pour gérer des évènements ou des états.

Il suffirait, en théorie, de télécharger régulièrement un calendrier des jours fériés et un calendrier des vacances. 

Restful templates

Cette méthode permettrait d’appeler des services REST pour vérifier si un jour est pendant les vacances ou non, ferié ou non

 

Open data : les services du gouvernement Français

Pour obtenir ces données, nous allons nous tourner vers les données ouvertes du gouvernement Français.

Le service des jours fériés

Le gouvernement met à disposition un service permettant d’obtenir les jours feriés de l’année

https://api.gouv.fr/les-api/jours-feries

Les données sont disponibles en différents formats :

  • CSV
  • ICS
  • Json via un service REST

Il est largement possible d’importer l’ICS et de le mettre au sein de son installation Home Assistant. Mais vu que je n’ai pas envie de faire des imports réguliers, je préfère passer par le JSON.

Pour nos besoins l’URL du service sera

https://calendrier.api.gouv.fr/jours-feries/metropole/{{année en cours}}.json

Ce service nous envoie des données de la sorte

 

resultObj = {
  "2025-01-01": "Jour de l'an",
  "2025-04-21": "Lundi de Pâques",
  "2025-05-01": "Fête du Travail",
  "2025-05-08": "Victoire des alliés",
  "2025-05-29": "Ascension",
  "2025-06-09": "Lundi de Pentecôte",
  "2025-07-14": "Fête Nationale",
  "2025-08-15": "Assomption",
  "2025-11-01": "Toussaint",
  "2025-11-11": "Armistice",
  "2025-12-25": "Noël"
}

Il suffira juste de vérifier que la date du jour est dans les clefs de l’objet JSON utilisé en tant que tableau associatif.

Le service des vacances scolaires

Ce service est fourni par le ministère de l’éducation nationale.

On peut le trouver à cette adresse

https://data.education.gouv.fr/explore/dataset/fr-en-calendrier-scolaire/api/

C’est un service remarquablement complet. Il permet d’utiliser les données sous plusieurs formats dont, notamment ICS et JSon. Mais il a également un constructeur d’appel REST extrêment élaboré : on peut préciser des clauses assez proches de ce qu’on a en SQL, avec du WHERE et du ORDER BY par exemple, et la page génèrera automatiquement l’URL du service à appeler. Perso, j’aime beaucoup.

Par exemple, l’URL suivante donne les prochaines vacances par ordre chronologique pour l’académie de Grenoble

Le résultat est sous la forme

 

resultObj ={
  "total_count": 4,
  "results": [
    {
      "description": "Vacances de Noël",
      "population": "-",
      "start_date": "2023-12-22T23:00:00+00:00",
      "end_date": "2024-01-07T23:00:00+00:00",
      "location": "Grenoble",
      "zones": "Zone A",
      "annee_scolaire": "2023-2024"
    },
    {
      "description": "Vacances d'Hiver",
      "population": "-",
      "start_date": "2024-02-16T23:00:00+00:00",
      "end_date": "2024-03-03T23:00:00+00:00",
      "location": "Grenoble",
      "zones": "Zone A",
      "annee_scolaire": "2023-2024"
    },
    {
      "description": "Vacances de Printemps",
      "population": "-",
      "start_date": "2024-04-12T22:00:00+00:00",
      "end_date": "2024-04-28T22:00:00+00:00",
      "location": "Grenoble",
      "zones": "Zone A",
      "annee_scolaire": "2023-2024"
    },
    {
      "description": "Pont de l'Ascension",
      "population": "-",
      "start_date": "2024-05-09T22:00:00+00:00",
      "end_date": "2024-05-10T22:00:00+00:00",
      "location": "Grenoble",
      "zones": "Zone A",
      "annee_scolaire": "2023-2024"
    }
  ]
}

C’est riche et en vrai nous n’avons pas besoin de tout ça. Il suffit en réalité de vérifier si la date du jour est comprise entre le début et la fin de vacances scolaires pour l’académie, et la valeur qui nous intéresse c’est le total_count qui doit être supérieur à 0.

Donc, nous allons utiliser une URL comme celle ci:

https://data.education.gouv.fr/api/explore/v2.1/catalog/datasets/fr-en-calendrier-scolaire/records?where=location%20%3D%20%22Grenoble%22%20and%20start_date%20%3E%3D%20now()%20and%20end_date%20%3C%3D%20now()&limit=20

Il suffira juste de changer l’académie si vous voulez intégrer ce service à votre HA. Chose importante : les ponts de jours fériés admis par l’éducation nationale sont inclus !

Intégration dans Home Assistant

Il faut maintenant intégrer tout cela dans Home Assistant.

Alors, désolé, il va falloir mettre les mains dans le camboui et aller modifier le YAML de configuration.

Pour cela, on utilisera l’outil que l’on préfère, je conseille pour ma part l’Add On « File Editor » qui a tout ce qu’il faut sous la main.

Nous allons rajouter les lignes suivantes sous la partie « Sensor »

 

sensor: 
    # Is today a bank holliday ?
    - platform: rest
      resource_template: https://calendrier.api.gouv.fr/jours-feries/metropole/{{now().year}}.json
      name: is_bank_holliday
      value_template: >
                        {% set today = '%d-%d-%d' | format(now().year,now().month,now().day) %}
                        {{ today in value_json.keys() }}
    
    # Is today a school hollyday ?                    
    - platform: rest
      resource: https://data.education.gouv.fr/api/explore/v2.1/catalog/datasets/fr-en-calendrier-scolaire/records?where=location%20%3D%20%22Grenoble%22%20and%20start_date%20%3E%3D%20now()%20and%20end_date%20%3C%3D%20now()&limit=20
      name: is_school_holliday
      value_template: >
                        {{ value_json.total_count > 0 }}

Je vais commencer par le capteur « is_school_hollyday » qui est le second.

Vu que nous avons bien pensé l’URL, fixe, de notre appel Rest, nous pouvons utiliser le paramètre « resource » directement, et le pointer sur l’URL. Comme nous disions, nous verifions juste si le paramètre « total_count » est supérieur à 0. Le template renverra un booléen, True ou False. Facile.

Pour les jours feriés, c’est un peu différent. Nous voulons uniquement les jours fériés pour l’année en cours (pas la peine de tout se ramener), et pour cela nous devons passer un paramètre dans l’URL.

Nous utiliserons donc à la place de « resource » un « resource_template » dans lequel nous pouvons insérer une valeur calculée via les templates Jinja, ici « {{ now().year }} » qui donnera l’année du jour.

Nous allons ensuite traduire la date du jour au format des données JSON renvoyées

{% set today = ‘%d-%d-%d’ | format(now().year,now().month,now().day) %}

« %d-%d-%d » est une chaine de caractère préformatée qui attend 3 entiers (%d). Nous les fournissons via le filtre format. Le résultat sera une chaine sous la forme « 2023-11-23 »

La propriété « keys » de la json_value renvoyée par le service contiendra les dates des différents jours fériés, il s’agit d’un set, nous pouvons donc vérifier si la date du jour est dedans, ce qui nous dira si le jour courant est ferié.

Après cela, il ne faut pas oublier de redémarrer Home Assistant Core, via les developper tools ou les settings par exemple.

Nous obtenons le résultat suivant

Finalement, nous allons utiliser la partie « template » de la config pour rajouter un capteur binaire

 

template:
    - binary_sensor:
        - name: is_school_day
          state: >
            {% set is_weekday = ( now().isoweekday() < 6 ) %}
           {{ is_weekday and is_state("sensor.is_bank_holliday","False") and is_state("sensor.is_school_holliday","False" ) }}

La fonction « now().isoweekday() » issue de la partie DateTime de Python nous renvoit une valeur numérique allant de 1 pour Lundi à 7 pour Dimanche.

Donc nous obtenons un capteur binaire (on off) dont la valeur est positive si :

  • Nous sommes un jour de semaine (du Lundi au Vendredi)
  • Qui n’est pas en période de vacances scolaires ou un pont
  • Qui n’est pas non plus un jour férié 🙂