Publicidade:

quarta-feira, 25 de fevereiro de 2015

Arduino - Autenticação HTTP de Usuário e Senha - Ethernet Shield

Por mais simples que uma aplicação com Ethernet Shield seja, ter um login pra autenticar o usuário pode ser uma boa. Mas nem sempre pode-se contar com uma base de dados de usuário ou algo mais elaborado.


Uma solução simples, é utilizar o próprio browser pra solicitar usuário e senha.



código fonte:



/*
 Web Server - HTTP Autentication
 Baseado na versão de exemplo do Arduino.
 
 ATENÇÃO: esse código é apenas para exemplo e não deve ser encarado como solução 
 completa para segurança de informações de qualquer aplicação.
 
 modified 25 feb 2015
 by Fabiano A. Arndt (fabianoallex)
*/
/*
 descrição Original:
 
 Web Server

 A simple web server that shows the value of the analog input pins.
 using an Arduino Wiznet Ethernet shield.

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)

 created 18 Dec 2009
 by David A. Mellis
 
 modified 9 Apr 2012
 by Tom Igoe
 
*/

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

#include <SPI.h>
#include <Ethernet.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";
  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********************************
***********************************************************************************/

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

void iniciar_ethernet(){
  byte ip[4]      = {192,168,200,188};
  //byte gateway[4] = {192,168,1,1};
  //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
  Ethernet.begin(mac, ip);
  server->begin();
}

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){
  client.println(F("HTTP/1.1 200 OK\n"
                   "Content-Type: text/html\n"
                   "Connection: keep-alive\n\n"
                   "<!DOCTYPE HTML>"
                   "<html>"));

  for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
    int sensorReading = analogRead(analogChannel);
    client.print(F("analog input "));
    client.print(analogChannel);
    client.print(F(" is "));
    client.print(sensorReading);
    client.println(F("<br>"));
  }
  client.println(F("</html>"));
}

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 conteudo           = 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) {
          autenticado ? html_autenticado(client) : html_autenticar(client);
          break;
        }
        if (c == '\n') { 
          currentLineIsBlank = true;               
          
          if (strstr(linebuf, "Authorization: Basic")>0 ) { if ( validar_usuario(linebuf) )   {  autenticado = 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);           // give the web browser time to receive the data
    client.stop();      // close the connection:
  }
}
/**********************************************************************************
**************************************** 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_ethernet();
}

void loop() {
  exec_ethernet();
}

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

quinta-feira, 12 de fevereiro de 2015

Motor do Limpador do Parabrisa do Uno - Wiper Motor

Funcionamento básico do motor do limpador do parabrisa do uno. Em breve postarei outros vídeos mostrando como usá-lo com o Arduino. Inscreva-se e acompanhe. :)




quinta-feira, 15 de janeiro de 2015

Arduino - Vários botões no mesmo pino + OO

Algum tempo atrás fiz um vídeo mostrando como ligar vários botões no mesmo pino, utilizando as portas analógicas.

Hoje estou postando um vídeo novo, onde dei uma boa melhorada no código, onde implemento uma classe que facilita o uso desse tipo de solução.






vídeo anterior:




código atualizado:



class BotaoSerialAnalogico{
  private:
    int  _pino;
    int  _quantidade;
    int* _ref_botao;              
  public:
    BotaoSerialAnalogico(int pino, int quantidade, int resistores[], int resistor_gnd){
      _ref_botao = new int[quantidade];
      _pino          = pino;
      _quantidade    = quantidade;
      
      float r_eq = 0;
      for(int i=0;i<_quantidade;i++){
        r_eq += resistores[i];
        _ref_botao[i] = 1023 - ( r_eq*1023 / (resistor_gnd + r_eq) ); 
      }
      
      int anterior;
      for(int i=0;i<_quantidade;i++){
        int temp = _ref_botao[i];
        _ref_botao[i] = (i==0 ? 1024 : ( anterior + temp ) / 2);
       
        anterior = temp;
      }
    }
  
  int get_button(){
    int v = analogRead(_pino);
    if (v == 0) return -1; //nenhum botao pressionado
    int b = 0;
    for(int i=0;i<_quantidade;i++){ if (_ref_botao[i] > v) { b=i; } else { break; } }
    return b;
  }
  
  void print(){
    Serial.print("|");
    for(int i=0;i<_quantidade;i++){
      Serial.print(_ref_botao[i]);
      Serial.print("|");
    }
    Serial.print("analog=");
    Serial.print(analogRead(_pino));
    Serial.print("|b=");
    Serial.println(get_button());
  }
};



BotaoSerialAnalogico *b;

int RESISTORES[] = {0, 1500, 1500, 2700, 4700};   //resistores dos botões

void setup() {
  Serial.begin(9600);
  
  b  = new BotaoSerialAnalogico(A0, 5, RESISTORES, 1000); //1000-> 1K -> resistor ligado entre o gnd e o pino analógico
}

void loop() {
  
  int botao = b->get_button();
  
  if (botao >= 0) {
    b->print();
    delay(200);
  }
  
  if (botao == 0){}  //programar botao 01
  if (botao == 1){}  //programar botao 02
  if (botao == 2){}  //programar botao 03
  if (botao == 3){}  //programar botao 04
  if (botao == 4){}  //programar botao 05
  
}

quarta-feira, 7 de janeiro de 2015

Arduino - Expansão dinâmica de portas


Vaja como fazer para o Arduino identificar a quantidade de expansores (74hc595, max7219, etc) conectados em série. veja o vídeo.






vídeo anterior sobre o 74HC595:
http://youtu.be/SwQECcYdEkI

Link para o artigo:
http://www.arduinoecia.com.br/2014/04/Painel-de-led-max7219.html


código:



int conta_modulos(int pino, float Rb, float Rp){
  float La = analogRead(pino);
  double N = ( 1 / (  ((1023*Rb)/La) - Rb ) )  / ( 1 / Rp );
  int n = round(N);
    
  Serial.print(N);
  Serial.print(" arredondado: ");
  Serial.println(n);
  
  return n;
}

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

void loop() {
  int q1 = conta_modulos(A0, 1000, 10000);  //resistor gnd->1K, resistor paralelo 10k
  delay(1000);
}