La semaine dernière, nous avons envoyé les données notre objet connecté vers AWS. Cette semaine, nous allons compléter la liste de nos exigences fonctionnelles en ajoutant les services additionnels, et en gérant le downlink.
Stocker les données.
Pour ceux qui ont l’habitude de AWS, il n’y aura pas vraiment de surprise. Amazon offre en effet un service de base de données non relationnelle orientée document, à savoir DynamoDB. Et comme AWS sait si bien le faire, l’intégration entre IoT et DynamoDB est aisée.
Retournons donc dans l’onglet IoT. Nous allons ajouter une nouvelle règle de gestion.
Il suffit ensuite de choisir DynamoDB dans la liste déroulante. Fait très appréciable, si votre base n’est pas préexistante, AWS vous permet de la créer à partir de cet écran. Nous verrons que ce n’est pas le cas chez tous les fournisseurs.
Les mécanismes internes de DynamoDB, et notre façon d’accéder aux données nous pousse vers un design simple : créer un clé primaire composite, avec l’identifiant de l’objet comme clé de hachage (toutes les données relatives à un objet se retrouveront sur la même partition), et le timestamp de la mesure comme clé de tri (les données seront ordonnées chronologiquement sur le disque). Petite subtilité, que je n’ai pas réussi à m’expliquer : votre colonne time doit être au format string
, faute de quoi DynamoDB refusera vos messages. Il semblerait que bien que le JSON de debug généré dans S3 montre que le champ time est un format number
, mais que la communication entre ioT et Dynamo le « convertit » en string
.
Créez votre action, et en déclenchant votre objet connecté (ou une simulation via Postman), vous devriez voir votre table se remplir :
Alerter par email
Mettons maintenant en place une simple règle métier : envoyer un mail d’alerte si la température dépasse 27°C. Là encore, tout se fait au niveau des actions disponibles dans le module IoT.
Il suffit d’adapter la requête de sélection des données pour qu’elle reflète cette règle simple. On ajoute donc une restriction dans la colonne Condition.
En ce qui concerne l’action déclenchée, nous allons utiliser le service de notification d’AWS, SNS. Là encore, chose agréable, il est possible de créer la file SNS (et le rôle associé) directement depuis le module IoT.
Ensuite, direction SNS, pour ajouter un envoi de mail lors de la réception d’un message dans la file.
Et là, magie, dès que votre objet envoie à Sigfox un message contenant une température supérieure à 27°C, Lambda transmet le message à IoT, qui fait suivre le message à SNS, qui transforme ce message en email :
Pour un email un peu plus élaboré, il faut concocter une architecture un peu plus complexe, qui enverra un évènement dans le service dédié, SES.
Mettre à jour un dashboard
Dernier étage de la fusée, pousser les données collectées sur un Dashboard « temps réel ». Là au moins, c’est simple, AWS ne propose pas ce type de service. Vous avez donc deux choix : héberger votre propre instance (par exemple en utilisant Dashing) ou bien vous reposer sur un service SaaS externe. Nous avons choisi cette dernière solution, avec un service de dashboarding extrêmement simple, Dashku.
Une fois inscrit, nous allons créer un tableau de bord basique, affichant les dernières valeurs reçues par chacun de nos trois capteurs.
Pour cela, il faut pousser à chacun des trois panels un fichier JSON en REST. Vous pouvez obtenir un exemple de code d’appel depuis NodeJs en cliquant sur l’engrenage, puis sur la pastille verte. Le code ressemble à celui ci :
var request = require("request"); var data = { "bigNumber": 500, "_id": "56f028b053146d7909011xxx", "apiKey": "7c3585c7-3ac8-45fb-840a-3e33d7e6fxxx" }; request.post({url: "https://dashku.com/api/transmission", body: data, json: true});
L’apiKey
est identique pour chacun des panels ; en revanche, l’_id
varie.
Pour que notre dashboard retrouve ses petits, il est nécessaire d’éditer chacun des widgets, pour les rendre plus parlant. Paramétrez donc les onglets HTML, CSS, et Javascript pour remplacer data
par le nim de vos champs dans le JSON émis par le module IoT (temperature, humidity et luminance).
Il reste donc à faire le pont entre le module IoT d’AWS et un appel REST. Nous l’avons fait dans un sens lorsque nous avons créé le bridge Sigfox, nous pouvons le faire dans l’autre sens en utilisant Lambda comme fonction de sortie au module IoT.
Reprenons donc notre Rule ‘Simple Debug’. Nous pouvons, en plus de S3, lui ajouter une sortie vers une Lambda, via le menu Edit actions.
Comme vous en avez maintenant l’habitude, il est possible de créer une nouvelle Lambda directement depuis ce menu.
Nous pouvons créer la Lambda directement depuis l’éditeur en ligne, celle ci est suffisamment simple pour qu’elle ne requiert pas un packaging évolué. Nous avons simplement réécrit la fonction extend
pour éviter d’avoir à importer le package utils
.
// Rewrite to avoir npm require function extend(obj1,obj2){ var obj3 = {}; for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; } for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; } return obj3; } // AWS Lambda handler exports.handler = function(event, context) { var httpCallsEmited = 0; var httpCallsEnded = 0; console.log('Input :', event); var data = { "temperature": event.temperature, "humidity": event.humidity, "luminance": event.luminance, "time": event.time, "device": event.device, "apiKey": "7c3585c7-3ac8-45fb-840a-3e33d7e6fxxx" }; function endHttpCall(err) { if (err) { context.fail("ERROR in http call"); } else { httpCallsEnded++; if(httpCallsEmited==httpCallsEnded){ context.succeed("SUCCESS"); } } } httpCallsEmited = 3; sendRequest(extend(data, {_id: "56f028b053146d7909011xxx"}), endHttpCall); sendRequest(extend(data, {_id: "56f028b453146d7909011xxx"}), endHttpCall); sendRequest(extend(data, {_id: "56f028b853146d7909011xxx"}), endHttpCall); }; function sendRequest(data, callback){ var http = require('https'); var options = { rejectUnauthorized: false, host: 'dashku.com', port: 443, path: '/api/transmission', method: 'POST', headers: { 'Content-Type': 'application/json' } }; var req = http.request(options, function(res) { res.setEncoding('utf8'); res.on('data', function (chunk) { console.log("body: " + chunk); callback(); }); res.on('error', function (err) { console.log("body: " + chunk); callback(err); }); }); req.write(JSON.stringify(data)); console.log(JSON.stringify(data)) req.end(); }
Si tout s’est bien passé, chaque émission de votre objet Sigfox devrait maintenant mettre à jour votre tableau de bord Dashku :
Cliffhanger
Nous en avons fini du traitement des données environnementales émises par notre objet connecté. Reste maintenant un gros morceau : le traitement des données en downlink, depuis notre cloud vers notre objet. Mais à chaque jour suffit sa peine ; nous verrons cela une prochaine fois.