Raspberry Pi : Contrôle des GPIO sur serveur Web (nginx)

Sommaire

Contrôler les GPIOs d’un RPi c’est bien mais cela donne des cas d’applications assez limité. Dans mon cas, je souhaite contrôler mes pins via une interface Web. Mon but est d’avoir un système que je peux contrôler à distance simplement. De plus, je souhaite pouvoir le faire dans une application quelconque (un système domotique ?) en ligne de commandes.

Pour commencer, on lance les commandes habituel d’un début de tutoriel :

1
2
sudo apt-get update
sudo apt-get upgrade -y

Contrôle des GPIOs en CLI

Installation de WiringPi

Pour cela, on va installer WiringPi en clonant le dépôt Git. Bien sur, on installe Git avant cela :

1
2
3
4
5
sudo apt-get install git-core -y
cd /tmp #les fichiers de ce dossier son effacés au reboot
git clone git://git.drogon.net/wiringPi
cd wiringPi
./build #lancement du script de compilation

La compilation me donne les avertissements suivants (tant pis !) :

1
2
wiringPi.c:1313:21: warning: ‘digitalWrite8Dummy’ defined but not used [-Wunused-function]
wiringPi.c:1312:21: warning: ‘digitalRead8Dummy’ defined but not used [-Wunused-function]

Tests de WiringPi

On vérifie que cela fonctionne (avec “gpio -v” et “gpio readall”) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
pi@raspberrypi:/tmp/wiringPi $ gpio -v
gpio version: 2.50
Copyright (c) 2012-2018 Gordon Henderson
This is free software with ABSOLUTELY NO WARRANTY.
For details type: gpio -warranty

Raspberry Pi Details:
  Type: Model B+, Revision: 02, Memory: 512MB, Maker: Sony
  * Device tree is enabled.
  *--> Raspberry Pi Model B Plus Rev 1.2
  * This Raspberry Pi supports user-level GPIO access.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
pi@raspberrypi:/tmp/wiringPi $ gpio readall
+-----+-----+---------+------+---+---Pi B+--+---+------+---------+-----+-----+
| BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
|     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
|   2 |   8 |   SDA.1 |   IN | 1 |  3 || 4  |   |      | 5v      |     |     |
|   3 |   9 |   SCL.1 |   IN | 1 |  5 || 6  |   |      | 0v      |     |     |
|   4 |   7 | GPIO. 7 |   IN | 1 |  7 || 8  | 1 | ALT0 | TxD     | 15  | 14  |
|     |     |      0v |      |   |  9 || 10 | 1 | ALT0 | RxD     | 16  | 15  |
|  17 |   0 | GPIO. 0 |   IN | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |
|  27 |   2 | GPIO. 2 |   IN | 0 | 13 || 14 |   |      | 0v      |     |     |
|  22 |   3 | GPIO. 3 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |
|     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |
|  10 |  12 |    MOSI |   IN | 0 | 19 || 20 |   |      | 0v      |     |     |
|   9 |  13 |    MISO |   IN | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |
|  11 |  14 |    SCLK |   IN | 0 | 23 || 24 | 1 | IN   | CE0     | 10  | 8   |
|     |     |      0v |      |   | 25 || 26 | 1 | IN   | CE1     | 11  | 7   |
|   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |
|   5 |  21 | GPIO.21 |   IN | 1 | 29 || 30 |   |      | 0v      |     |     |
|   6 |  22 | GPIO.22 |   IN | 1 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |
|  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |
|  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |
|  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |
|     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
+-----+-----+---------+------+---+---Pi B+--+---+------+---------+-----+-----+

Bon ben maintenant il va falloir lire le tableau ! En fonction de votre modèle de RPi, le tableau sera différant.

Voici quelques explications sur la lecture du tableau :
La colonne “Physical” représente schématiquement les broches (pins) du RPi.
Le pin 7 représente le GPIO 7 et aussi le port 7 de la colonne “wPi”, c’est cette valeur qui nous intéresse.
Le pin 7 représente le GPIO 7 correspondant aussi à la puce 4 selon la numérotation électronique de la puce (colonnes “BCM”).

Contrôle en CLI

On peut tester le contrôle du pin avec les commandes ci-dessous :

1
2
3
gpio mode 7 out
gpio write 7 1 #ON
gpio write 7 0 #OFF

Le mode sortie (OUT) est pour modifier l'état du pin. L’autre mode, qui s’appelle entrée (IN), permet de lire le status du pin.

En mode BCM (option “-g”) :

1
2
3
gpio -g mode 4 out
gpio -g write 4 1
gpio -g write 4 0

On remarque bien qu’en mode BCM, j’utilise la valeur 4 et non 7.

A chaque passage de “ON” à “OFF”, on fait un gpio readall afin de voir le status du pin.

