domingo, 29 de julho de 2012

Arduino com Ethernet Shield lendo Twitter

Hoje surgiu a oportunidade de utilizar o Ethernet Shield com chip Wiznet W5100 e slot de cartão SD que comprei no dealextreme:
Esse shield em particular te abre uma gama muito grande de projetos, te da a liberdade de acessar a internet e utilizar o cartão SD dele para fazer logs e tudo mais, não vou entrar muito nos detalhes dele, num post futuro quem sabe. No Brasil esse mesmo shield chega a custar entre 250-350 reais, então vale a pena esperar 1 mês e receber da China com preço de 17 USD.

Eu comprei ele mas nunca fiz muitos testes, mas hoje apareceu uma ideia que pode ser muito útil.É o seguinte, eu acesso um computador remotamente para fazer algumas atualizações, esse computador fica ligado 24/7, nunca é desligado.Como nenhum sistema é perfeito, é comum o computador travar e eu perder o acesso remotamente, impossibilitando de executar as ações já que o LogMeIn não consegue ligar ele a distancia.
Hoje esse computador travou, e a única solução até então é ir pessoalmente e reiniciar ele, foi ai que eu tive a ideia de utilizar o Arduino+Ethernet+Twitter.

O Ethenet shield acessa a internet,mais precisamente o servidor do twitter e a minha conta e faz a leitura da ultima coisa que eu postei, depois de fazer essa leitura, o Arduino checa se ela se encaixa em alguma ação pre determinada nele. Essa faixa de código determina isso:

Foi feito um exemplo com um LED, que pode ser substituído por um relé ou qualquer outro componente para controlar qualquer tipo de carga remotamente.
Sendo assim você pode ligar e desligar o comutador, cortando a energia dele, ou internamente conectando ao botão de reset.
O programa esta muito bem comentado, e fácil de compreender, o tempo de refrescamento esta em 20000 milissegundos, ou seja, 20 segundos, e pode ser alterado para ter resposta mais rápido, mas achei melhor deixar 20 segundos para não sobrecarregar.



Código Completo:

