Publié par
Il y a 1 année · 8 minutes · IoT

Atelier – Plateforme 2 – IBM Bluemix (1/3)

Après avoir secoué le module IoT de AWS, attaquons nous aujourd’hui à un autre Cloud public, IBM Bluemix. Bluemix propose lui aussi un module dédié à l’IoT, IoT Platform.

Nous allons donc tenter de réaliser le même sytème que précédemment. Nous passerons par un survol de la plateforme, puis nous rentrerons dans le dur du sujet : exécution de code à la demande, captation des messages en provenance de Sigfox et traitement de ces messages dans le backend IoT.

Commençons par le commencement, à savoir l’objet connecté.

Le module IoT de la plateforme Bluemix (et ça continue, encore et encore).

C’est parti, nous allons piocher dans le catalogue Bluemix le module qui nous intéresse :

module IoT de la plateforme Bluemix

L’ajout d’un objet connecté au module est particulièrement bien documenté, nous n’allons donc pas nous attarder sur ce sujet particulier.

En revanche, nous revoici confrontés à un problème que nous avions découvert lors de l’expérimentation de la plateforme AWS : les objets connectés de la plateforme Bluemix supportent un seul et unique protocole de manière native : MQTT. Or les données stockées dans le backend Sigfox sont exploitables uniquement via des callbacks HTTP. Ce n’est donc pas une nouveauté pour nous, pas plus que cela n’est un problème. De la même façon que nous avions développé un bridge pour AWS, nous allons nous atteler à la création du pont entre Sigfox et Bluemix. Tant pis donc pour le canal de communication « natif » du module IoT de Bluemix.

Exécuter du code NodeJs à la demande

Depuis peu, IBM propose un nouveau service, OpenWhisk. Il s’agit d’un service d’exécution de code à la demande, qui ressemble furieusement au service AWS Lambda que nous avions utilisé.

L’installation de la CLI OpenWhisk est détaillée ici.

Malheureusement, ce service, en bêta, n’est disponible que sur la plaque américaine. Mais comme nous sommes dans une démarche exploratoire, il serait dommage de ne pas expérimenter une brique qui colle parfaitement avec nos besoins. Nous ne vous ferons pas l’insulte du HelloWorld qui est disponible ici.

Au delà du HelloWorld, notre OpenWhisk va nécessiter d’utiliser a minima un module externe, à savoir le module dédié à la communication avec la plateforme IoT,

const IotfDevice = require("ibmiotf").IotfDevice;

OpenWhisk accepte des containers, ou bien un fichier unique .js. Nous allons donc devoir inliner nos dépendances et packager notre application. En cherchant un peu sur le web, on trouve facilement un exemple utilisant WebPack (ouais, cool, celui là je ne l’avais pas sur mon CV…).

Pour la version courte, voici les lignes de commande pour (bien) démarrer le projet :

npm init
npm install --save-dev webpack babel-core babel-loader \
    babel-preset-es2015 json-loader
npm install --save ibmiotf
npm install -g webpack

Et là, manque de bol, cela ne suffira pas pour fonctionner instantanément.

npm run build
> sigfox-bluemix@1.0.0 build /Users/pablolopez/xebia/dev/projects/sigfox-bluemix
> webpack --config webpack.config.js --progress --colors
Hash: 1e9176458703f75e54c3
Version: webpack 1.12.15
Time: 6817ms
    Asset    Size  Chunks             Chunk Names
bundle.js  145 kB       0  [emitted]  main
   [0] multi main 28 bytes {0} [built]
    + 75 hidden modules
WARNING in ./~/ibmiotf/~/axios/~/es6-promise/dist/es6-promise.js
Module not found: Error: Cannot resolve module 'vertx' in /Users/pablolopez/xebia/dev/projects/sigfox-bluemix/node_modules/ibmiotf/node_modules/axios/node_modules/es6-promise/dist
 @ ./~/ibmiotf/~/axios/~/es6-promise/dist/es6-promise.js 137:20-30
