Il y a quelques temps, nous vous avons présenté les débuts d'une nouvelle librairie Yoctopuce destinée moderniser notre support JavaScript, aussi bien pour les browsers que pour Node.js. Après trois mois de tests en interne et en externe, et bien des améliorations, il est temps d'officialiser cette librairie EcmaScript qui sera désormais supportée au même titre que tous les autres langages.
Jusqu'à présent, notre support officiel pour JavaScript se déclinait sous forme de deux librairies:
- la librairie JavaScript, destinée à être utilisée dans les navigateurs
- la librairie Node.js, destinée spécifiquement aux environnements Node
Ces deux librairies était initialement basée sur des requêtes HTTP "bloquantes". Ces dernières n'étant pas vues d'un bon œil de nos jours par les développeurs JavaScript, des versions asynchrones avec résultat par callback avaient été ajoutées pour presque toutes les méthodes. Leur utilisation n'était toutefois pas très pratique, car un programme entièrement basé callback est peu lisible et difficile à debugger. De plus, la librairie Node.js avait un certain nombre de limitations liées à la librairie HTTP utilisée.
Le nouvelle librairie s'intitule EcmaScript, car c'est le nom officiel du language standardisé. Elle couvre aussi bien les navigateurs que Node.js. Elle utilise une nouvelle méthode beaucoup plus élégantes pour gérer les appels asynchrones, sans casser le flux d'exécution du code par des callbacks: les promesses (en anglais: Promise). A part quelques rares exceptions documentées, toutes les méthodes de la librairie retournent désormais des promesses dont l'appelant peut attendre la résolution à l'aide de l'opérateur await. Vous trouverez de nombreux exemples dans les repertoires example_html et example_nodejs de la nouvelle librairie.
Vous pouvez charger la nouvelle librairie depuis notre site, ou directement à l'aide de npm ou jspm depuis GitHub. Les instructions détaillées sont disponibles dans le README et dans la documentation PDF.
Un exemple : Un relais piloté par GSM
A titre d'exemple, nous allons montrer comment créer en Node.js un petit système de commande à distance d'un relais à l'aide d'un YoctoHub-GSM-3G-EU. Comme les cartes SIM disponibles au commun des mortels ne peuvent contacter que des serveurs publics sur Internet, nous hébergerons notre code Node.js sur Heroku.com.
L'application est volontairement très simple: le but est simplement de montrer comment cette nouvelle librairie peut être utilisée, par exemple sur un hébergement Node.js public comme Heroku. Nous aurons d'autres occasions de faire des choses plus subtiles avec cette librairie lors d'articles ultérieurs. A ce stade, nous sautons aussi à pied joint sur tous les aspects de sécurité et de scalabilité, dont nous parlerons ultérieurement.
Pour rester dans les standards Node.js, nous utiliserons Express comme moteur pour servir les pages de notre Web app. Ce même serveur Web acceptera les connexions entrantes du YoctoHub-GSM, au standard WebSocket. L'interface de notre Web app offrira simplement d'afficher les relais connectés et de les commuter.
Structure du projet
Le code de l'application est disponible sur GitHub. Vous y trouverez:
- sous /public les fichiers statiques de l'interface web
- sous /views les pages de la console web, interprétées par Express
- sous /src le code source EcmaScript de l'application
- à la racine du projet, différents fichiers de configuration
Le code source de l'application tient en un seul fichier. La structure de base pour faire un serveur Express avec WebSockets est la suivante:
var server = require('http').createServer();
var WebSocketServer = require('ws').Server;
var express = require('express');
// Setup Websocket handler
function WebSocketCallbackHandler(ws)
{ ... }
var wss = new WebSocketServer({ server: server });
wss.on('connection', WebSocketCallbackHandler);
// Setup Express app server
var app = express();
server.on('request', app);
app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.get('/', function(request, response) {
response.render('pages/index');
});
// Start web server
server.listen(app.get('port'), function() {
console.log('Server running on port', app.get('port'));
});
Le code spécifique à Yoctopuce
Le code nécessaire à gérer les modules Yoctopuce est placé dans la fonction WebSocketCallbackHandler(), qui est appelée lorsque le YoctoHub-GSM-3G-EU se connecte. Il commence par initialiser la librairie Yoctopuce et énumère les relais. Il attend ensuite pour permettre à l'interface web d'envoyer des instructions de commutations. Notez l'utilisation des mot-clés async et await pour gérer les opérations asynchrones.
{
let hwids = [];
let errmsg = new YErrorMsg();
let yctx = new YAPIContext();
try {
// Initialize library
if(await yctx.RegisterHubWebSocketCallback(ws, errmsg)!=YAPI.SUCCESS){
console.log('HTTP callback error: '+errmsg);
yctx.FreeAPI();
return;
}
// Enumerate relays
let relay = YRelay.FirstRelayInContext(yctx);
while(relay) {
let hwid = await relay.get_hardwareId();
hwids.push(hwid);
Relays[hwid] = relay;
relay = relay.nextRelay();
}
// Keep the calling hub connected for a 30 seconds
await yctx.Sleep(30000);
} catch(e) {
console.log('Caught exception in WS code', e);
}
// Remove relays from list before disconnecting
for(let i = 0; i < hwids.length; i++) {
delete Relays[hwids[i]];
}
// Free ressources
yctx.FreeAPI();
}
Pour faire simple, la commutation via l'interface web se fera à l'aide d'arguments passés sur l'URL. Nous verrons à une autre occasion comment faire plus élégant à l'aide de code JavaScript directement dans l'interface. Voici les lignes à remplacer dans le squelette de serveur donné précédemment pour piloter les relais en fonction des arguments:
if(request.query.relay && Relays[request.query.relay]) {
Relays[request.query.relay].set_state(request.query.state);
}
app.locals.Relays = Relays;
response.render('index');
});
Prérequis pour l'installation
On suppose ici que vous avez installé git, npm et Node.js sur votre machine.
Pour utiliser la librairie Yoctopuce pour EcmaScript, nous vous recommandons aussi d'installer jspm, qui permet d'utiliser les nouvelles syntaxes EcmaScript avec Node.js:
Pour tester Heroku, il vous faudra aussi vous créer un compte sur Heroku.com. L'hébergement gratuit suffit pour lancer cet exemple. Installez les outils Heroku (Heroku Toolbelt) comme décrit sur cette page.
Compiler le projet
Pour commencer, il vous faudra rapatrier le projet sur votre machine, depuis GitHub:
$ cd ecmascript-on-heroku
Installez les dépendances du projet avec les commandes suivantes:
$ jspm install
Pour pouvoir utiliser le projet sur Heroku, il faut compiler le projet pour traduire la syntaxe async/await en code utilisable directement par Node.js:
A ce stade, vous pouvez déjà lancer le projet en local à l'aide de la commande:
Déploiement sur Heroku
Une fois le projet compilé, vous pouvez le télécharger vers Heroku:
Enter your Heroku credentials.
Email: ...
$ heroku create
$ git push heroku master
Vous pouvez maintenant aller sur la page web de votre application. Cela peut se faire avec la commande suivante, qui ouvrira votre navigateur directement sur la bonne page:
Configuration du YoctoHub
Il ne reste plus qu'à configurer le YoctoHub-GSM-3G-EU pour qu'il se connecte à notre serveur Heroku. Utilisez les réglages comme ci-dessous, mais remplacez simplement l'URL par celle de votre application, telle que dans votre navigateur lorsque vous êtes sur l'interface:
Configuration du callback WebSocket
Démonstration
Et voici une petite vidéo qui démontre le fonctionnement de ce code d'exemple:
Voilà, vous avez désormais de quoi bâtir un "smart home hub" avec votre propre console internet, en gardant le contrôle complet du code source et sans dépendre du bon vouloir d'un tiers...