Publicidade:

quarta-feira, 17 de junho de 2015

Arduino - Ethernet Shield + SDCard + Arquivos


Nesse vídeo mostro como incluir imagens, javascript, e outros tipos de arquivos e mídias na sua aplicação web baseada no Ethernet Shield W5100


31/10/2016 - Observação
Erro de login

Várias pessoas têm me relatado problemas no login, e eu não havia conseguido achar o problema, mas o Rodrigo (nos comentários abaixo) encontrou o problema e postou a solução. Vou manter o código original, e se quem tiver erros, siga o que o Rodrigo recomendou:

//Descobri o problema e mudei o meu código. 
//A função base64_encode não retorna corretamente o primeiro byte codificado, 
//por isso a função validar_usuario sempre recebia a string "out" errada. 
//Tive que trocar a função base64_encode para uma que retornasse o valor 
//inteiro de "out" codificado. Dai minha função validar_usuario ficou assim:

boolean validar_usuario(char * linebuf) {
  char usuario_senha[] = "admin:admin"; //"admin:admin";
  byte t = strlen(usuario_senha);
  int tamanhoEnc = (((t-1) / 3) + 1) * 4; //tamanho da string codificada
  char *out = base64_encode(usuario_senha, t);
  char out2[tamanhoEnc];

  for (t=0; t<(tamanhoEnc); t++) {
    out2[t] = linebuf[21+t];
  }
  return (strstr(out2, out)>0);
} 


Entenda o Mime Types:
https://pt.wikipedia.org/wiki/MIME

Lista de todos (acredito eu) os Mime Types de Arquivos:
http://www.sitepoint.com/web-foundations/mime-types-complete-list/



Para rodar a aplicação, copie os seguintes arquivos para dentro do SDCard



atmel.pdf

Qualquer arquivo PDF chamado atmel.pdf (cuidado com o tamanho do arquivo)

favicon.ico

qualquer arquivo do tipo ico, chamado favicon.ico

uno.jpg

qualquer imagem do tipo jpg, chamada uno.jpg


os demais arquivos, devem ser conforme mostrados abaixo


HTML - index.htm

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" type="text/css" href="/css.css">
  <script src="/js.js"></script>
</head>
<body onload="init();">
  <h1>ARDUINO - ETHERNET SHIELD + SDCARD + ARQUIVOS</h1>
  <br>
  <img src="/uno.jpg" />
  <br>
  <a href="/atmel.pdf">Download datasheet</a> | <a href='/logoff'>Logoff</a>
  <br>
</body>
</html>


Javascript - js.js

function init(){
  window.alert("hello world!");
}



CSS - css.css

body {
    background-color: #FAEBD7;
}
h1 {
    margin-left: 40px;
} 




Sketch - código-fonte:

/*
 Web Server - HTTP Autentication
 Baseado na versão de exemplo do Arduino.
 
   - exemplo que mostra como incluir html, css, 
   javascript e imagem em arquivos no sdcard e também
   como fazer download de um arquivo pdf do sdcard.
  
   by Fabiano A. Arndt (fabianoallex)
*/

/**********************************************************************************
************************************BIBLIOTECAS************************************
**********************************************************************************/

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

/**********************************************************************************
********************************FIM BIBLIOTECAS************************************
**********************************************************************************/

/**********************************************************************************
*************************ROTINAS USUARIO E SENHA***********************************
***********************************************************************************/

boolean validar_usuario(char * linebuf) {
  /*
  nesse exemplo o usuario e senha estão definidos dentro do código fonte.
  mas o usuário e senha poderiam ser autenticados de diversas maneiras,
  lendo os dados de um servidor web, arquivo texto, etc, bastando apenas atribuir
  o valor lido para a variável usuario_senha. 
  */
  
  char usuario_senha[] = "admin:admin";                           //usuario e senha para acessar a pagina
  int t = strlen(usuario_senha);
  
  int tamanhoEnc = (((t-1) / 3) + 1) * 4;   //tamanho da string codificada
  char out[tamanhoEnc];
  base64_encode(out, usuario_senha, t+1 );
  
  //---desconta é usado pra eliminar os caracteres '='
  int desconta = 0;
  if ((t%3) == 1) { desconta = 2; }
  if ((t%3) == 2) { desconta = 1; }
  
  char out2[tamanhoEnc-desconta];
  
  byte i;
  for (i=0; i<(tamanhoEnc-desconta);i++){ out2[i] = out[i]; }
  out2[i] = '\0';
  
  return ( strstr(linebuf, out2)>0 );
}

/**********************************************************************************
*************************FIM ROTINA USUARIO E SENHA********************************
***********************************************************************************/

/****************************************************************************************
 ****************************SD CARD INICIO***********************************************
 ****************************************************************************************/

#define PIN_SD_CARD 4
 
boolean iniciar_sd_card() {
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
   
  if (!SD.begin(PIN_SD_CARD)) { return false; }
   
  return true;
}

 
/****************************************************************************************
 ****************************SD CARD FIM**************************************************
 ****************************************************************************************/
 

