Interaja com a Web em tempo real usando Arduino, Firebase e Angular.js

Tempo de leitura: 6 minutes

Este projeto simples pretende ser uma introdução híbrida para conectar e manipular dados pela Internet com Arduino, Node, Angular e Firebase.

A Internet das Coisas não é nada novo. Você pode ter usado isso o tempo todo. No sentido mais amplo, seu laptop e smartphones são objetos de IoT. O que é realmente novo é a parte “T”. Temos usado computadores e smartphones com tanta frequência que dificilmente os reconhecemos como “coisas”. No entanto, “coisas” são mais sinônimos de objetos do cotidiano, como roupas, móveis, geladeiras, relógios, livros, lâmpadas, skates, bicicletas e etc. IoT é quando uma máquina de café prepara uma xícara de java para você quando o tempo fica muito frio, um par de sapatos que acende 10 minutos antes da chegada do trem ou uma maçaneta que alerta seu telefone quando seus pais tentam invadir seu quarto.

Para poder se conectar à Internet, dar sentido aos seus dados e interagir com os usuários, essas coisas precisam de pequenos computadores, também conhecidos como microcontroladores, para torná-los conscientes.

 

O que estamos construindo

Vamos conectar uma placa Arduino à internet e alterar a propriedade de cor RGB em uma página da web em tempo real girando um potenciômetro.

O que precisamos:

  • Arduino Uno
  • Cabo USB A-B
  • Potenciômetro
  • LED RGB
  • Resistores de 330 Ohms x 3
  • Resistência de 10 KOhms x 1
  • Fios de jumper macho para macho x 9

Tudo está incluído no kit do inventor do Sparkfun, que é muito legal para colocar em suas mãos. Sem necessidade de wi-fi ou blindagem ethernet, já que estamos na verdade mantendo os dados no banco de dados online e nos comunicamos com o aplicativo da web por meio da API REST fornecida pelo Firebase.

Se você não instalou o Node, vá para a página inicial do Node.js e siga as instruções para instalar o Node e o npm.

Todos os códigos podem ser baixados do meu repo ou clonados usando git:

$ git clone https://github.com/caneto/firepot

Depois de fazer o download, faça cd firepot para entrar no diretório e você verá dois subdiretórios – pot e app. CD em cada um e instale as dependências:

$ cd pot && npm install

Todas as dependências são indicadas em package.json, e o npm as instala automaticamente de acordo com as informações. Eles serão coletados em um novo subdiretório node_modules e podem ser exigidos por qualquer código dentro do escopo do projeto.

 

Conectando o circuito

Conecte seu circuito de acordo com o diagrama. Um potenciômetro típico possui três derivações. Conecte uma extremidade à alimentação de +5V via resistor pull-up de 10KOhms e a outra extremidade ao aterramento (0V). O potenciômetro fornece resistência variável entre a tensão e o condutor do meio deve ser conectado ao pino de entrada analógica do Arduino (A0) para alimentar o sinal de tensão no Arduino.

O LED RGB é essencialmente três LEDs em um, cada um com cores diferentes de vermelho, verde e azul, produzindo juntos 16.777.216 cores possíveis. Vamos usar o potenciômetro para atravessar essa faixa de cores do vermelho puro (#FF0000) ao azul (#0000FF) ao verde (#00FF00) e de volta ao vermelho novamente. O cabo mais longo do LED é chamado de comum e deve ser conectado ao aterramento. O resto está conectado às saídas PWM do Arduino (aquelas com ~ precedendo o número). O código conecta os terminais vermelho, verde e azul a ~9, ~10 e ~11, respectivamente.

Conecte o Arduino ao seu laptop por meio do cabo USB e pronto.

 

Inscrever-se no Firebase

Firebase é um serviço de banco de dados no estilo JSON para aplicativos em tempo real (você precisará de uma inscrição gratuita para usar). O Firebase implementa uma maneira inteligente de manipular dados JSON adotando APIs RESTful. Neste projeto, iremos CRIAR, LER e ATUALIZAR um bloco de dados parecido com este:

"colors" : {
  "r" : 255,
  "g" : 0,
  "b" : 0
}

O Firebase tem uma maneira fácil de acessar seus dados por meio da API REST, ou seja, você pode obter seus dados JSON em https://burning-limbo-6666.firebaseio.com/colors.json, onde https://burning-limbo-6666.firebaseio.com é o endereço de domínio do seu aplicativo que o Firebase gera para você após a criação de um novo aplicativo, e/colors é o nó pai dos seus dados. O Firebase tem um painel de dados no próprio URL, então você pode simplesmente colar o endereço no navegador e acessá-lo depois de atualizar os dados lá na próxima seção para ver seus dados alterados pelo pote em tempo real.

pot.js

Johnny-five é uma biblioteca javaScript que envolve a linguagem C/C++ do Arduino e faz interface com a placa via firmware Firmata, criada pelo incrível Rick Waldron, e é sinônimo de Movimento Nodebot. Para fazer isso funcionar, você deve abrir o IDE do Arduino para fazer um flash de um código Firmata padrão na placa. Em seu IDE, vá para Arquivo > Exemplos > Firmata > StandardFirmata e carregue o código (não se esqueça de selecionar a placa correta e a porta serial no menu Ferramentas). Assim que o upload for concluído, você pode fechar o IDE. Agora, vamos dar uma olhada em nosso código pot.js.

var Firebase = require("firebase");
var five = require("johnny-five");

// Create a new reference of Firebase db
var firebaseRef = new Firebase(
  // fictional URL, replace it with your own from Firebase
  "https://burning-limbo-6666.firebaseio.com/colors"
);

five.Board().on("ready", function() {
  var maxValue = 511;
  var colRange = 6;
  var offset   = maxValue / colRange;

  // Create a new pot instance
  var pot = new five.Sensor({
    pin: "A0",
    freq: 250
  });

  // Create a new led array based on pin number
  var ledArray = new five.Led.Array([9, 10, 11]);

  // Listen on data change
  pot.on("data", function() {

    var self = this.value;
    // Print pot value 
    console.log(self);

    // Map dynamic color brightness to pot value
    // RED - MAGENTA - BLUE
    var redDec   = Math.round(five.Fn.map(self, offset, offset*2, 255, 0));
    var blueInc  = Math.round(five.Fn.map(self, 0, offset, 0, 255));
    // BLUE - CYAN - GREEN
    var blueDec  = Math.round(five.Fn.map(self, offset*3, offset*4, 255, 0));
    var greenInc = Math.round(five.Fn.map(self, offset*2, offset*3, 0, 255));
    // GREEN - YELLOW - RED
    var greenDec = Math.round(five.Fn.map(self, offset*5, offset*6, 255, 0));
    var redInc   = Math.round(five.Fn.map(self, offset*4, offset*5, 0, 255));

    // Adjusting color brightness conditionally based on 
    // the location of the pot output value.
    switch (true) {
      case (self > 0 && self <= offset):
        console.log("1st loop");
        ledArray[0].brightness(255);
        ledArray[2].brightness(blueInc);
        ledArray[1].brightness(0);
    // update firebase colors' child node r, g, b
    firebaseRef.set({"r": 255, "b": blueInc, "g": 0});
        break;
      case (self > offset && self <= offset*2):
        console.log("2nd loop");
        ledArray[0].brightness(redDec);
        ledArray[2].brightness(255);
        ledArray[1].brightness(0);
    // update firebase colors' child node r, g, b
    firebaseRef.set({"r": redDec, "b": 255, "g": 0});
    break;
      case (self > offset*2 && self <= offset*3):
        console.log("3rd loop");
        ledArray[0].brightness(0);
        ledArray[2].brightness(255);
        ledArray[1].brightness(greenInc);
    // update firebase colors' child node r, g, b
    firebaseRef.set({"r": 0, "b": 255, "g": greenInc});
    break;
      case (self > offset*3 && self <= offset*4):
        console.log("4th loop");
        ledArray[0].brightness(0);
        ledArray[2].brightness(blueDec);
        ledArray[1].brightness(255);
    // update firebase colors' child node r, g, b
    firebaseRef.set({"r": 0, "b": blueDec, "g": 255});
        break;
      case (self > offset*4 && self <= offset*5):
        console.log("5th loop");
        ledArray[0].brightness(redInc);
        ledArray[2].brightness(0);
        ledArray[1].brightness(255);
    // update firebase colors' child node r, g, b
    firebaseRef.set({"r": redInc, "b": 0, "g": 255});
    break;
      case (self > offset*5 && self <= offset*6):
        console.log("6th loop");
        ledArray[0].brightness(255);
        ledArray[2].brightness(0);
        ledArray[1].brightness(greenDec);
    // update firebase colors' child node r, g, b
    firebaseRef.set({"r": 255, "b": 0, "g": greenDec});
    break;
      default:
    console.log("Out of range");
        ledArray[0].brightness(255);
    ledArray[2].brightness(0);
    ledArray[1].brightness(0);
    // update firebase colors' child node r, g, b
    firebaseRef.set({"r": 255, "b": 0, "g": 0});
    }
  });
});

Esta visualização html(V) vincula sua parte a um modelo de dados (M) que sincroniza os dados do seu Firebase storage e, conforme os dados mudam, apenas essa parte é renderizada novamente. O Angular opera no que é chamado de “diretiva”. As diretivas adicionam novas funcionalidades aos elementos HTML em vez de manipular o DOM como no JQuery. (3) a diretiva ng-app inicia o aplicativo e define o escopo da ligação, (7) ng-controller define o aplicativo controller(C) e o escopo sobre o qual aquele método de controlador específico tem efeito e (10) o estilo ng permite estilo dinâmico do documento (como você faria com .css ou .addClass do JQuery). Para exibir dados do modelo, colchetes duplos ({{}}) são usados para conter a variável, que é uma maneira comum de fazer isso na linguagem de modelo de outras estruturas da web. Não importa o objeto de dados por enquanto, você o verá em public/index.js. Certifique-se de ter incluído os scripts antes de </body>.

 

index.js

Esta é a sala de máquinas da nossa frente. Neste arquivo, anexamos o módulo firebase ao aplicativo, definimos o método do controlador e sincronizamos os dados do firebase para um objeto de modelo local usado pela vinculação html.

// Register firebase module                                                                                         
var app = angular.module("app", ["firebase"]);

// Set up controller function                                                                                       
app.controller("Ctrl", function($scope, $firebase) {
    var firebaseRef = new Firebase(
      // Replace this fictional URL with your own
      "https://burning-limbo-6666.firebaseio.com/colors"                                                          
    );
    // create an AngularFire ref to the data                                                                        
    var sync = $firebase(firebaseRef);

    // pull the data into a local model                                                                             
    var syncObject = sync.$asObject();

    // sync the object with three-way data binding                                                                  
    syncObject.$bindTo($scope, "data");
});

(2) Registre o serviço Firebase no aplicativo Angular. Depois disso, (5) você terá a variável $firebase disponível para injetar no controlador. (6–9) A configuração da primeira parte do método do controlador é familiar – criamos uma referência firebase para nossos dados. Agora, (11) use a referência como um parâmetro para $firebase() para criar uma referência Angularfire para os dados. (14) Nós traduzimos os dados em um objeto JavaScript e (17) os associamos à variável “data” que será usada no template index.html.

$ node pot.js

O console deve começar imprimindo “Servidor ouvindo na porta 3000” e emitindo valores RGB do Firebase. Vá para o navegador da Web e o navegador para http://localhost:3000, com sorte, você gostará do vídeo abaixo.