sábado, 19 de outubro de 2013

Web Cliente com Arduino, ENC28J60 e PHP


Nível de complexidade: Mediano. Necessário prévio conhecimento sobre Arduino, redes de computadores e programação em PHP.

Uma  funcionalidade muito interessante para o Arduino é a conexão com a rede local ou com a Internet. Isso pode ser realizado de forma relativamente simples com a ajuda do Ethernet Shield oficial, com o chip W5100 e sua respectiva biblioteca "ethernet" presente no Arduino 1.5.4.


No entanto, esta não é a única forma. Neste exemplo vou utilizar o Arduino UNO e um adaptador ethernet ENC28J60 que custa 1/3 do valor da Ethernet Shield oficial, em um exemplo que transmite os dados de um sensor qualquer para um site em PHP na internet ,no meu caso ivair.orgfree.com


Conexões:

A comunicação entre o Arduino e o ENC28J60 utiliza o protocolo SPI e os pinos devem ser conectados da seguinte forma:
  ARDUINO     ENC28J60  
GND
GND
3.3V
VCC
Pino 2
INT
Pino 10
CS
Pino 11
SI
Pino 12
SO
Pino 13
SCK

Um sensor deve ser conectado a entrada A0 do arduino UNO, caso utilize um potenciômetro conecte o terminal central a porta A0 e os terminais laterais um ao positivo e o outro ao negativo.

Código Arduino UNO:

    No início do código é definido um MAC para o adaptador ENC28J60, bem como são declaradas as demais variáveis utilizadas pelo programa. Neste exemplo o site PHP "ivair.orgfree.com" receberá e apresentará os dados enviados pelo arduino. O código do site está também logo abaixo.

Função Setup():
    O ENC28J60  deve estar conectado a um roteador com DHCP ativado para que possa ser configurado automaticamente (ether.dhcpSetup()) o número IP, a máscara, o gateway e o servidor DNS.
    Imediatamente após a gravação abra o monitor serial e será possível observar os resultados da configuração,  ou mensagens de erros,  caso algo esteja errado. Se tudo correr bem o site responde com um "OK" para cada valor recebido e armazenado na base de dados.


A função Loop():
    Esta função envia por GET o valor do sensor conectado a entrada analógica A0. Por exemplo: caso o valor obtido do sensor seja 356, é gerada a seguinte string: "http://ivair.orgfree.com/inserir.php?val=356" que é enviada pela função: ether.browseUrl().
   Isso pode ser testado digitando-se essa string diretamente no navegador. Após o recebimento,  o site em PHP responde com a sequência de texto padrão do protocolo e a palavra "OK", que é tratado pela função my_callback() e apresentado no monitor serial. Para visualizar a mensagem de retorno completa retire o comentário da segunda linha e comente a terceira.

   A biblioteca utilizada é a EtherCard desenvolvida por Jean Claude Wippler. Após descompactá-la na pasta libraries, crie um novo sketch com o código a seguir.

#include <EtherCard.h>
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[700];
static uint32_t timer;
char website[] PROGMEM = "ivair.orgfree.com";
char temp_sensor[150];
int an0 = A0;
int sensor = 0;

static void my_callback (byte status, word off, word len)
{
   Ethernet::buffer[off+len] = 0;    //mensagem do retorno do servidor
   //Serial.print((const char*) Ethernet::buffer + off);  //mostra todo o retorno
   Serial.print((const char*) Ethernet::buffer + off + 157); //mostra somente ok
}