/**********************************************************************************
***********************************PAGINAS HTML************************************
***********************************************************************************/
EthernetServer * server;

void write_from_file(EthernetClient &client, char * filename){
  File webFile = SD.open(filename);
  if (webFile) {
    while(webFile.available()) {
      client.write(webFile.read()); 
    }
    webFile.close();
  } else {
    Serial.print("Erro SD CARD: ");
    Serial.println(filename);
  }
}

void iniciar_ethernet_01(){
  byte ip[4]      = {192,168,200,25};                    //definir aqui o ip
  byte gateway[4] = {192,168,200,254};
  byte subnet[4]  = {255,255,255,0};
  byte mac[6]     = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
  int  porta      = 80;

  server = new EthernetServer(porta);

  Ethernet.begin(mac, ip, gateway, subnet);         //caso necessario gateway utilizar essa linha
  server->begin();
}

void iniciar_ethernet_02(){
  byte ip[4]      = {192,168,200,25};                    //definir aqui o ip
  byte mac[6]     = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
  int  porta      = 80;

  server = new EthernetServer(porta);

  Ethernet.begin(mac, ip);
  server->begin();
}

void iniciar_ethernet() {              //escolher apenas um dos dois modos de iniciar o ethernet shield
  iniciar_ethernet_01();               //inicia com ip, gateway, mascara e porta
  //iniciar_ethernet_02();             //inicia só com ip e porta
}

void html_cab_200_ok(EthernetClient &client){
  
  client.println(F("HTTP/1.1 200 OK\n"
                   "Content-Type: text/html\n"
                   "Connection: keep-alive\n\n"));
}


void html_logoff(EthernetClient &client){
    client.print(F(
                 "HTTP/1.1 401 Authorization Required\n"  
                 "Content-Type: text/html\n"  
                 "Connnection: close\n\n"  
                 "<!DOCTYPE HTML>\n"  
                 "<html><head><title>Logoff</title>\n"  
                 "<script>document.execCommand('ClearAuthenticationCache', 'false');</script>"  //IE logoff
                 "<script>try {"                                                                //mozila logoff
                 "   var agt=navigator.userAgent.toLowerCase();"
                 "   if (agt.indexOf(\"msie\") != -1) { document.execCommand(\"ClearAuthenticationCache\"); }"
                 "   else {"
                 "     var xmlhttp = createXMLObject();"
                 "      xmlhttp.open(\"GET\",\"URL\",true,\"logout\",\"logout\");"
                 "     xmlhttp.send(\"\");"
                 "     xmlhttp.abort();"
                 "   }"
                 " } catch(e) {"
                 "   alert(\"erro ao fazer logoff\");"
                 " }"
                 "function createXMLObject() {"
                 "  try {if (window.XMLHttpRequest) {xmlhttp = new XMLHttpRequest();} else if (window.ActiveXObject) {xmlhttp=new ActiveXObject(\"Microsoft.XMLHTTP\");}} catch (e) {xmlhttp=false;}"
                 "  return xmlhttp;"
                 "}</script>"
                 "</head><body><h1>Voce nao esta mais conectado</h1></body></html>\n"));
}

void html_autenticar(EthernetClient &client) {
  client.print(F("HTTP/1.1 401 Authorization Required\n"  
               "WWW-Authenticate: Basic realm=\"Area Restrita\"\n"  
               "Content-Type: text/html\n"  
               "Connnection: close\n\n"  
               "<!DOCTYPE HTML>\n"  
               "<html><head><title>Error</title>\n"  
               "</head><body><h1>401 Acesso nao autorizado</h1></body></html>\n"));
}

void html_autenticado(EthernetClient &client, char * filename){
  client.println(F("HTTP/1.1 200 OK\n"
                   "Content-Type: text/html\n"
                   "Connection: keep-alive\n"));

  write_from_file(client, filename);
}


void js_file(EthernetClient &client, char * filename){
  client.println(F("HTTP/1.1 200 OK\n"
                   "Content-Type: text/javascript\n"
                   "Connection: keep-alive\n"));

  write_from_file(client, filename);
}

void css_file(EthernetClient &client, char * filename){
  client.println(F("HTTP/1.1 200 OK\n"
                   "Content-Type: text/css\n"
                   "Connection: keep-alive\n"));

  write_from_file(client, filename);
}

void favicon_file(EthernetClient &client, char * filename){
  client.println(F("HTTP/1.1 200 OK\n"
                   "Content-Type: image/x-icon\n"
                   "Connection: keep-alive\n"));

  write_from_file(client, filename);
}


void pdf_file_download(EthernetClient &client, char * filename){
  client.println(F("HTTP/1.1 200 OK\n"
                   "Content-Type: application/download\n"
                   "Connection: close\n"));
    
  write_from_file(client, filename);
}

void jpg_file(EthernetClient &client, char * filename){
  client.println(F("HTTP/1.1 200 OK\n"
                   "Content-Type: file/jpg\n"
                   "Connection: close\n"));
    
  write_from_file(client, filename);
}


void exec_ethernet() {
  EthernetClient client = server->available();
  if (client) {
    char linebuf[80];
    memset(linebuf, 0, sizeof(linebuf));
    
    int     charCount          = 0;
    boolean autenticado        = false;
    boolean currentLineIsBlank = true;
    boolean logoff             = false;
    boolean indCss             = false;
    boolean indJs              = false;
    boolean indPdfDataSheet    = false;
    boolean indJpgUno          = false;
    boolean indFavicon         = false;
    
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        
        linebuf[charCount] = c;
        
        if (charCount<sizeof(linebuf)-1) { charCount++; }
        Serial.write(c);
        
        if (c == '\n' && currentLineIsBlank) {
          if (autenticado && !logoff ) {
            if (indJs){
              js_file(client, "js.js");                          //js file
            } else if(indCss){
              css_file(client, "css.css");                       //css file
            } else if(indPdfDataSheet){
              pdf_file_download(client, "atmel.pdf");        //datasheet download
            } else if(indJpgUno){
              jpg_file(client, "uno.jpg");                       //jpg file
            } else if(indFavicon){
              jpg_file(client, "favicon.ico");                   //icone do browser
            } else {
              html_autenticado(client, "index.htm");             //página inicial
            }
          } else {
            logoff ? html_logoff(client) : html_autenticar(client);
          }
          break;
        }
        if (c == '\n') { 
          currentLineIsBlank = true;               
          
          if (strstr(linebuf, "GET /logoff"         )>0 ) { logoff = true; }
          if (strstr(linebuf, "Authorization: Basic")>0 ) { if ( validar_usuario(linebuf) )   {  autenticado = true;   } }  
          if (strstr(linebuf, "GET /css.css"        )>0 ) { indCss = true; }
          if (strstr(linebuf, "GET /js.js"          )>0 ) { indJs = true; }
          if (strstr(linebuf, "GET /atmel.pdf"      )>0 ) { indPdfDataSheet = true; }
          if (strstr(linebuf, "GET /uno.jpg"        )>0 ) { indJpgUno = true; }
          if (strstr(linebuf, "GET /favicon.ico"    )>0 ) { indFavicon = true; }
          
          
          memset(linebuf, 0, sizeof(linebuf));
          charCount = 0;
        } else if (c != '\r') {
          currentLineIsBlank = false;    // you've gotten a character on the current line
        }
      }
    }
    
    delay(1);           
    client.stop();      
  }
}
/**********************************************************************************
**************************************** FIM PAGINAS HTML**************************
***********************************************************************************/


/**********************************************************************************
*************************BASE 64 CODE/DECODE DO USUARIO E SENHA********************
***********************************************************************************/

void a3_to_a4(unsigned char * a4, unsigned char * a3);
void a4_to_a3(unsigned char * a3, unsigned char * a4);
unsigned char b64_lookup(char c);

int base64_encode(char *output, char *input, int inputLen) {
  const char b64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  int i=0, j=0, encLen=0;
  unsigned char a3[3], a4[4];

  while(inputLen--) {
    a3[i++] = *(input++);
    if(i == 3) {
      a3_to_a4(a4, a3);
      for(i=0; i<4; i++) { output[encLen++] = b64_alphabet[a4[i]]; }
      i = 0;
    }
  }

  if (i) {
    for(j = i; j < 3; j++)     { a3[j] = '\0';                           }
    a3_to_a4(a4, a3);
    for(j = 0; j < i + 1; j++) { output[encLen++] = b64_alphabet[a4[j]]; }
    while((i++ < 3))           { output[encLen++] = '=';                 }
  }
  output[encLen] = '\0';
  return encLen;
}

/*
int base64_decode(char * output, char * input, int inputLen) {
  int i = 0, j = 0;
  int decLen = 0;
  unsigned char a3[3];
  unsigned char a4[4];
  while (inputLen--) {
    if (*input == '=') { break; }
    a4[i++] = *(input++);
    if (i == 4) {
      for (i = 0; i <4; i++)  { a4[i] = b64_lookup(a4[i]); }
      a4_to_a3(a3,a4);
      for (i = 0; i < 3; i++) { output[decLen++] = a3[i];  }
      i = 0;
    }
  }

  if (i) {
    for (j=i; j<4; j++)   { a4[j] = '\0';             }
    for (j=0; j<4; j++)   { a4[j] = b64_lookup(a4[j]);}
    a4_to_a3(a3,a4);
    for (j=0; j<i-1; j++) { output[decLen++] = a3[j]; }
  }
  output[decLen] = '\0';
  return decLen;
}
*/

//int base64_enc_len(int plainLen) {
//  int n = plainLen;
//  return (n + 2 - ((n + 2) % 3)) / 3 * 4;
//}