Pin activé :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
+-----+-----+---------+------+---+---Pi B+--+---+------+---------+-----+-----+
| BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
|     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
|   2 |   8 |   SDA.1 |   IN | 1 |  3 || 4  |   |      | 5v      |     |     |
|   3 |   9 |   SCL.1 |   IN | 1 |  5 || 6  |   |      | 0v      |     |     |
|   4 |   7 | GPIO. 7 |  OUT | 1 |  7 || 8  | 1 | ALT0 | TxD     | 15  | 14  |
|     |     |      0v |      |   |  9 || 10 | 1 | ALT0 | RxD     | 16  | 15  |
|  17 |   0 | GPIO. 0 |   IN | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |
|  27 |   2 | GPIO. 2 |   IN | 0 | 13 || 14 |   |      | 0v      |     |     |
|  22 |   3 | GPIO. 3 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |
|     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |
|  10 |  12 |    MOSI |   IN | 0 | 19 || 20 |   |      | 0v      |     |     |
|   9 |  13 |    MISO |   IN | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |
|  11 |  14 |    SCLK |   IN | 0 | 23 || 24 | 1 | IN   | CE0     | 10  | 8   |
|     |     |      0v |      |   | 25 || 26 | 1 | IN   | CE1     | 11  | 7   |
|   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |
|   5 |  21 | GPIO.21 |   IN | 1 | 29 || 30 |   |      | 0v      |     |     |
|   6 |  22 | GPIO.22 |   IN | 1 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |
|  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |
|  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |
|  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |
|     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
+-----+-----+---------+------+---+---Pi B+--+---+------+---------+-----+-----+

Pin désactivé :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
+-----+-----+---------+------+---+---Pi B+--+---+------+---------+-----+-----+
| BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
|     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
|   2 |   8 |   SDA.1 |   IN | 1 |  3 || 4  |   |      | 5v      |     |     |
|   3 |   9 |   SCL.1 |   IN | 1 |  5 || 6  |   |      | 0v      |     |     |
|   4 |   7 | GPIO. 7 |  OUT | 0 |  7 || 8  | 1 | ALT0 | TxD     | 15  | 14  |
|     |     |      0v |      |   |  9 || 10 | 1 | ALT0 | RxD     | 16  | 15  |
|  17 |   0 | GPIO. 0 |   IN | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |
|  27 |   2 | GPIO. 2 |   IN | 0 | 13 || 14 |   |      | 0v      |     |     |
|  22 |   3 | GPIO. 3 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |
|     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |
|  10 |  12 |    MOSI |   IN | 0 | 19 || 20 |   |      | 0v      |     |     |
|   9 |  13 |    MISO |   IN | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |
|  11 |  14 |    SCLK |   IN | 0 | 23 || 24 | 1 | IN   | CE0     | 10  | 8   |
|     |     |      0v |      |   | 25 || 26 | 1 | IN   | CE1     | 11  | 7   |
|   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |
|   5 |  21 | GPIO.21 |   IN | 1 | 29 || 30 |   |      | 0v      |     |     |
|   6 |  22 | GPIO.22 |   IN | 1 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |
|  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |
|  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |
|  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |
|     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
+-----+-----+---------+------+---+---Pi B+--+---+------+---------+-----+-----+

On peut valider le bon fonctionnement sur le RPi avec un multimètre (voltmètre) en se servant par exemple du pin 9 (car c’est une masse sur mon RPi : 0v) pour le port COM.

Contrôle sur serveur Web

Installation service Web

Pour le serveur Web, je vais utiliser Nginx (se lit “engine x” avec un accent anglais s’il vous plait) car il est plus léger qu’Apache. On l’installe donc avec un module PHP pour des pages dynamiques. Je vais ici utiliser “PHP-FPM” plutôt qu’un simple serveur PHP pour les mêmes raisons que Nginx.

1
2
sudo apt-get install nginx
sudo apt-get install php-fpm

On vérifie que cela c’est bien passé en tapant l’adresse IP de son RPi dans la barre d’adresse de son navigateur Web.

Page d’accueil par défaut d’Nginx
Page d’accueil par défaut d’Nginx

Configuration du serveur Web

Il faut spécifier à Nginx de prendre en compte les fichiers PHP. Pour cela on modifie le fichier de configuration avec “nano” par exemple :

1
sudo nano /etc/nginx/sites-enabled/default

Comme l’explique le commentaire au dessus des fichiers d’index, on ajoute “index.php” dans la liste des fichiers index :

1
2
# Add index.php to the list if you are using PHP
index index.php index.html index.htm;

Ici, l’ordre est important : si le fichier “index” n’existe pas, le serveur essaye d’afficher “index.php” et ainsi de suite.
On en profite pour supprimer “index.nginx-debian.html” qui ne sert à rien.