void setup ()
{
  delay(1000);
  Serial.begin(57600);
  Serial.println("Obtendo IP:");
  if (ether.begin(sizeof Ethernet::buffer, mymac,10) == 0)
    Serial.println( "Falha ao acessar o controlador Ethernet");
  if (!ether.dhcpSetup())
    Serial.println( "Falha ao obter o IP");
  ether.printIp("IP: ", ether.myip);
  ether.printIp("Mascara: ", ether.mymask);
  ether.printIp("Gatway: ", ether.gwip);
  ether.printIp("Sevidor DNS: ", ether.dnsip);
  if (!ether.dnsLookup(website))     //IP do servidor por DNS
    Serial.println("Falha no DNS");
  //ether.parseIp(ether.hisip, "144.76.99.221"); //IP do servidor manual
  ether.printIp("Servidor: ", ether.hisip);
  Serial.println(" ");
}

void loop ()
{
  ether.packetLoop(ether.packetReceive());
  if (millis() > timer)
  {
    timer = millis() + 5000;
    ether.persistTcpConnection(true);
    sensor = analogRead(an0);
    sprintf(temp_sensor, "?val=%d", sensor);
    ether.browseUrl(PSTR("/inserir.php"), temp_sensor, website, my_callback);
  }
}

Código do site PHP:

O site obrigatoriamente deve estar na Internet, não consegui fazê-lo rodar em um servidor local.
   No provedor PHP crie uma base de dados no seguinte formato:
        Tabela: leituras
        Campos: cod(int auto incremento, chave primária), valor(int) e data (datahora).
   O sistema todo é extremamente simples e constituído por três páginas: 
         index.php - Gera e apresenta uma tabela com os dados armazenados na base.
         apagar.php - Limpa a base de dados.
         inserir.php - Insere o valor recebido por GET na base de dados

   Observe que todas fazem a conexão com os seguintes dados: ("localhost","login","senha","base_de dados"), O primeiro item é o nome do servidor e é definido pelo provedor da página, no meu caso o provedor indicou que utilizasse a palavra "localhost", em outros o nome pode mudar.
O segundo e terceiro itens são o login  e a senha escolhidos no momento do cadastro da conta.
O quarto item é o nome da base de dados, que muitas vezes é o próprio login. Faça uma busca no google por "free php host" que você achará alguns gratuítos

Página index.php
<html>
<head>
<meta http-equiv="refresh" content="10">
  <title>Arduino</title>
</head>
<body bgcolor="Lightsteelblue">
<table align="center" border="0" width="20%">
<tr><td align="center">
  <form method="POST" action="apagar.php">
    <input type="submit" value="Apagar">
  </form>
</td></tr>
</table>
<table align="center" border="1" width="20%">
  <tr><th>Sensor</th><th>Data - Hora</th></tr>
  <?php
    $con = mysqli_connect("localhost","login","senha","base_de dados") or die("Falha na conexao com o MySQL");
    $res = mysqli_query($con,"SELECT * FROM leituras") or die ("Nao foi possivel realizar a consulta");
    while($linha = mysqli_fetch_array($res))
    {
     echo "<tr><td align='center'>".$linha['valor']."</td>";
     echo "<td align='center'>".$linha['data']."</td></tr>";
    }
    mysqli_close($con);
  ?>
</table>
</body>
</html>

Página apagar.php
<?php
  $con = mysqli_connect("localhost","login","senha","base_de dados") or die("Falha na conexao com o MySQL");
  mysqli_query($con,"DELETE FROM leituras WHERE cod") or die ("Falha ao apagar os dados");
  mysqli_close($con);
  header("Location:index.php");
  exit(0);
?>

Página inserir.php
<?php
  date_default_timezone_set('America/Sao_Paulo');
  if (!empty($_GET['val']))
  {
    $valor = $_GET['val'];
    $data = date("d/m/Y H:i:s");
    $con = mysqli_connect("localhost","login","senha","base_de dados") or die("Falha na conexao com o MySQL");
    mysqli_query($con,"INSERT INTO leituras VALUES ('','$valor','$data')") or die ("Falha ao inserir os dados");
    mysqli_close($con);
    echo "ok  ";     //resposta em caso de sucesso
  }
  else
    echo "falha";   //resposta em caso de falha
?>

Boa sorte.

Ivair.