//int base64_dec_len(char * input, int inputLen) {
//  int i = 0;
//  int numEq = 0;
//  for(i = inputLen - 1; input[i] == '='; i--) { numEq++; }
//  return ((6 * inputLen) / 8) - numEq;
//}

void a3_to_a4(unsigned char * a4, unsigned char * a3) {
  a4[0] = (a3[0]  & 0xfc) >> 2;
  a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
  a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
  a4[3] = (a3[2] & 0x3f);
}

//void a4_to_a3(unsigned char * a3, unsigned char * a4) {
//  a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4);
//  a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2);
//  a3[2] = ((a4[2] & 0x3) << 6) + a4[3];
//}

unsigned char b64_lookup(char c) {
  if(c >='A' && c <='Z') return c - 'A';
  if(c >='a' && c <='z') return c - 71;
  if(c >='0' && c <='9') return c + 4;
  if(c == '+') return 62;
  if(c == '/') return 63;
  return -1;
}

/**********************************************************************************
*************************FIM BASE 64 CODE/DECODE DO USUARIO E SENHA****************
***********************************************************************************/

/**********************************************************************************
**************************************** VOID / LOOP ******************************
***********************************************************************************/

void setup() {
  Serial.begin(9600);
  iniciar_sd_card();
  iniciar_ethernet();
}

void loop() {
  exec_ethernet();
}

/**********************************************************************************
*************************************FIM VOID / LOOP*******************************
***********************************************************************************/