ERROR in ./~/ibmiotf/~/mqtt/mqtt.js
Module parse failed: /Users/pablolopez/xebia/dev/projects/sigfox-bluemix/node_modules/ibmiotf/node_modules/mqtt/mqtt.js Line 1: Unexpected token ILLEGAL
You may need an appropriate loader to handle this file type.
| #!/usr/bin/env node
| 'use strict';
| /*
 @ ./~/ibmiotf/dist/clients/BaseClient.js 3:4-91

C’est dommage ça sonnait plutôt bien comme manière de faire. Ha, on me dit dans l’oreillette « Webpack n’est pas fait pour ça à la base, certains l’ont un peu tweaké mais ça m’étonne pas que tu tombes sur ce genre de problèmes ».

 Tant pis pour le JS, nous allons tenter de nous rabattre sur Docker.

Exécuter du code NodeJs à la demande, en utilisant Docker (même joueur joue encore).

Deuxième solution offerte pas OpenWhisk, packager notre application sous forme de conteneur. La documentation n’est pas forcément évidente à trouver, mais avec un peu de persévérance, on y arrive. Un squelette d’application Docker est disponible, via la commande wsk sdk install docker.

Ceux qui connaissent Docker ne seront pas trop perdus. On retrouve un DockerFile, et un répertoire server, qui contiendra notre application Node.

Adaptons donc le Dockerfile à notre besoin :

FROM node
# ...
# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# Copy app
COPY server/package.json /usr/src/app/
# Install dependencies
RUN npm install
COPY server/* /usr/src/app/
COPY server/src/* /usr/src/app/src/
EXPOSE 8080
CMD ["/bin/bash", "-c", "node ./app.js"]

Dans un premier temps, inutile de modifier le fichier server.js, qui fait ce qu’on attend de lui. Nous allons nous attaquer au coeur du système, le fichier src/service.js. La partie qui nous concerne se trouve dans le corps de la fonction runCode. Nous allons remplacer le code C par un bloc de NodeJs.

var config = {
    "org" : "<org>",
    "id" : "<device id>",
    "type" : "<device type>",
    "auth-method" : "token",
    "auth-token" : "<device token>"
};
 
this.runCode = function runCode(req, res) {
        // Unmodified
  var meta = (req.body || {}).meta;
        var value = (req.body || {}).value;
        var payload = value.payload; // we expect this to be a string
        if (typeof payload != 'string')
            payload = JSON.stringify(payload);
        
  // IoT bridge starts here
        var IotfDevice = require("ibmiotf").IotfDevice;
        var device = new IotfDevice(config);
        
  device.on("connect", function () {
      console.log("On connect")

      var dataToPush = {"temperature":17};
      var msg = '{"d" : '+ JSON.stringify(dataToPush) + '}';
      //publishing event using the default quality of service
      device.publish("status","json", msg);

      device.disconnect();

      var result = { 'result' : { 'msg' : 'Message pushed : ' + JSON.stringify(dataToPush, null, 2) + ' to ' + JSON.stringify(device,  null, 2) } };
      res.status(200).json(result);
  });
 
        device.connect();
    }

Dans le but de tester notre bridge, nous avons décidé d’envoyer une valeur statique. Testons maintenant notre conteneur. Vous aurez besoin pour cela d’un compte sur le DockerHub.

docker login -u <docker hub login> -p <docker hub password>
./buildAndPush.sh <docker hub login>/bluemix-sigfox-bridge
wsk action create <or update> --docker bluemixSigfoxBridge <docker hub login>/bluemix-sigfox-bridge
wsk action invoke --blocking --result bluemixSigfoxBridge

En plus d’obtenir un succès dans votre console, vous devriez voir apparaitre dans le tableau de bord d’IBM IoT la première valeur que vous avez poussée pour votre objet : 

code-NodeJs-avec-Docker

Notre conteneur, déployé dans OpenWhisk, est donc fonctionnel. Nous allons maintenant l’adapter pour recevoir les données en provenance de Sigfox.

Exposer le conteneur aux callbacks.

Dans un premier temps, modifions légèrement le code pour récupérer les paramètres de la requête HTTP. Le changement est mineur :

device.on("connect", function () {
    var msg = '{"d" : '+ JSON.stringify(value) + '}';

Mettons à jour notre OpenWhisk :

./buildAndPush.sh <docker hub login>/bluemix-sigfox-bridge
wsk action update --docker bluemixSigfoxBridge <docker hub login>/bluemix-sigfox-bridge

Nous allons maintenant avancer d’un cran dans l’utilisation d’OpenWhisk, en actionnant notre action avec Postman. En premier lieu, nous allons récupérer nos identifiants pour l’authentification basique requise par l’API REST.

cat ~/.wskprops
NAMESPACE=xebia_dev-us
AUTH=xxx:yyy

Ensuite, il suffit d’invoquer un POST sur notre action en utilisant l’URL https://openwhisk.ng.bluemix.net/api/v1/namespaces/<NAMESPACE>/actions/bluemixSigfoxBridge, avec dans la BasicAuth les valeurs xxx en tant que user et yyy en tant que password. Dans le body, nous allons utiliser un JSON équivalent à celui que Sigfox nous poussera :

conteneur-callbacks

La réponse HTTP nous renvoie un numéro d’activation. Nous pouvons utiliser cet identifiant pour obtenir les traces de notre exécution :

$ wsk activation logs 223009cfbe1d4873b411a1bd93dde16a
2016-04-13T16:54:10.108005764Z stdout: Starting service
2016-04-13T16:54:14.066298008Z stdout: Message pushed : {
2016-04-13T16:54:14.06635685Z  stdout: "idEvent": "af8f677f-2d30-4d5a-a54e-a7355d79669f",
2016-04-13T16:54:14.066383211Z stdout: "luminance": "1",
2016-04-13T16:54:14.066400409Z stdout: "temperature": "25.5",
2016-04-13T16:54:14.066412734Z stdout: "humidity": "40",
2016-04-13T16:54:14.066423672Z stdout: "ack": true,
2016-04-13T16:54:14.066439583Z stdout: "time": 1454520570,
2016-04-13T16:54:14.066451139Z stdout: "device": "1C69C"
2016-04-13T16:54:14.066466347Z stdout: } to {
...
2016-04-13T16:54:14.066877827Z stdout: }

Autre solution pour obtenir les traces d’activation en live, la commande wsk activation poll qui récupère de manière quasi synchrone les logs d’exécution de vos actions.

Si tout s’est correctement passé, vous devriez maintenant avoir un statut plus complet dans le tableau de bord de votre objet :

conteneur-callbacks2

Il ne reste plus qu’à renseigner correctement le backend Sigfox pour compléter la première étape de notre découverte de Bluemix. N’oubliez pas d’ajouter le header Autorization, qui correspond à la BasicAuth (vous pouvez le récupérer directement depuis Postman).

conteneur-callbacks2-sigfox

Voilà pour cette première étape, les données de notre objet connecté remontent correctement dans le module IoT de Bluemix. Reste à les exploiter. Mais ce sera pour la semaine prochaine.

Pablo Lopez
Pablo est directeur technique au sein de Xebia. Opérationnel par goût, il intervient sur une large variété de missions, de l'analyse de performances en production au conseil en architecture logicielle.

Une réflexion au sujet de « Atelier – Plateforme 2 – IBM Bluemix (1/3) »

  1. Publié par Claude, Il y a 3 mois

    Bonjour
    Bravo pour vos tutoriaux très détaillés
    Avez pu continuer sur les autres modules de BlueMix et les autres plateformes IOT ?

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *