terça-feira, 17 de janeiro de 2017

Arduino com Ajax


Neste post vou dar um exemplo de código para implementar leitura e comando com o Arduino através do Navegador usando Ajax.
Como sabemos a tecnologia do Ajax permite a comunicação entre navegador e servidor sem precisar efetuar todo o recarregamento de toda página.
Então o primeiro request realizado pelo Navegador os códigos HTML e JavaScript são transferidos para o Navegador, a partir dai o código javaScript  (rodando no navegador) faz requisições ao servidor sem precisar transferir toda a página e com isto evitamos o flicker.
Usei o Arduino Mega 2560 com um shield baseado no W5100 assim a biblioteca Ethernet nativa da IDE do Arduino pode ser usada sem problemas:



Como pode ser visto na figura acima temos apenas um Led no pino 6 e ao GND com um resistor em série e um Jump para inserir 0V, 3.3V ou 5 V nas entradas analógicas para ser visualizado no navegador.
A interface gráfica é  bastante simples para não complicar o foco do funcionamento do Ajax:


Temos as leituras das 06 entradas analógicas e um botão para ligar e desligar o Led.

Existe a possibilidade de inserir a pagina HTML e JavaScript no cartão SD ou em um servidor externo mas neste post todo o código está no arduino.

Vamos ao código então:


#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };//Endereco Mac 
IPAddress ip(192, 168, 0, 52);//IP de acordo com a rede local

EthernetServer server(80);//Inicializa a biblioteca Ethernet
EthernetClient client;


int RED = 6;//  Liga & Desl. o Led no Pino 6
String HTTP_req; // String com a requisicao do Navegador


//================ajustes iniciais===============================
void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // Espera a porta serial iniciar
  }

  Ethernet.begin(mac, ip);//Inicia o Servidor
  server.begin();
  Serial.print("Servidor Escutando..... ");
  Serial.println(Ethernet.localIP());
  HTTP_req = "";
  pinMode(RED, OUTPUT);//Pino onde estah o LED
}

//==========Funcao para Envio do cabecalho padrao  HTTP ======================
void enviaCabecalhoHttp()
{
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println("Connection: close");  //A conexao sera fechada apos completar a resposta
  client.println();
}

//==================Funcao para enviar pagina HTML====================
void enviaHTML()
{
  
  client.println("<!DOCTYPE HTML>");
  client.println("<html lang=\"en\">");
  client.println("<script>window.setInterval(function(){");
  client.println("nocache = \"&nocache=\" + Math.random() * 10;");
  client.println("var request = new XMLHttpRequest();");
  client.println("request.onreadystatechange = function() {");
  client.println("if (this.readyState == 4) {");
  client.println("if (this.status == 200) {");
  client.println("if (this.responseText != null) {");
  client.println("document.getElementById(\"analoge_data\")\ .innerHTML = this.responseText;");
  client.println("}}}}");
  client.println("request.open(\"GET\", \"ajaxrefresh\" + nocache, true);");
  client.println("request.send(null);");
  client.println("}, 5000);");
  client.println("function changeLEDStatus() {");
  client.println("nocache = \"&nocache=\" + Math.random() * 10;");
  client.println("var request = new XMLHttpRequest();");
  client.println("request.onreadystatechange = function() {");
  client.println("if (this.readyState == 4) {");
  client.println("if (this.status == 200) {");
  client.println("if (this.responseText != null) {");
  client.println("document.getElementById(\"led_status\")\ .innerHTML = this.responseText;");
  client.println("}}}}");
  client.println("request.open(\"GET\", \"?ledstatus=1\" + nocache, true);");
  client.println("request.send(null);");
  client.println("}");
  client.println("</script></head>");
           
  client.print("<h1>Valores Analogicos</h1>"); //Valores de saida de cada pino analogico
  client.println("<div id=\"analoge_data\">Arduino analog input values loading.....</div>");
  client.println("<h1>Arduino LED Status</h1>");
  client.println("<div><span id=\"led_status\">");
  if(digitalRead(RED) == 1)
     client.println("On");//Passa a informacao do status do Led no carregamento da pagina
     else
     client.println("Off");//Passa a informacao do status do Led no carregamento da pagina
  client.println("</span> | <button onclick=\"changeLEDStatus()\">Troca Status</button> </div>");
  client.println("</html>");
  
}


//======================Loop principal================================
void loop() {
  client = server.available();//Escutando a entrada de clientes
  if (client) {
    Serial.println("Novo Cliente");
    
    boolean currentLineIsBlank = true;//Uma solicitação http termina com uma linha em branco
    
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if( HTTP_req.length() < 120)
          HTTP_req += c;  //Forma a String de requisicao 1 caracter por vez
        //Serial.write(c);
        
        /*
        Se você chegou ao final da linha (recebeu uma nova linha)
        E a linha está em branco, a solicitacao HTTP terminou,
        Para que você possa enviar uma resposta.
        */
        
        if (c == '\n' && currentLineIsBlank)//Inicio do Envio de Respostas das Requisicoes
        {
          enviaCabecalhoHttp();//Envia resposta com o cabecalho padrao HTTP
          
          Serial.println(HTTP_req);//Exibe no Monitor a requisicao feita pelo Navegador
          
          if (HTTP_req.indexOf("ajaxrefresh") >= 0 )//Se tem a palavra ajaxrefresh na requisicao
          {
            ajaxRequest();//Le portas analogicas
            break;
          }
          else if (HTTP_req.indexOf("ledstatus") >= 0 )//Se tem a palavra ledstatus na requisicao
          {
            ledChangeStatus();
            break;
          }
          else 
          {              
            enviaHTML();//Envia o codigo HTML e JavaScript para o Navegador
            break; 
          }
        }//Final dos Envios das requisicoes
        
        if (c == '\n')
        {
          currentLineIsBlank = true;// Estah comecando uma nova linha
        } 
        else if (c != '\r')
        {
          currentLineIsBlank = false;//Recebeu um caractere na linha atual
        }
      }
    }
    
    delay(1);//Tempo para o navegador receber os dados
    client.stop();//Fecha a conexao
    HTTP_req = "";//Limpa a String que recebe a mensagem do navegador
    Serial.println("cliente Desconectado");
  }
}

//===========Envia leituras do AD =======================
void ajaxRequest()
{
  for (int analogChannel = 0; analogChannel < 6; analogChannel++) 
  {
    int sensorReading = analogRead(analogChannel);//Leitura dos ADs de 0 a 6
    client.print("analog input ");
    client.print(analogChannel);
    client.print(" is ");
    client.print(sensorReading);//Valor lido dos canais 0 a 6
    client.println("<br />");
  }
}

//====================Troca o Estado do LED======================
void ledChangeStatus()
{
  int state = digitalRead(RED);
  Serial.println(state);
  if (state == 1) {
    digitalWrite(RED, LOW);
    client.print("OFF");
  }
  else {
    digitalWrite(RED, HIGH);
    client.print("ON");
  }
}

O código está todo comentado e podemos verificar que são 03 tipos de requisição do navegador ao Arduino que está operando como servidor:

  1. Requisição HTTP da página HTML e JavaScript
  2. Requisição Ajax das leituras das entradas analógicas
  3. Requisição ajax para ligar e Desligar o LED  


Usando o Monitor Serial ( atenção para a velocidade da Serial...) do Arduino pode-se acompanhar as requisições feitas pelo Navegador.

Quando o entra em operação tem-se a informação do IP que o servidor está aguardando as requisições:


Quando o Navegador estabelece a conexão é informado o tipo de requisição HTM/JavaScript


Após este carregamento o código javaScript transferido passa a fazer requisições Ajax em intervalos regulares para atualizar as informações no Navegador:


Quando o botão no navegador é clicado é feita uma requisição Ajax para mudança de status do Led como pode ser visto na figura abaixo:



Estas diferenças nas requisições podem ser observadas logo após o GET.

Para verificar os códigos transferidos do Servidor Arduino para o Navegador pode se clicar com o botão direito sobre a tela do navegador e pedir para exibir o código fonte:


Feito isto o código que foi transferido do arduino para o navegador pode ser visto:



O código foi dividido em várias funções para facilitar o entendimento.

Conseguir fazer o Arduino se comunicar com o Navegador abre um grande leque de opções, pois as aplicações Web tem a grande facilidade de acesso por causa das redes locais ou internet, além do que os códigos que rodam no Navegador são transferidos via rede dispensando a instalação de aplicativos.

Este código foi baseado no autor do seguinte email:  Gus @ ArduinoMyLifeUp.com

Espero ter ajudado com este simples exemplo
Até a próxima.










Nenhum comentário:

Postar um comentário