Plus bas, on cherche les lignes suivantes :

1
2
3
4
5
6
7
8
#location ~ \.php$ {
#       include snippets/fastcgi-php.conf;
#
#       # With php-fpm (or other unix sockets):
#       fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
#       # With php-cgi (or other tcp sockets):
#       fastcgi_pass 127.0.0.1:9000;
#}

On dé-commente les lignes 1, 2, 5 et 8 (on enlève les “#") se référant à l’exemple ci-dessus et on enregistre.

On créer alors une page de test “index.php” :

1
sudo nano /var/www/html/index.php

Avec le code PHP suivant :

1
<?php echo phpinfo(); ?>

On relance Nginx les services :

1
sudo /etc/init.d/nginx reload

En actualisant la page de votre navigateur Web, vous devriez voir la page d’information PHP. Merci de ne pas laisser une page de ce type sur un serveur en production ! Penser aussi a supprimer le fichier “/var/www/html/index.nginx-debian.html”

Création des pages de contrôle Web

On va maintenant crée une page (“index.php”) qui envoie un formulaire (méthode POST) à une autre page (“script.php”) qui va exécuter du code afin de piloter le pin 7 de notre GPIO.

“index.php”

Modifier le fichier “index.php” en lui insérant le code suivant :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<!doctype html>
<html lang="fr">
    <head>
        <meta charset="utf-8">
        <title>GPIO</title>
    </head>
    <body>
        <form action="script.php" method="post">
            <input type="submit" name="cmd" value="ON" style="height:50vh;width:100%;background-color:darkgreen">
            <br/>
            <input type="submit" name="cmd" value="OFF" style="height:50vh;width:100%;background-color:darkred">
        </form>
    </body>
</html>

En rechargeant la page, on voit bien deux gros boutons (on peut les rendre moins moche avec un peu de CSS, mais sa ne intéresse pas car je n’utiliserais pas beaucoup cette interface après les tests…). On met juste de la couleur avec “background-color”.

Aperçu de l’interface Web
Aperçu de l’interface Web

Quand on clic sur un des boutons on arrive sur une page “script.php” qui nous donne une erreur 404. Cela est normal car la page n’existe pas encore ! On va donc crée donc cette page avec le contenue de la sous partie suivante.

“script.php”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?php
    system("gpio mode 7 out");

    if($_POST['cmd'] == 'ON'){
        system("gpio write 7 1");
    }
    else {
        system("gpio write 7 0");
    }
    header('Location: index.php');
?>

Le script se lit de la manière suivante :
“On passe le port GPIO en mode sortie (OUT).”
“Si on reçois la variable “cmd” avec pour valeur “ON”, on envoie le signal sur le pin. Sinon, on le coupe.
Ensuite, on repart sur le page “index.php” grâce à la fonction header()”

Bon ben, la page crée, il vous suffit de tester maintenant !

Contrôle en CLI (cURL )

Maintenant que l’on peut piloter notre pin du GPIO simplement, il ne nous reste pas grand chose à faire pour pouvoir le déclenché en ligne de commande (pour le placer dans un script d’automatisation par exemple). Pour cela on va envoyé “ON” ou bien “OFF” en ligne de commande sur notre formulaire Web.

Normalement, “cURL” est disponible par défaut, vous pouvez vérifier cela avec un curl --version et s’il ne semble pas installé : sudo apt-get install curl.

Les commandes de cette partie sont effectuées depuis une autre machine sous Linux (pour ma part, une machine virtuelle sur mon PC).
Mon RPi a pour adresse IP 192.168.42.51/24. Si vous faire les tests depuis le RPi, remplacer cette adresse par “localhost”.

Allumer le pin

1
curl http://192.168.42.51/script.php -d"cmd=ON"

On appel dont le formulaire (script.php) avec “cmd=ON” en données d’entrée. Cela équivaut au clic sur le bouton “ON”.

Éteindre le pin

En vu de notre code, lorsque la page reçoit autre chose que “ON” pour la variable “cmd” (ou rien !), le pin se coupe.
On peut donc envoyé n’importe quoi pour couper le pin.

Voici quelques exemple parmi tant d’autres :

1
2
3
4
curl http://192.168.42.51/script.php -d"cmd=OFF"
curl http://192.168.42.51/script.php
curl http://192.168.42.51/script.php -d"cmd=salut"
curl http://192.168.42.51/script.php -d"lol=ON"

Et voilà ! Il ne vous manque plus qu’a trouvé une utilité à tous cela !
Pour ma part, je vais l’utilisé pour (télé-)commander mon ventilateur en connectant un relais sur le pin du RPi. Je ferais surement un autre tutoriel pour cela.