/*
  Twitter Client

 Esse sketch conecta ao Twitter usando um Ethernet shield. Ele vasculha o XML
 retornado, e procura por <text>esse é um tweet</text>

 Circuito:
 * Ethernet shield ligado nos pinos 10, 11, 12, 13

por Vinicius R.
VRO Projetos
viniciusro@gmail.com

 Esse codigo é de dominio publico.

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

const int led = 7;
// entre com MAC e IP para seu controlador.
// O IP vai depender da sua rede:
byte mac[] = {0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x01};
IPAddress ip(192,168,1,20);

// inicia a biblioteca:
EthernetClient client;

const unsigned long requestInterval = 20000;  // delay entre pedidos

char serverName[] = "api.twitter.com";  // pagina do twitter URL

boolean requested;                   // se vc fez um pedido des de quando conectou
unsigned long lastAttemptTime = 0;            // ultima vez que vc estava conectado em milesegundos

String currentLine = "";            // string para guardar texto de servidor
String tweet = "";                  // string para guardar o tweet
boolean readingTweet = false;       // se vc está atualmente lendo o tweet

void setup() 
{
  pinMode(led, OUTPUT);
  // reserva espaço para as strings:
  currentLine.reserve(256);
  tweet.reserve(150);

 // abre comunicação serial e espera a porta abrir:
  Serial.begin(9600);

  // tenta conexão DHCP:
  Serial.println("Tentando pegar um IP usando DHCP:");
  if (!Ethernet.begin(mac)) 
  {
    // se o  DHCP falhar, começa tentar manualmente:
    Serial.println("não foi possivel pegar um IP usando DHCP, tentando manualmente");
    Ethernet.begin(mac, ip);
  }
  Serial.print("Meu IP:");
  Serial.println(Ethernet.localIP());
  // Conecta no Twitter:
  connectToServer();
}

void loop()
{
  if (client.connected()) 
  {
    if (client.available()) 
    {
      // ler os bytes de entrada:
      char inChar = client.read();

      // adiciona os bytes de entrada ao final da linha:
      currentLine += inChar; 

      // se vc receber "newline" nova linha, limpa a linha:
      if (inChar == '\n') 
      {
        currentLine = "";
      } 
      // se a linha atual terminar com <text>, vai ser seguida do tweet:
      if ( currentLine.endsWith("<text>")) 
      {
        // o tweet esta começando. Limpa a string tweet:
        readingTweet = true; 
        tweet = "";
      }
      // se vc esta atualmente lendo os bytes do tweet, adicona eles a String do tweet,
      if (readingTweet) 
      {
        if (inChar != '<') 
        {
          tweet += inChar;
        } 
        else 
          {
          // se vc receber um caracter "<", chegou ao final do tweet:
          readingTweet = false;
          Serial.println(tweet);
            if(tweet==">.215 ligado")
             {
              digitalWrite(led, HIGH);
              Serial.println("Computador .215 LIGADO");
             }   
            if(tweet==">.215 desligado")
             {
              digitalWrite(led, LOW);
              Serial.println("Computador .215 DESLIGADO");
             }   
            if(tweet==">status")
             {
              Serial.print("Computador .215 esta: ");
              int estado = digitalRead(led);
              if (estado==1)
                {
                 Serial.print("Ligado ");
                }
              if (estado==0)
                {
                 Serial.print("Desligado ");
                }
              Serial.println(estado);
             }
          // fecha conexão com servidor:
          client.stop(); 
        }
      }
    }   
  }
  else if (millis() - lastAttemptTime > requestInterval) 
  {
    // se vc não esta conectado, e passou 2 minutos des da sua ultima conexão
    // então tenta reconectar:
    connectToServer();
  }
}

void connectToServer() 
{
  // tenta conectar e espera em milesegundos:
  Serial.println("conectando no servidor...");
  if (client.connect(serverName, 80)) 
  {
    Serial.println("fazendo pedido de HTTP...");
    // faz pedido HTTP GET para o twitter:
    client.println("GET /1/statuses/user_timeline.xml?screen_name=viniciusrdo&count=1 HTTP/1.1");
    client.println("HOST: api.twitter.com");
    client.println();
  }
  // observa o tempo dessa tentativa de conexão:
  lastAttemptTime = millis();
}


Esse vídeo exemplifica seu funcionamento:




18 comentários:

  1. Vinícius, parabéns pelo projeto e pela iniciativa! Muito legal mesmo!!! Como você mesmo disse, a gama de possibilidades para utilização é enorme. Agora é pensar em uma forma de colocarmos em prática na RemOpt!

    ResponderExcluir
  2. Valeu Paulo!
    Agora é pensar se é viável ou não de implementar isso, e a melhor forma de fazer com segurança.

    ResponderExcluir
  3. Vinicius ótima idéia, uma dúvida, quando eu envio um twitter com a palavra status o mesmo imprime o status na serial somente, terria como imprimir no twitter para poder visualizar a distância?
    Obrigado

    ResponderExcluir
    Respostas
    1. Olá Adriano, legal que vc gostou do projeto.

      Essa na realidade foi uma das primeiras versões dele, hoje ele já esta 100% implementado e sofreu varias modificação para o código rodar sem problemas, foram implementadas varias correções de erros.

      Sobre o twitte "status", hoje ele funciona assim, tem opção de receber um SMS nos celulares cadastrados e/ou receber a resposta no próprio twitter e/ou na porta serial onde é salvo em um cartão de memoria e em um documento .txt no computador.

      Em breve vou postar a versão mais recente do código.

      Att

      Excluir
  4. Bom dia Vinicius, se fosse possivel publicar a versão mais recente do projeto eu ficaria muito agradecido pois preciso apresentar esse projeto no meu trabalho até sexta e vou precisar adequar ele para a minha realidade. Eu consegui montar um projeto que publica no twitter e outro parecido com o seu, que lê e executa os comandos mas não consegui integrar os dois.
    Obrigado pela atenção,
    abraço.

    ResponderExcluir
    Respostas
    1. Andre da uma olhada nesse post, talvez possa te ajudar:

      http://microembarcado.blogspot.com.br/2012/08/reiniciando-computador-remotamente.html

      Estou organizando o outro projeto aqui para publicar.

      Excluir
  5. Olá vinicius, eu montei um projeto que publica mensagens no twitter mas somente mensagem de texto entre aspas e eu gostaria de publicar uma variavel de uma entrada analógica, pelo que eu entendi tenho que converter a variavel int para char, mas não estou conseguindo, teria como e ajudar.

    Abraço.

    ResponderExcluir
    Respostas
    1. Oi Andre,

      Não necessariamente vc tem que fazer essa conversão, fica um pouco dificil te falar assim sem ver o codigo, vc tentou enviar o twitter usando o valor da leitura analogica? deu algum problema na hora de compilar no arduino dizendo que a conversão estava errada?
      Me parece simples de arrumar, vamos trocando ideia que resolvemos isso.


      abraço

      Excluir
  6. Este é o erro, se eu tentar publicar um CHAR vai mas INT ou Float não, tentei postar o código mas passa de 4000 caracter e dai não dá, se precisar ver o código me manda o teu email pra eu enviar.

    _07_03_2013:251: error: no matching function for call to 'Twitter::post(float&)'

    ResponderExcluir
    Respostas
    1. tente converter, exemplo:

      char buff[16];
      float val =14.7;
      dtostrf(val, 10, 3, buff);


      o valor de buff agora é: " 14.700".

      qualquer coisa me envia o código completo em viniciusro,gmail.com

      Excluir
    2. Outro exemplo:
      float temperatura;
      char temp_aux[10];
      String tempParaString;

      dtostrf(temperatura,2,2,temp_aux);
      tempParaString = String(temp_aux);

      Assim vc deve postar tempParaString, que vai dar certo

      Excluir
  7. Olá Vinicius tentei esta alternativa mas continua com erro, este é o erro error: no matching function for call to 'Twitter::post(String&)'

    ResponderExcluir
  8. Funcionou, postei temp_aux dai deu certo, obrigado pela força.

    ResponderExcluir
  9. Boa tarde Vinicius, gostaria de uma forcinha tua, de novo hehehe, fiz o projeto em que o arduino escrevia mensagens no meu twitter e lia comandos escritos lá, bem como o teu projeto acima, mas em abril queimou ao meu ethernet shield e agora comprei outro mas ele não lê as mensagens, somente consegue escrever, tentei com vários exemplos, inclusive com o seu mas não rolou, será que é defeito no shield?

    Obigado

    ResponderExcluir
    Respostas
    1. Olá Andre, eu fiz um teste aqui, acessei a pagina XML onde o arduino busca os dados do twitter:

      http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=remopte&count=1

      E obtive o seguinte resultado:


      The Twitter REST API v1 is no longer active. Please migrate to API v1.1. https://dev.twitter.com/docs/api/1.1/overview.


      Ou seja... o API mudou de versão para 1.1, a forma GET modificou, talvez isso possa tw ajudar: https://dev.twitter.com/discussions/15078

      assim que possível vou dar uma olhada tb.

      Excluir
  10. Valeu pela dica, fiz varias tentativas mas não rolou.

    ResponderExcluir