Rasp-AutoStart-Script
Introduction
Si vous lisez cette page c'est probablement parce que vous avez besoin de démarrer automatiquement un script python au démarrage de votre Pi.
Garder bien à l'esprit les éléments suivants qui peuvent largement influencer le démarrage ou non de votre script:
- Si vous avez une interface utilisateur, l'utilisateur qui lancera le script doit pouvoir accéder au terminal!
- Si vous utilisez des ressources particulières (eg: le GPIO), l'utilisateur qui lancera votre script doit posséder les droits adéquats.
System V vs System D
- Raspbian Wheezy (et prédécesseurs) utilise un système d'initialisation basé sur System V, ses RunLevels et scripts shell d'initialisations.
- Depuis Raspbian Jessie (courant 2016), le système d'initialisation est basé sur le très controversé SystemD (Wikipedia.fr)
Suivant la version de Rapsbian, vous pourrez utiliser une méthode où une autre.
Avec System V
Utilisable jusqu'à Raspbian Whezzy, le système d'initialisation basé sur des RunLevels et des scripts.
System V permet d'insérer facilement le lancement d'un script... mais malheureusement, ce système est remplacé par SystemD (nettement moins transparent).
Si vous avez besoin de démarrer un script sous System V, vous pouvez consulter notre "tutoriel Init-Script pour écran LCD"
Avec System D
SystemD (Wikipedia.fr) est apparu depuis Raspbian Jessie.
Notre expérience personnelle de SystemD n'a pas été des plus réjouissantes... dans les faits, installer une horloge temps réel sur le Pi s'est révéler être un cauchemar de configuration (et il reste encore des surprises).
Décrié par une grande partie de la communauté Linux, SystemD s'est pourtant fait une place... il faut donc composer avec lui!
Voici quelques solutions constructives.
Déclaration d'un service SystemD
Nous avons un script Python lcdordertrack.py qui lit des données sur un WebService et afficher les données sur un afficheur LCD USB.
Voici, en quelques étapes, les opérations effectuées pour démarrer automatiquement le script lcdordertrack.py au démarrage du Pi sous SystemD
Déclarer le service (une unité/unit)
sudo nano /lib/systemd/system/lcdordertrack.service
Et y ajouter le contenu suivant:
[Unit] Description=MCHobby LCD Order Tracker After=multi-user.target [Service] Type=idle ExecStart=/usr/bin/python /home/pi/PrestaConsole/lcdordertrack.py > /home/pi/lcdordertrack.log 2>&1 [Install] WantedBy=multi-user.target
Utiliser la combinaison de touche CTRL-X, Y pour quitter nano en sauvant le fichier.
Vous noterez que nous avons ajouté des redirections (sortie standard et sortie erreur) vers des fichiers de log.
Permission sur le service (l'unité)
Un point vraiment important est de fixer correctement les permissions sur notre nouveau fichier!
sudo chmod 644 /lib/systemd/system/myscript.service
Activer le service (unité) dans SystemD
sudo systemctl daemon-reload sudo systemctl enable myscript.service
La deuxième ligne va créer un lien symbolique (propre au système) qui activera le service au prochain démarrage.
Le plus facile maintenant est encore de faire un
sudo reboot
Eviter les pièges - Utilisateur vs SystemD
En utilisant un script python, vous devez garder à l'esprit qu'il n'utilise pas votre "login" courant pour fonctionner.
Donc, ce qui est valable en session interactive ne le sera pas forcément lorsqu'il sera exécuté avec SystemD (le processus parent sera SystemD, donc avec un PID = 1)
Par exemple, si vous chargez un fichier de configuration ("ini"), vous devrez spécifier le chemin complet vers le fichier (alors qu'il est simplement chargé depuis le répertoire courant si vous lancez votre script à la main dans un shell).
Etat du service et instructions utiles
Il arrive souvent que cela ne fonctionne pas la première fois, c'est qu'utiliser un service à certaines contraintes (droit accès, sécurité sur les fichiers comme sur le GPIO par exemple, accès à certaines ressources).
Nous avons prévu des fichiers de log dans dans la commande de démarrage ( /home/pi/lcdordertrack.log ), utile pour récupérer les informations produites par l'instruction print().
SystemD produit également de nombreuses informations utiles avec l'option status .
sudo systemctl status lcdordertrack.service
ce qui avait produit ce résultat très intéressant:
lcdordertrack.service - MCHobby LCD Order Tracker Loaded: loaded (/lib/systemd/system/lcdordertrack.service; enabled) Active: failed (Result: exit-code) since Sat 2016-10-29 10:38:13 UTC; 2min 45s ago Process: 636 ExecStart=/usr/bin/python /home/pi/PrestaConsole/lcdordertrack.py > /home/pi/lcdordertrack.log 2>&1 (code=exited, status=1/FAILURE) Main PID: 636 (code=exited, status=1/FAILURE) Oct 29 10:38:13 r1501 python[636]: Traceback (most recent call last): Oct 29 10:38:13 r1501 python[636]: File "/home/pi/PrestaConsole/lcdordertrack.py", line 39, in Oct 29 10:38:13 r1501 python[636]: config = Config() Oct 29 10:38:13 r1501 python[636]: File "/home/pi/PrestaConsole/config.py", line 34, in __init__ Oct 29 10:38:13 r1501 python[636]: self._presta_api_key = config.get( CONFIG_SECTION_PRESTAAPI, CONFIG...KEY ) Oct 29 10:38:13 r1501 python[636]: File "/usr/lib/python2.7/ConfigParser.py", line 607, in get Oct 29 10:38:13 r1501 python[636]: raise NoSectionError(section) Oct 29 10:38:13 r1501 python[636]: ConfigParser.NoSectionError: No section: 'PRESTA-API' Oct 29 10:38:13 r1501 systemd[1]: lcdordertrack.service: main process exited, code=exited, status=1/FAILURE Oct 29 10:38:13 r1501 systemd[1]: Unit lcdordertrack.service entered failed state. Hint: Some lines were ellipsized, use -l to show in full.
Où nous pouvons voir qu'il y avait un problème dans le script config.py (et donc la lecture de notre config.ini)
C'est la raison pour laquelle nous avons mentionné, plus tôt, qu'il fallait indiqué le chemin d'accès complet vers le fichier de configuration.
Démarrer, arrêter, ...
sudo systemctl start lcdordertrack.service
Voici la commande type qui permet de démarrer le service après modification ou ajustement.
Vous avez également l'opportunité d'utiliser les commandes start, stop et restart. Les commandes enable et disable permettent respectivement d'activer et désactiver un service.
Ressources utiles
Je vous recommande chaudement les lectures suivantes (source d'information utiles pour systemD et le démarrage d'un script python depuis systemD).
- SystemD pour les administrateur - parties 1 et 2 (LinuxFr.org, Français)
- SystemD pour les administrateur - parties 3,4 et 5 (LinuxFr.org, Français)
- Getting Started With systemd on Debian Jessie
- How To Autorun A Python Script On Boot Using systemd
- Running Programs Automatically on Your Tiny Computer (Adafruit.com)
Avec un excellent exemple pour créer un mini serveur/Service HTTP en Python :-) - systemd, tout nouveau tout beau ? ou pas... (Framboise314)
Explique en autre comment démarrer vncserver avec systemd
Contourner SystemD (application graphique)
Nous avons également une application PyGame que nous voulions démarrer en même temps que le Raspberry-Pi.
Voici comment nous nous y sommes pris.
- Utiliser sudo raspi-config pour logger automatiquement votre pi en mode console
- Ecrire un fichier /home/pi/my_app/my_app.sh qui contient de quoi démarrer votre application.
C'est à la fois pratique durant vos développements et facilite le démarrage
#!/bin/bash
MYAPP_DIR=/home/pi/my_app
cd "${MYAPP_DIR}"
# initialisation diverses pour votre script
if [[ $1 == "set-time" ]]; then
sudo gnome-control-center datetime
fi
# Utiliser sudo si necessaire
sudo python my_app.py >>my_app.log 2>>my_app.err
cd -
- Maintenant modifiez le fichier .baschrc
Rendez vous dans votre répertoire home, puis éditez votre fichier .bashrc
cd ~
nano .bashrc
ajoutez la section similaire à celle ci-dessous pour démarrer automatiquement votre script my_app.sh.
# starts my_app (if not started yet)
ps -a | grep -v grep | grep my_app.sh > /dev/null
result=$?
if [ "${result}" -eq "0" ]
then echo "MY_APP is already running!"
else
tty | grep tty1 > /dev/null
result=$?
if [ "${result}" -eq "0" ]
then
echo "MY_APP starting..."
sudo /home/pi/my_app/my_app.sh &
else
echo "MY_APP not started (autostart reserved to tty1)"
fi
fi
Ce bout code contient un petit plus!
En effet, il vérifie si le script my_app.sh n'est pas déjà en cours d'exécution avant de le lancer.
Ensuite, le script vérifie que l'on est bien sur le terminal 1 (tty1) avant de lancer le script... cela évite de lancer le script lors d'une connexion ssh (utilisé pour prendre le contrôle à distance).
Toute référence, mention ou extrait de cette traduction doit être explicitement accompagné du texte suivant : « Traduction par MCHobby (www.MCHobby.be) - Vente de kit et composants » avec un lien vers la source (donc cette page) et ce quelque soit le média utilisé.
L'utilisation commercial de la traduction (texte) et/ou réalisation, même partielle, pourrait être soumis à redevance. Dans tous les cas de figures, vous devez également obtenir l'accord du(des) détenteur initial des droits. Celui de MC Hobby s'arrêtant au travail de traduction proprement dit.