MagicMirror², configuration scriptée

| par Teddy Payet

Toujours dans l’optique d’améliorer mon installation de MagicMirror², j’ai mis en place une mise en place automatique de mes modules. Prenez un café ou thé et voyons cela en détail.

Pour rappel, MagicMirror² est installé sur un Raspberry Pi 3 avec un Debian 9, Stretch. Cette installation permet donc pas mal de choses très sympathiques dont les crontab, la connection ssh et les scripts bash.

Préambule

Pour des raisons de stabilité, je ne mets pas à jour MagicMirror² avec la dernière version en ligne. De même, les modules tiers ne seront pas mis à jour automatiquement. Je ne désire pas casser mon installation avec des versions que je n’aurais pas testé au préalable. Ces derniers points seront donc mis à jour manuellement pour avoir une meilleure maitrise de "mon" logiciel.

Versionner sa configuration

Comme vous commencez à le savoir, MagicMirror² a besoin d’un fichier config.js dans config/ pour fonctionner correctement et surtout pour avoir votre personnalisation.
Au lieu de faire des copier-coller d’une machine à une autre, j’ai mis en place un dépôt (privé) sur mon compte gitlab.com. J’ai cloné ce dépôt sur mon Raspberry. Puis, j’ai créé un lien symbolique dans /home/pi/MagicMirror/config/ vers /home/pi/magicmirror_config/config.js

De même, pour personnaliser la mise en page sur certains points, j’ai créé un fichier custom.css dans /home/pi/magicmirror_config/. Un lien symbolique dans /home/pi/MagicMirror/css/ est également présent.
Le concept de lien symbolique est mis en place sans difficulté. Voyons maintenant les scripts bash.

Bash, une installation scriptée

Il n’y a rien de crypter, mais tout est scripté, rien de sorcier. :-)

Ma philosophie dans tous mes développements est d’automatiser (scripter) les actions répétitives. Ici vous êtes dans un cas typique d’école : le déploiement de codes.

Je teste sur ma machine locale (mon mac) certains modules tiers (voir des versions de modules que j’aurais fait évoluer).
Dans mon répertoire /home/pi/magicmirror_config/, j’ai créé un fichier bash update_files_config.sh.
Le chemin vers mes répertoires MagicMirror et magicmirror_config change selon la plateforme. Au lieu de changer le chemin vers ces répertoires à chaque fois, je vais créer 2 variables dans mon profil bash :
Sur le Raspberry Pi, dans le fichier ~/.bashrc :

export MM_CFG_HOME=/home/pi/magicmirror_config/
export MM_HOME=/home/pi/MagicMirror/

Sur mon Mac, dans le fichier ~/.bash_profile :

export MM_CFG_HOME=~/Sites/magicmirror_config/
export MM_HOME=~/Sites/MagicMirror/

Ce qui vous permettra d’appeler ces variables dans notre fichier bash sans sourciller :

#!/usr/bin/env bash
_MM_CFG_HOME=$MM_CFG_HOME
_MM_HOME=$MM_HOME

Un script classique affichera du texte de la couleur par défaut que vous aurez choisit dans votre Terminal. J’ai envie de rendre cela un peu plus lisible. Pour cela, je vais utiliser du texte bold et de la couleur.
Voici ce que cela donne comme variable :

txt_bold=$(tput bold)
txt_normal=$(tput sgr0)
txt_red='\033[0;31m'
txt_green='\033[0;32m'
txt_nc='\033[0m' # No Color

Les paramètres de personnalisation "graphique" sont en place. Cool. On les utilisera en temps voulu.

Même si vous avez bien exporté votre variables d’environnement, il est préférable de mettre une petite sécurité (toujours la sécurité !) :

if [ -z ${_MM_CFG_HOME} ];
        then
           _MM_CFG_HOME=/home/pi/magicmirror_config/
fi
if [ -z ${_MM_HOME} ];
        then
           _MM_HOME=/home/pi/MagicMirror/
fi

En gros, si votre variable d’environnement est "vide" pour X raisons, le script va leur donner une valeur par défaut.

