Utiliser le Raspberry Pi comme serveur, le script

Il doit pourvoir fournir des données sur demande à un autre appareil, le client, ou exécuter des programmes sur commande.

Installer un serveur de services et données avec Node.js

Il vous faut de préférence une version récente de Node, pas la version 0.10 fournie dans Raspbian! Pour l'installer automatiquement, voici un petit script:

#!/bin/sh
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs

Le script doit être réalisé sur le Raspberry et pas sous Windows, car le shell est sensible aux codes de fin de ligne. Pour ce faire, tapez:

leafpad instnode

Puis copiez le code ci-dessus (cela suppose que cette page soit chargée sur le navigateur du Pi). Vous pouvez aussi télécharger le script dans une archive zip à décompresser sur le Pi.

Pas de sudo ici car c'est en tant qu'utilisateur et non administrateur que l'on utilise le script. Il faut ensuite changer les permissions pour le rendre exécutable. Cliquez avec le bouton droit sur le nom du fichier à partir du gestionnaire du fichier, sur droits d'accès, et changez "rendre exécutable" en "pour tout le monde".
Vous pouvez ensuite lancer le script par:

./instnode

Eventuellement vous pouvez créer un dossier pour votre serveur, sur un compte utilisateur, par défaut dans /home/pi.

mkdir www 

La racine de serveur sera:

/home/pi/www

Le serveur est un simple programme JavaScript que l'on lance pour mettre le Pi en ligne. Pour mettre des Pi et autres ordinateurs en réseau, envoyer des pages HTML n'est pas le but, il s'agit surtout d'envoyer des commandes et recevoir des données. Voici un exemple de serveur qui exécute des commandes et en retour envoie des informations. De façon asynchrone.

1) Le serveur Node.js

Ce serveur de service n'envoie pas de fichiers à un navigateur, un script qui fait cela est fourni dans un autre article, Réaliser un serveur de pages avec Node.js. Il reçoit le nom d'une commande et des données à passer à cette commande et exécute le script correspondant.

var runner = require("child_process"),
http = require("http"),  
path = require("path"),  
url = require("url"),  
fs = require("fs");  

function sendError(errCode, errString, response)
{
    response.writeHeader(errCode, {"Content-Type": "text/plain"});  
    response.write(errString + "\n");  
    response.end(); 
    return; 
}

function sendData(err, content, response) 
{  
  if(err) return sendError(500, err, response);
    response.writeHeader(200, {"Content-Type": "text/plain"});  
    response.write(content + "\n");  
    response.end(); 
}  

/* 
   Run a script
   This script will send  data to the user when it wants.
*/

function runScript(params, response)
{
  var command = "";
  if(params.script == undefined) return;

  if(params.data == undefined) return;

  var child = runner.execFile("node", 
    [params.script, params.data], 
    function(error, stdout, stderr) {
        console.log(error + " " + stdout);
        sendData(error, stdout, response);
  });

  child.on('close', function(code) {
    process.exit(1);
  });
}

function getCommand(request, response)
{  
    if(request.method != "POST") {
       console.log("POST only supported.");
       return;
    }

    var data = "";
    request.on("data", function(chunk) {
      data += chunk;
    });
 
    request.on("end", function() {
	    var urlpath = url.parse(request.url).pathname;   
	    if(urlpath == "favicon.ico") return;
	    var localpath = path.join(process.cwd(), urlpath); 
	    console.log("Requested script: " + localpath); 
	    fs.exists(localpath, function(result) { 
       		var params = { 
	           "script": localpath,
        	   "data" : "\"" + data + "\""
	        };
	    runScript(params, response);
    	}); 
    });
}

var server = http.createServer(getCommand);
server.listen(3000);  
console.log("Server available...");  

Le code dispose des fonctions nécessaires pour créer un serveur, exécuter un script, et passer des données à ce script. Il renvoie en réponse à l'origine de la requête le résultat affiché par le script.

2) Un exemple de service très basique

Ce script de démonstration reçoit les données envoyées par l'ordinateur distant au raspi, et les affiche. Il envoie en réponse le message "Hello computer!".

function processCommand(data) {
   console.log("Received from computer: " + data);
   var answer = "Hello computer!";
   console.log("Answer:");
   console.log(answer);
}

console.log("\nRaspberry: Starting script.js...");

var data = process.argv[2];

processCommand(data); 

3) Code d'utilisation du service par un autre ordinateur

C'est à nouveau un script JavaScript en ligne de commande, mais tout autre langage ou interface pourraient convenir. Il envoie au serveur le nom d'un script (script.js) et des données à traiter, en l'occurence le message "Hello Raspi!".
Il affiche ensuite la réponse envoyée par le script sur le raspi.

http = require("http");  

var options = {
  host: 'xxx.xxx.xxx.xxx',  // the IP of your Raspberry Pi
  path: '/script.js',
  port: '3000',
  method: 'POST'
};

function received(response) {
  var message = ''
  response.on('data', function (chunk) {
    message += chunk;
  });

  response.on('end', function () {
    console.log(message);
  });
}

var req = http.request(options, received);
req.write("Hello Raspi!");
req.end();

Pour faire fonctionner le script, vous devez assigner l'adress IP de votre raspi à l'attribut host en options. Par la suite vous pourrez aussi choisir parmi plusieurs scripts et leur envoyer des données selon vos besoins...

Ce code est parfaitement fonctionnel, mais volontairement simplifié. On peut améliorer le serveur avec une liste de scripts au choix et en échangeant des objets JSON plutôt que de simples message. Le principe est le même avec l'emploi des méthodes stringify et parse. Une autre amélioration serait d'utiliser le Wifi plutôt qu'Internet, ce qui conviendrait mieux à la plupart des projets sous Raspberry. Ce sera l'objet des articles suivants.

Télécharger le code:

Start.js et script.js se placent sur le raspi dans le répertoire utilisateur. On démarre le serveur par "node start.js".
Computer.js se place sur l'appareil qui veut communiquer avec le raspi. On démarre le script par "node computer.js".