J’entame cette série Node Package of the Week par un module bien pratique : SerialPort. Vous l’aurez certainement compris, ce module vous permettra d’utiliser les ports série de votre machine au sein de Node.js.

En pratique

On commence donc par installer ce module. Aucune surprise, NPM s’en charge très bien :

1
$ npm install serialport

C’est l’heure de tester ça, alors je vous propose de ressortir ce bon module GSM Sim900 et de tenter d’envoyer et de recevoir quelques SMS au sein de notre application !

Configuration

SerialPort est très simple à configurer, puisqu’il ne suffit que de ces quelques lignes :

1
2
3
4
5
6
7
var serialPort = require("serialport");
var SerialPort = serialPort.SerialPort;

var com = new SerialPort("/dev/cu.usbserial-A600eufu", {
baudrate: 19200,
parser: serialPort.parsers.readline("\r\n")
});

En à peine trois lignes, vous avez ouvert le port /dev/votre_port avec un baudrate de 9600 bauds. Notez que le constructeur de SerialPort peut accepter un troisème paramètre booléen permettant de ne pas ouvrir directement le port. Par défaut à true, si vous décidez de ne pas l’ouvrir à l’instanciation, votre code ressemblera à ça :

1
2
3
4
5
6
7
8
9
10
11
var serialPort = require("serialport");
var SerialPort = serialPort.SerialPort;

var com = new SerialPort("/dev/cu.usbserial-A600eufu", {
baudrate: 19200,
parser: serialPort.parsers.readline("\r\n")
}, false);

com.open(function () {
// Votre code ...
});

Utilisation

SerialPort fournit quatre évènements qui sont :

  • open (déclenché quand le port est ouvert),
  • data (déclenché quand une donnée est reçue sur le port),
  • close (déclenché quand le port est fermé),
  • error (déclenché quand une erreur se présente).

Autant dire qu’à l’usage, c’est un bonheur ! L’exemple ci-dessous montre l’envoi et la réception de données ainsi que la gestion des erreurs :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var serialport = require("serialport");
var SerialPort = serialport.SerialPort;

var com = new SerialPort("/dev/cu.usbserial-A600eufu", {
baudrate: 19200,
parser: serialport.parsers.readline("\r\n")
}, false);

com.open(function () {
com.write("AT\r");
}
);

com.on('data', function(data) {
console.log('Data ' + data);
});

com.on('error', function(error) {
console.log('Erreur: ' + error);
});

Comme on a pu le voir dans l’article concernant le Sim900, la réponse du module à la commande AT doit être OK.

Les réponses du module s’achèvent par un retour chariot et un caractère de fin de ligne ; c’est le rôle du parser définit dans le constructeur. Aussi, pour qu’une commande soit interprétée par ledit module, il faut que celle-ci se termine par un retour chariot. On précise alors \r à chaque fin de commande.

Notre exemple

Pour tester ce package, on va simplement créer un petit serveur Web qui sera capable de nous envoyer un SMS contenant l’IP du visiteur chaque fois qu’il est interrogé. Question utilité on a vu mieux, on aura cependant un bon exemple de ce qu’il est possible de faire avec SerialPort.

Création de la classe SMS.js

Puisque nous souhaitons envoyer des SMS, nous allons créer une classe SMS.js contenant le numéro du destinataire ainsi que le message à transmettre. Notre classe doit ressembler à ça :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function SMS(phone, message) {
this.phone = phone;
this.message = message;
}

if(typeof SMS.initialized == "undefined") {
SMS.prototype.getPhone = function() {
return this.phone;
}

SMS.prototype.getMessage = function() {
return this.message;
}
}

module.exports = SMS;

Deux attributs et deux getters, ça va pas chercher bien loin.

Création de la classe Sim900