Bash, liens symboliques, bis

Comme expliqué au début de cet article, MagicMirror a besoin d’un fichier config.js. De ce fait, le script vérifie sa présence dans /home/pi/MagicMirror/config/. Et si il n’existe pas, il crée un lien symbolique vers /home/pi/magicmirror_config/config.js :

if [ ! -f ${_MM_HOME}config/config.js ];
        then
           ln -s ${_MM_CFG_HOME}config.js ${_MM_HOME}config/config.js
fi

Dans mon précédent article, j’ai indiqué que j’utilisais le module MMM-AlarmClock avec des fichiers mp3 personnalisés. Pour que le module prenne en compte ces fichiers mp3, ils doivent être présents dans le répertoire /home/pi/MagicMirror/modules/MMM-AlarmClock/sounds.
J’ai une carte SD de 16Go, ce qui assez confortable. Mais je ne veux pas surcharger inutilement la carte mémoire. Pour se faire, les liens symboliques sont également une très bonne solution.

Dans mon dépôt /home/pi/magicmirror_config/, j’ai créé un répertoire sounds/ qui contiendra tous mes fichiers mp3.

Pour mon besoin de fichiers mp3, voici le code présent :

if [ -d ${_MM_HOME}modules/MMM-AlarmClock ];
 then
   #ls ${_MM_CFG_HOME}sounds/ | grep ".mp3"
   list_mp3=$(ls ${_MM_CFG_HOME}sounds/ | grep ".mp3")
   for mp3_file in $list_mp3;
   do
     if [[ -f ${_MM_HOME}modules/MMM-AlarmClock/sounds/$mp3_file ]];
       then
         echo "Le fichier ${txt_bold}$mp3_file${txt_normal} existe dans ${_MM_HOME}modules/MMM-AlarmClock/sounds";
       else
         echo "Le fichier ${txt_bold}$mp3_file${txt_normal} n'existe pas dans ${_MM_HOME}modules/MMM-AlarmClock/sounds. On crée le lien symbolique.";
         ln -s ${_MM_CFG_HOME}sounds/$mp3_file ${_MM_HOME}modules/MMM-AlarmClock/sounds/$mp3_file;
     fi
   done
fi

Bash, des fonctions : importer un module

Le but principal du script update_files_config.sh est d’importer un module qui est nécessaire au fichier config.js pour notre MagicMirror. J’utilise plus d’un module tiers. Certainement, cela sera également votre cas.
Au lieu de répéter X fois le même code, vous allez créer une fonction. Appelons la "import_module" (module au singulier).

import_module () {
 if [[ ! -z ${1} ]];
   then
     cd ${_MM_HOME}modules/
     repository=$(basename -s .git "$1")
     echo ""
     printf "${txt_green}${txt_bold}${repository}${txt_normal}${txt_nc}\n"
     if [[ -d ${_MM_HOME}modules/${repository} ]];
       then
         echo "** ${_MM_HOME}modules/${repository} existe déjà"
       else
         echo "** Récupération du répertoire ${1}"
         git clone ${1}
     fi
     cd ${_MM_HOME}modules/${repository}
     if [[ -f $(ls | grep 'package.json') && ! -d $(ls | grep 'node_modules') ]];
       then
         echo "** Installation des modules npm de ${repository}"
         npm install
         npm audit fix
       else
         if [[ ! -f $(ls | grep 'package.json') ]];
           then
             echo "** Il n'y a pas de modules npm à installer pour ${txt_bold}${repository}${txt_normal}"
           else
             echo "** Les modules npm de ${txt_bold}${repository}${txt_normal} sont déjà installés"
         fi
     fi
     cd ${_MM_HOME}modules/
   else
     printf "\n${txt_red}Vous avez oublié d'indiquer un dépôt git en paramètre${txt_nc}\n"
 fi
}

Cette fonction permet d’importer un module à partir de son url git. Pour cela, vous devez indiquer l’url du git en paramètre de cette façon :

import_module https://github.com/Ybbet/MMM-AlarmClock.git