49 comentários:

  1. Fabiano, poderia passar onde entraria o código no arquivo.ino para acionar as lâmpadas por exemplo.

    ResponderExcluir
    Respostas
    1. no html vc vai incluir o código que envia os comandos que vc quer executar, algo assim:

      < form method="GET" action="/comandos" >
      < input type="checkbox" name="led7" > Ligar led 7



      < input type="submit" value="Submit">
      < /form >


      e no scketch vc vai incluir um if nessa lista abaixo:

      if (strstr(linebuf, "GET /logoff" )>0 ) { logoff = true; }
      if (strstr(linebuf, "Authorization: Basic")>0 ) { if ( validar_usuario(linebuf) ) { autenticado = true; } }
      if (strstr(linebuf, "GET /css.css" )>0 ) { indCss = true; }
      if (strstr(linebuf, "GET /js.js" )>0 ) { indJs = true; }
      if (strstr(linebuf, "GET /atmel.pdf" )>0 ) { indPdfDataSheet = true; }
      if (strstr(linebuf, "GET /uno.jpg" )>0 ) { indJpgUno = true; }
      if (strstr(linebuf, "GET /favicon.ico" )>0 ) { indFavicon = true; }
      if (strstr(linebuf, "GET /comandos" )>0 ) { executa_comandos(linebuf); }


      veja que a ultima linha acima foi incluida pra tratar os comandos

      ai vc cria a função que ira tratar os comandos recebidos

      void executa_comandos(char * linebuf) {
      pinMode(7, OUTPUT);
      if (strstr(linebuf, "led13=on" )>0 ) {
      digitalWrite(7, LOW);
      } else {
      digitalWrite(7, HIGH);
      }

      //aqui vc coloca os demais comandos que serão recebidos do html
      }


      qualquer duvida só falar.

      Excluir
    2. corrigindo...

      void executa_comandos(char * linebuf) {
      pinMode(7, OUTPUT);
      if (strstr(linebuf, "led7=on" )>0 ) {
      digitalWrite(7, HIGH);
      } else {
      digitalWrite(7, LOW);
      }

      //aqui vc coloca os demais comandos que serão recebidos do html
      }

      Excluir
    3. eu estou apanhando nesse mesmo lugar!!! por favor poderia me explicar melhor?
      meu email é gtautomotivo@hotmail.com

      muito obrigado
      william

      Excluir
    4. to fazendo um artigo novo sobre ethernet shiedl, com mais alguns detalhes, mas to meio sem tempo de terminar, mas assim que der ele vai tá no ar, acho que vai ajudar nessas dúvidas.

      Excluir
    5. Boa noite, você poderia disponibilizar esse artigo?

      Excluir
  2. Olá fabiano como eu conseguiria ler um sensor na porta analógica? Poderia me mandar um email com o código fbramos27@gmail.com

    ResponderExcluir
  3. Nesta linha "//aqui vc coloca os demais comandos que serão recebidos do html" os "comandos" são obrigatórios ou opcionais?
    Se obrigatórios, poderia dizer quais são?

    ResponderExcluir
    Respostas
    1. na verdade são os parâmetros que serão passados do html para o arduino. no exemplo, led7=on significa que é pra ligar um led. Ou seja, tem um parâmetro que é passado, e que quando recebido ele executa um comando, que seria ligar o led, poderia ser qualquer outra coisa. Não são obrigatórios.

      Excluir
    2. Fabiano, muito obrigado pela atenção e presteza.

      Já consegui acionar até 3 relés com os códigos "htm" inseridos no próprio sketch. Mas, utiliza muita memória e não consigo aumentar a quantidade de relés.

      Estou tentando fazer acionar 4 relés e para isso preciso escrever os códigos da página "htm", gravar no SDCard e trazer os comandos para o sketch interpretar.

      Caso você possua alguma coisa que possa compartilhar faça esse favor. Vou continuar procurando solução, caso obtenha, posto aqui.

      De antemão, mais uma vez, obrigado!


      Excluir
    3. to fazendo um artigo novo sobre ethernet shiedl, com mais alguns detalhes, mas to meio sem tempo de terminar, mas assim que der ele vai tá no ar, acho que vai ajudar nessas dúvidas.

      Excluir
    4. Bom dia Fabiano.
      Seria de grande ajuda se você puder explicar sobre este ponto.
      Preciso enviar um sinal de valor lógico 1 por um botão contido nessa página.
      Parabéns pela qualidade dos seus trabalhos!

      Excluir
    5. Lembrando que a sua explicação a esta questão ao colega que lhe perguntou eu testei exatamente e não acendeu o led. Obrigado.

      Obs: existem outros exemplos que acende um led pelo webserver do arduino, porém é mais complicado de achar quando a página é gerada pelo código html dentro do cartão SD.

      Excluir
    6. a questão aqui é que exige conhecimentos um pouco mais avançados. No meu exemplo, to mostrando como carregar arquivos do cartão, no caso dos arquivos html, eles são estáticos, não dinâmicos, apenas pra exemplificar como carregar algo do cartão de memória.

      a ideia é mostrar alguns conceitos, e não aprofundar tudo que é possível fazer.

      pra incluir dinamicidade às páginas é preciso usar outros recursos, como javascript, ajax, requisições assíncronas, etc.

      mas isso já são questões de desenvolvimento web, e eu não queria misturar os conceitos. Seria interessante buscar esses conhecimentos sem serem especificamente voltados para Arduino. Por isso não quis misturar as coisas, pra não bagunçar.

      eu to com outro artigo pra terminar que queria tratar um pouco desses outros detalhes, mas to sem tempo, e por enquanto ainda não tenho previsão de terminar.

      Excluir
  4. Este comentário foi removido pelo autor.

    ResponderExcluir
  5. Fantastic exemplo! ¡Fantástico ejemplo! Fantastic example!

    ResponderExcluir
  6. boa tarde
    muito bom o exemplo criado por voce
    e temos que agradecer a iniciativa de compartilhar seu conhecimento
    seria possivel me auxiliar em uma duvida
    quando envio valor led7=on toda pagina e recarregada

    ResponderExcluir
    Respostas
    1. bom dia, valeu. quanto a sua dúvida, só verificando o código pra eu conseguir saber o que pode estar errado. qualquer coisa manda um email pra fabianoallex@gmail.com. abraço

      Excluir
  7. Boa noite.
    Tentei usar seu código para um teste, e não sai da pagina de login.
    oque pode ser?

    ResponderExcluir
    Respostas
    1. Boa Noite....

      Então, Não aparece mensagem de erro... apos fazer a autenticação (admin admin) ele voltar na pagina para autenticar novamente, vira um ciclo.

      Estou testando com o arduino mega 2560 e shield Ethernet w5100
      muda alguma configuração por ser no mega?



      Excluir
    2. O meu está com o mesmo problema. Só fica pedindo usuario e senha....

      Excluir
    3. O meu uno também está com o mesmo problema.

      Excluir
    4. Acho que o problema está na função validar_usuario, pois ela nunca retorna true. Tentei debugar o código, e aparentemente a string out2 nunca está contida na string linebuf. Alguma luz aí?

      Excluir
    5. Descobri o problema e mudei o meu código. A função base64_encode não retorna corretamente o primeiro byte codificado, por isso a função validar_usuario sempre recebia a string "out" errada. Tive que trocar a função base64_encode para uma que retornasse o valor inteiro de "out" codificado. Dai minha função validar_usuario ficou assim:

      boolean validar_usuario(char * linebuf) {
      char usuario_senha[] = "admin:admin"; //"admin:admin";
      byte t = strlen(usuario_senha);
      int tamanhoEnc = (((t-1) / 3) + 1) * 4; //tamanho da string codificada
      char *out = base64_encode(usuario_senha, t);
      char out2[tamanhoEnc];

      for (t=0; t<(tamanhoEnc); t++) {
      out2[t] = linebuf[21+t];
      }
      return (strstr(out2, out)>0);
      }

      Excluir
    6. obrigado Rodrigo, várias pessoas tem relatado esse problema, mas ainda não tinha conseguido um tempo pra verificar o que poderia ser. Vou editar no artigo pra quem estiver com problema seguir sua solução.

      Excluir
    7. Rodrigo, tentei esse cod que vc deixou acima, mas da um erro, -> invalid convertion fron 'byte {aka unsigned char}' to 'char*'[-fpermissive] <- esse erro da na linha : char out = base64_encode(usuario_senha, t); , se puder me ajudar eu agradeço

      Excluir
    8. Comigo também dá erro, char *out = base64_encode(usuario_senha, t);.
      A função base64_encode pede 3 parâmetros e no caso aqui manda só 2.

      Excluir
    9. mesma coisa comigo. pede 3 parametros mas so tem 2.

      Excluir
  8. Bom dia amigo. Preciso enviar dados de um banco de dados para o meu arduino, como por exemplo o usuário e senha. Você tem ideia de como eu fazer? Consigo enviar do arduino para o banco de dados o qual estão atrelados por um servidor php, mas o contrário eu não consigo.
    Gostaria de saber se existe algum comando ou algo do tipo.

    Muito obrigado.

    ResponderExcluir
  9. Boa tarde Fabiano, ainda não consegui fazer com que meu html acione minha saída, teria como você mandar um exemplo para meu email..
    eduardoewertoncruzdelima@gmail.com
    Muito show o post, porém ainda tenho dificuldades com a programação.
    Vlw

    ResponderExcluir
    Respostas
    1. Olá Fabiano. Sei que não é exatamente sobre o assunto desse post, mas estou a bastante tempo pesquisando e até agora não achei nenhuma resposta descente. Como faço para jogar valores de variáveis de sensores, para uma pagina HTML que esta sendo lida de dentro do cartão SD(index.htm)? obs: estou usando o shield ethernet.

      Excluir
  10. Bom dia Fabiano/Rodrigo,

    Ainda estou com o probleminha do login, ja fiz a alteração da função validar o usuario, quanto a alteração da função base64_encode não sei como editá-la, poderia me ajudar com o código?

    ResponderExcluir
  11. Boa tarde! O meu problema é : entro com senha e login, mas ele entra em uma tela branca, poderia me ajudar ?

    ResponderExcluir
  12. Ola boa tarde!
    Fabiano eu estou usando a placa Mega 2560 com Eth Shield e não estou tendo sucesso em rodar este seu escript. Vi que no codigo você usa os pinos 4 e 10 do arduino UNO para habilitar/desabiltar o cartão SD e a ETH. Me pareceu que no Mega 2560 o pino 53 tem a mesma função do pino 4 do UNO, mas o pino 10, não consigo encontrar equivalente. Tambem não sei se só seria este dois os pontos. Gravei os arquivos no SD e no PC estão funcionando como esperado, porem no Arduino não passam do Login, rejeitando o usuario e senha admin:admin.. Vc pode me ajudar?? Obrigado

    ResponderExcluir
  13. Galera, consegui achar a função que transforma o login_senha para base64.
    Primeiro: Substituam a função validar_usuario exatamente como o Rodrigo postou.
    Segundo: Tirem toda aquela parte entre /**** BASE 64 ****/ e /**** FIM DA BASE64 ****/
    Terceiro: Coloquem o codigo abaixo nesse lugar. PS: obrigado ao Fabiano por postar esse código para nós!!!

    static const char b64all[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"
    "ghijklmnopqrstuvwxyz0123456789+/";

    const char *base64_encode(const char *original, int length) {
    // Se o tamanho não for informado, consideramos uma string bem
    // formada
    if (length == 0)
    length = strlen(original);

    // Inteiro com o tamanho do código a ser gerado
    int b64length = ((length + 2) / 3) * 4 + 1;

    // Contadores para percorrer as strings
    int i=0, j=0;

    // Alocando memória para o código
    char *b64 = (char *) malloc(sizeof(char) * b64length);
    memset(b64, 0, b64length);

    while (i < length) {
    // Codifica um grupo de três bytes...
    _encode(
    (uint8_t *) b64 + j,
    (const uint8_t *) original + i,
    (length - i)
    );

    // E segue para o próximo grupo
    i += 3;
    j += 4;
    }

    // Retorna o código
    return (const char *) b64;
    }

    void _encode(uint8_t *dest, const uint8_t *src, int len) {
    // Menor que 1, nada a fazer
    if (len < 1)
    return;

    // Dados a serem retornados
    int aux[] = { 0, 0, 0, 0 };

    // Primeiro elemento: os 6 bits mais significativos do primeiro
    // byte
    aux[0] = src[0] >> 2;

    // Segundo elemento: os 2 bits menos significativos do primeiro e
    // os quatro bits mais significativos do segundo byte
    aux[1] = (src[0] & 0x03) << 4;

    if (len > 1) {
    // SE houver um segundo...
    aux [1] |= (src[1] & 0xf0) >> 4;

    // Terceiro elemento: os quatro bits menos significativos do
    // segundo e os dois mais significativos do terceiro byte
    aux [2] = (src[1] & 0x0f) << 2;

    if (len > 2) {
    // Se houver um terceiro...
    aux[2] |= src[2] >> 6;

    // Quarto elemento: os seis bits menos significatos do
    // terceiro byte
    aux[3] = src[2] & 0x3f;
    }
    }

    // Codifica agora os valores numéricos para string
    dest[0] = b64all[aux[0]];
    dest[1] = b64all[aux[1]];
    dest[2] = '=';
    dest[3] = '=';
    if (len > 1) {
    dest[2] = b64all[aux[2]];
    if (len > 2)
    dest[3] = b64all[aux[3]];
    }
    }

    ResponderExcluir
    Respostas
    1. aqui pra mim mesmo seguindo isso ainda da errado

      Excluir
    2. Pra mim funcionou! Muito obrigado a todos que colaboraram!

      Excluir
  14. why i cant use admin admin for enter ?

    ResponderExcluir
  15. Este comentário foi removido pelo autor.

    ResponderExcluir
    Respostas
    1. Fabiano este Código fonte que mandei em partes tem com você unir com este seu código fonte.
      Ficaria uma ótima automação, por hora eu agradeço.
      o site que eu achei foi este (http://startingelectronics.org/articles/arduino/switch-and-web-page-button-LED-control/)

      Excluir
  16. #include
    #include
    #include
    // size of buffer used to capture HTTP requests
    #define REQ_BUF_SZ 60

    // MAC address from Ethernet shield sticker under board
    byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
    IPAddress ip(192, 168, 1, 102); // IP address, may need to change depending on network
    EthernetServer server(8081); // create a server at port 80
    File webFile; // the web page file on the SD card
    char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
    char req_index = 0; // index into HTTP_req buffer
    boolean LED_state[2] = {0}; // stores the states of the LEDs

    void setup()
    {
    // disable Ethernet chip
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);

    Serial.begin(9600); // for debugging

    // initialize SD card
    Serial.println("Initializing SD card...");
    if (!SD.begin(4)) {
    Serial.println("ERROR - SD card initialization failed!");
    return; // init failed
    }
    Serial.println("SUCCESS - SD card initialized.");
    // check for index.htm file
    if (!SD.exists("index.htm")) {
    Serial.println("ERROR - Can't find index.htm file!");
    return; // can't find index file
    }
    Serial.println("SUCCESS - Found index.htm file.");
    // switches
    pinMode(2, INPUT);
    pinMode(3, INPUT);
    // LEDs

    pinMode(30, OUTPUT);
    pinMode(31, OUTPUT);

    Ethernet.begin(mac, ip); // initialize Ethernet device
    server.begin(); // start to listen for clients
    }

    ResponderExcluir
  17. void loop()
    {
    EthernetClient client = server.available(); // try to get client

    if (client) { // got client?
    boolean currentLineIsBlank = true;
    while (client.connected()) {
    if (client.available()) { // client data available to read
    char c = client.read(); // read 1 byte (character) from client
    // limit the size of the stored received HTTP request
    // buffer first part of HTTP request in HTTP_req array (string)
    // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
    if (req_index < (REQ_BUF_SZ - 1)) {
    HTTP_req[req_index] = c; // save HTTP request character
    req_index++;
    }
    // last line of client request is blank and ends with \n
    // respond to client only after last line received
    if (c == '\n' && currentLineIsBlank) {
    // send a standard http response header
    client.println("HTTP/1.1 200 OK");
    // remainder of header follows below, depending on if
    // web page or XML page is requested
    // Ajax request - send XML file
    if (StrContains(HTTP_req, "ajax_inputs")) {
    // send rest of HTTP header
    client.println("Content-Type: text/xml");
    client.println("Connection: keep-alive");
    client.println();
    SetLEDs();
    // send XML file containing input states
    XML_response(client);
    }
    else { // web page request
    // send rest of HTTP header
    client.println("Content-Type: text/html");
    client.println("Connection: keep-alive");
    client.println();
    // send web page
    webFile = SD.open("index.htm"); // open web page file
    if (webFile) {
    while(webFile.available()) {
    client.write(webFile.read()); // send web page to client
    }
    webFile.close();
    }
    }
    // display received HTTP request on serial port
    Serial.print(HTTP_req);
    // reset buffer index and all buffer elements to 0
    req_index = 0;
    StrClear(HTTP_req, REQ_BUF_SZ);
    break;
    }
    // every line of text received from the client ends with \r\n
    if (c == '\n') {
    // last character on line of received text
    // starting new line with next character read
    currentLineIsBlank = true;
    }
    else if (c != '\r') {
    // a text character was received from client
    currentLineIsBlank = false;
    }
    } // end if (client.available())
    } // end while (client.connected())
    delay(1); // give the web browser time to receive the data
    client.stop(); // close the connection
    } // end if (client)

    // read buttons and debounce
    ButtonDebounce();
    }

    ResponderExcluir
  18. void ButtonDebounce(void)
    {
    static byte buttonState[2] = {LOW, LOW}; // the current reading from the input pin
    static byte lastButtonState[2] = {LOW, LOW}; // the previous reading from the input pin

    // the following variables are long's because the time, measured in miliseconds,
    // will quickly become a bigger number than can be stored in an int.
    static long lastDebounceTime[2] = {0}; // the last time the output pin was toggled
    long debounceDelay = 50; // the debounce time; increase if the output flickers

    byte reading[2];

    reading[0] = digitalRead(2);
    reading[1] = digitalRead(3);

    for (int i = 0; i < 2; i++) {
    if (reading[i] != lastButtonState[i]) {
    // reset the debouncing timer
    lastDebounceTime[i] = millis();
    }

    if ((millis() - lastDebounceTime[i]) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading[i] != buttonState[i]) {
    buttonState[i] = reading[i];

    // only toggle the LED if the new button state is HIGH
    if (buttonState[i] == HIGH) {
    LED_state[i] = !LED_state[i];
    }
    }
    }
    } // end for() loop

    // set the LEDs
    digitalWrite(30, LED_state[0]);
    digitalWrite(31, LED_state[1]);

    // save the reading. Next time through the loop,
    // it'll be the lastButtonState:
    lastButtonState[0] = reading[0];
    lastButtonState[1] = reading[1];
    }

    // checks if received HTTP request is switching on/off LEDs
    // also saves the state of the LEDs
    void SetLEDs(void)
    {
    // LED 1 (pin 6)
    if (StrContains(HTTP_req, "LED1=1")) {
    LED_state[0] = 1; // save LED state
    digitalWrite(30, HIGH);
    }
    else if (StrContains(HTTP_req, "LED1=0")) {
    LED_state[0] = 0; // save LED state
    digitalWrite(30, LOW);
    }
    // LED 2 (pin 7)
    if (StrContains(HTTP_req, "LED2=1")) {
    LED_state[1] = 1; // save LED state
    digitalWrite(31, HIGH);
    }
    else if (StrContains(HTTP_req, "LED2=0")) {
    LED_state[1] = 0; // save LED state
    digitalWrite(31, LOW);
    }
    }

    // send the XML file with analog values, switch status
    // and LED status
    void XML_response(EthernetClient cl)
    {
    int analog_val; // stores value read from analog inputs
    int count; // used by 'for' loops
    int sw_arr[] = {2, 3}; // pins interfaced to switches

    cl.print("");
    cl.print("");
    // LED1
    cl.print("");
    if (LED_state[0]) {
    cl.print("on");
    }
    else {
    cl.print("of");
    }
    cl.println("");
    // LED2
    cl.print("");
    if (LED_state[1]) {
    cl.print("on");
    }
    else {
    cl.print("of");
    }
    cl.println("");
    cl.print("");
    }

    // sets every element of str to 0 (clears array)
    void StrClear(char *str, char length)
    {
    for (int i = 0; i < length; i++) {
    str[i] = 0;
    }
    }

    // searches for the string sfind in the string str
    // returns 1 if string found
    // returns 0 if string not found
    char StrContains(char *str, char *sfind)
    {
    char found = 0;
    char index = 0;
    char len;

    len = strlen(str);

    if (strlen(sfind) > len) {
    return 0;
    }
    while (index < len) {
    if (str[index] == sfind[found]) {
    found++;
    if (strlen(sfind) == found) {
    return 1;
    }
    }
    else {
    found = 0;
    }
    index++;
    }

    return 0;
    }

    ResponderExcluir
  19. Olá bom dia a todos. Estou com um problema em meu codigo, ele funciona perfeitamente, porem ele demora cerca de 10 segundos para responder (passar valores do site para o arduino). Eu simplesmente não sei como resolver isso, alguem poderia me ajudar? Muito obrigado!
    email: jonashenrique989@gmail.com

    ResponderExcluir
  20. Fiz conforme o Caio Queiroz orientou no comentário, e funcionou perfeitamente.
    Obrigado a todos!!!!

    ResponderExcluir
  21. fabiano estou tentando colocar mais esta linha neste sketch, mas so da este erro exit status 1
    redefinition of 'void jpg_file(EthernetClient&, char*)' como posso fazer para resolver isto?

    Linha De Programação
    void jpg_file(EthernetClient &client, char * trip){
    client.println(F("HTTP/1.1 200 OK\n"
    "Content-Type: file/jpg\n"
    "Connection: close\n"));

    write_from_file(client, trip);
    }

    ResponderExcluir
  22. Boa noite Fabiano, gostaria de solicitar a sua ajuda. Sou novo na programação html. Estou tentando passar os dados de uma leitura analógica para o web server e depois coletar com o Node-red, para montar um gráfico. O meu problema está no código html no Arduino. Ao fazer a programação e testar, eu não estou conseguindo passar os valores da leitura como números, e sim como string. Daí não consigo tratar esses dados no Node-red. Você saberia como ajudar?

    Obrigado desde já.

    ResponderExcluir