Une bonne pratique lorsque l’on intéragit avec du matériel est de créer une classe qui le représente. Puisque notre but est de donner des ordres à un module Sim900, On crée une classe Sim900.js qui doit être capable de se construire autour d’une liaison série et d’envoyer les ordres au Sim900 pour l’envoi d’un SMS :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Sim900(com) {
this.serialPort = com;
}

if(typeof Sim900.initialized == "undefined") {
Sim900.prototype.send = function(sms) {
var self = this;
setTimeout(function(){
self.serialPort.write('AT+CMGS="' + sms.getPhone() + '"\r')
setTimeout(function(){
self.serialPort.write(sms.getMessage() + '\r')
setTimeout(function(){
self.serialPort.write('\x1A')
}, 100);
}, 100);
}, 100);
}
}

module.exports = Sim900;

Comme dit plus haut, le constructeur attend qu’on lui passe la liaison série déjà instanciée et paramétrée. La méthode send(), quant à elle, prendra en paramètre un objet de type SMS, puis elle enverra au Sim900 les commandes AT nécessaires pour que ce dernier puisse envoyer le SMS.

Le Sim900 a besoin d’un peu de temps entre deux demandes, c’est pourquoi on retrouve les trois setTimeout(). Le délai de 100ms est arbitraire. Une meilleure méthode existe certainement ; je creuserai ça à l’occasion.

Il ne nous reste maintenant qu’à utiliser ces deux classes pour que notre application envoie l’IP du visiteur par SMS.

Création du serveur Web

Rien de nouveau là dedans, je ne vais pas détailler le code suivant puisque c’est le point de départ de la plupart des projets d’exemple Node.js.

1
2
3
4
5
6
7
var http = require('http');

var server = http.createServer(function(req, res) {
res.end('Bonjour, votre IP est ' + req.connection.remoteAddress);
});

server.listen(1337);

La seule chose à noter est la ligne req.connection.remoteAddress qui permet de récupérer l’adresse IP du client. En effet, l’objet req contient un bon nombre d’informations intéressantes ; vous n’aurez qu’à jouez du console.log(req); pour vous en rendre compte !

En executant notre application (node main.js) et en se rendant sur http://127.0.0.1:1337/, le serveur doit nous répondre Bonjour, votre IP est 127.0.0.1.. All right ?

Bon, il ne nous reste plus qu’à intégrer nos deux classes pour pouvoir enfin envoyer le SMS. Pour celà, on va commencer par instancier tout le monde :

1
2
3
4
5
6
7
8
9
10
11
12
13
var http = require('http');
var serialport = require("serialport");
var SerialPort = serialport.SerialPort;

var SMS = require('./SMS.js');
var Sim900 = require('./Sim900.js');

var com = new SerialPort('/dev/cu.usbserial-A600eufu', {
baudrate: 19200,
parser: serialport.parsers.readline('\r')
}, false);

var sim900 = new Sim900(com);

Puis, au moment où le serveur reçoit la requette du client, il faut appeller la méthode send() de notre classe Sim900de la sorte :

1
sim900.send(new SMS('+33612345678', 'Nouveau visiteur ayant pour IP ' + req.connection.remoteAddress));

Le code au complet doit alors ressembler à ça :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var http = require('http');
var serialport = require("serialport");
var SerialPort = serialport.SerialPort;

var SMS = require('./SMS.js');
var Sim900 = require('./Sim900.js');

var com = new SerialPort('/dev/cu.usbserial-A600eufu', {
baudrate: 19200,
parser: serialport.parsers.readline('\r')
}, false);


var sim900 = new Sim900(com);

com.open(function () {
var server = http.createServer(function(req, res) {
res.end('Yeah !');
sim900.send(new SMS('+33612345678', 'Visiteur ayant pour IP ' + req.connection.remoteAddress));
});

server.listen(1337);
});

Et là, victoire !




Et voilà, c’est terminé pour aujourd’hui. J’espère que cette première édition de #NPotW vous a plu, en attendant la semaine prohaine je vous laisse le code sur Github et je vous dit à très bientôt !