Si vous ne donnez aucune url, vous aurez un message vous indiquant que l’information est manquante.

Cool… Mais ce n’est pas tout. Un module a souvent besoin d’une installation de modules pour son bon fonctionnement. Pour le savoir, autrement que de lire la documentation, le script vérifie la présence d’un fichier package.json mais également l’absence du répertoire node_modules. En effet, l’absence de ce répertoire indique que l’installation n’a pas encore été réalisée. Le script lancera un npm install && npm audit fix dans son répertoire local.

Pas mal non ? :-)

Bash, des fonctions : effacer les modules inutiles

Vous aurez testé des modules, rejeté des modules et garder des modules. Pour que le script reconnaisse votre choix, il y a une solution très très simple : le fichier config.js
En effet, quand vous utilisez un module, vous indiquez dans votre fichier la mention module: "MMM-AlarmClock" (remplacez "MMM-AlarmClock" par votre nom de module). Ce nom de module correspond au nom du dépôt git désiré et donc du répertoire téléchargé (merci import_module).
Vous l’appellerez "delete_modules" (modules avec un "s" cette fois-ci car on s’occupe de tous les modules sans distinction)

Donc, il suffit de vérifier la présence de cette chaine de caractères dans le fichier :

delete_modules () {
 # Stocker l'ensemble des répertoires présents /home/pi/MagicMirror/modules/
 modules_list=$(ls ${_MM_HOME}/modules/)

 # Ne pas prendre en compte certains fichiers et répertoires propres à MagicMirror
 modules_list=${modules_list[@]//default/}
 modules_list=${modules_list[@]//README.md/}
 modules_list=${modules_list[@]//node_modules/}

 # lançons une boucle pour s'occuper de chaque module.
 for module in ${modules_list[@]}
 do
   # Si le module n'est pas utilisé dans config.js
   if grep -Fq "module: \"${module}\"" ${_MM_HOME}/config/config.js
     then
       echo "${module} existe dans config.js"
     else
       echo "${module} n'existe pas dans config.js"
       rm -rf ${_MM_HOME}/modules/${module}
   fi
 done
}

Bash, oui mais dans l’ordre

Si vous n’avez pas été trop perdu, vous vous rendez compte que je parle de liens symboliques avant même d’avoir installé les modules. :-D
Ben, ouais, c’était un petit piège. Ce n’est pas logique de lancer la création de liens symboliques (cf. MMM-AlarmClock/sounds) dans un répertoire si son installation n’a pas été faite d’abord. Cet ordre est surtout important lorsque vous lancez pour la première fois le script et/ou si vous revenez à plusieurs reprises sur le choix d’un module. J’en ai fait l’expérience avec MMM-AlarmClock. J’ai testé MMM-TTS (pour avoir directement le texte prononcé par la machine sans passer par un fichier mp3, sauf que le français n’est pas pris en compte), créé un module MMM-Google-tts (pas tout à fait convaincant sur le Raspberry Pi). Donc, voici l’ordre dans lequel le code doit être placé (et donc exécuté) :

  • Bash, une installation scriptée ;
  • Bash, liens symboliques, bis (la partie config.js uniquement) ;
  • Bash, des fonctions : importer un module ;
  • Bash, des fonctions : effacer les modules inutiles ;
  • Bash, liens symboliques, bis (la partie sounds ici).

En gros, tous vos paramètres d’environnement du fichier bash doivent se trouver en début de script. Puis :

  1. lancer les petites sécurités sur la présence de fichier et répertoire propres à MagicMirror ;
  2. créer les fonctions ;
  3. lancer l’importation des modules, un module par ligne pour faciliter la relecture ;
  4. lancer la suppression des modules inutiles (cf. delete_modules)
  5. lancer vos actions dans les répertoires (liens symboliques par exemple) à la fin du fichier car là, vous serez sûr de la présence de ces modules dans /home/pi/MagicMirror/modules/.

Voilà ! C’est tout pour aujourd’hui. Je laisse un peu pour un nouvel article : MagicMirror², mise à jour journalière

P.-S.

Visuel : Photo by Annie Spratt on Unsplash