sexta-feira, 14 de novembro de 2014

Arduino etílico 3: A Internet das Coisas





Neste novo artigo da série "Arduino Etílico", vamos mostrar um pouco da versatilidade do Javascript em uma aplicação de IoT, oi "Internet das Coisas".



Para demonstrar a versatilidade do Javascript, e sua aplicabilidade em sistemas embarcados, eu criei um "sensor" de temperatura, capaz de enviar notificações via Google Cloud Message para dispositivos Android.






Mas isso não é "Internet das Coisas" !



Realmente, os críticos de plantão dirão que: Internet das Coisas é diferente de "Uma coisa acessando à Internet".

Lamento, mas isso não é verdade. Na própria definição de IoT, na Wikipedia, temos o primeiro parágrafo:

The Internet of Things (IoT) is the interconnection of uniquely identifiable embedded computing devices within the existing Internet infrastructure."


Logo, minha aplicação consiste em um dispositivo "embarcado", um sensor, composto por um Raspberry e um Arduino, que se comunica através da Internet.

Mesmo não utilizando os protocolos próprios da comunicação M2M (Machine to Machine), como o MQTT, ainda é um dispositivo autônomo (e não um computador pessoal, ou um smartphone), se comunicando via Internet automaticamente.





O diagrama do sensor



O circuito que usei foi o mesmo do artigo anterior. Ele tem um termistor na porta analógica 0 e dois leds. Veja no Arduino Etílico 2 como montar.

A modificação foi usar um Raspbery na porta USB, com o Node.js e o GCM instalados.

Preparação do Raspberry



O Raspberry é ARM, logo, temos que instalar tudo de maneira diferente. Primeiramente, a IDE do Arduino:


  • sudo apt-get update

  • sudo apt-get install arduino



Rode a IDE (com seu Arduino conectado) e veja se encontra o dispositivo Serial "ttyACM0".

Já o Node.js e o NPM precisam ser instalados de um porte especial para ARM:


  • wget http://node-arm.herokuapp.com/node_latest_armhf.deb

  • sudo dpkg -i node_latest_armhf.deb








Olha a bagaça toda



Eis a minha bagaça: Um Rasberry, um Arduino e o circuito. Eu não estou usando WiFi porque não tive grana para comprar um modem para o Raspberry. Um Shield WiFi para o Arduino é MUITO mais caro que um modem WiFi para o Raspberry.

Bom, agora, carregue o exemplo "StandardFirmata" na IDE do Arduino e faça upload.






Ok. Está tudo quase pronto! Agora, precisamos de um script node.js para controlar nosso Arduino. O código-fonte está no Dropbox. Eis o script:


var five = require("johnny-five");
var gcm = require('node-gcm');
 
var sender = new gcm.Sender('<< API Key do GCM >>'); 
var registrationIds = [];

registrationIds.push('<< Registratio ID do seu dispositivo Android >>');

var msgSent = false;

function sendMsg(msg) {
   var message = new gcm.Message();
   message.addData('message', msg);
   message.addData('title','URGENTE!!!' );
   message.addData('msgcnt','3'); 
   message.addData('soundname','beep.wav'); 
   message.collapseKey = 'demo';
   message.delayWhileIdle = true; 
   message.timeToLive = 3000;
   sender.send(message, registrationIds, 4, function (err, result) {
      if(err) {
        console.log('Erro: ' + err);
      }
      if (result) {
        console.log('Result: ' + JSON.stringify(result));
      }
      else {
        console.log('Result nulo');
      }
   });
   msgSent = true;
}

five.Board().on("ready", function() {
  var sensor = new five.Sensor("A0");
  var ledVerde = new five.Led(3);
  var ledVermelho = new five.Led(5);
  sensor.on("data", function() {
    var temp = (this.value * 0.2027) - 82;
    console.log(temp + "°C"); 
    if(temp <= 30) {
        ledVermelho.off();
        ledVerde.on();
      if(!msgSent) {
            sendMsg("Estouro de temperatura");
        }
    }
    else {
        msgSent = false;
           ledVermelho.on();
          ledVerde.off();
    }
  });
});



Você tem que colocar a API Key do Google Cloud Message. Mas calma que eu vou falar depois sobre isso.

Eu uso dois módulos NPM: johnny-five e node-gcm. Eis o package.json:


{
  "name": "iottemp1", 
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node iottemp1.js"
  },
  "dependencies": {
    "johnny-five" : "*",
    "node-gcm": "*"    
  }
}



E, como o nosso dispositivo envia uma "Push notification", precisamos ter uma aplicação Android para recebe-la. Ela está no mesmo ZIP. Eu fiz uma app simples, que tem um arquivo de "code-behind" usando jQuery. Eis o arquivo index.js:


var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
    },
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicitly call 'app.receivedEvent(...);'
    onDeviceReady: function() {
        app.receivedEvent('deviceready');
    },
    // Update DOM on a Received Event
    receivedEvent: function(id) {
        var pushNotification = window.plugins.pushNotification;
        pushNotification.register(app.successHandler, app.errorHandler,{"senderID":"","ecb":"app.onNotificationGCM"});
        var parentElement = document.getElementById(id);
        var listeningElement = parentElement.querySelector('.listening');
        var receivedElement = parentElement.querySelector('.received');

        listeningElement.setAttribute('style', 'display:none;');
        receivedElement.setAttribute('style', 'display:block;');

        console.log('Received Event: ' + id);
    },
    // result contains any message sent from the plugin call
    successHandler: function(result) {
    alert('Callback Success! Result = '+result)
    },
    errorHandler:function(error) {
    alert(error);
    },
    onNotificationGCM: function(e) {
        switch( e.event )
        {
            case 'registered':
                if ( e.regid.length > 0 )
                {
                    console.log("Regid " + e.regid);
                    alert('registration id = '+e.regid);
                }
            break;
 
            case 'message':
              // this is the actual push notification. its format depends on the data model from the push server
              alert('message = '+e.message+' msgcnt = '+e.msgcnt);
            break;
 
            case 'error':
              alert('GCM error = '+e.msg);
            break;
 
            default:
              alert('An unknown GCM event has occurred');
              break;
        }
    }
};



Para que essa app funcione, é necessário infornar o Project ID do seu projeto que usa a API Google.

Então, é só carregar o APK no Android (mostrarei mais adiante), e rodar nosso script no Raspberry: "node iottemp1"'.






App enviano notificação



Aqui, vemos a app enviando uma notificação, porque a temperatura passou de 30 graus C (é só segurar o termistor por 3 segundos).






A notificação chegou!



Como podemos ver, a notificação chegou sem problemas.

A mesma app móvel poderia ser adaptada para uso com o APNS - Apple Push Notification Service, permitindo enviar notificações para iPhone também.

Otras cositas...



Para saber como cadastrar seu projeto no Google Cloud Messaging, leia a aula sobre Conectividade, do meu curso de PhoneGap.

Para saber como transferir apk criada em PhoneGap para um dispositivo Android, leia a Segunda lição do meu curso de PhoneGap.