viernes, 5 de junio de 2015

Estación Metorológica y enviando datos a web esde arduino + Shield Ethernet (internet de las cosas)

Estación Meteorológica – Capturando Temperatura, Humedad y Luminosidad en MySQL usando Apache, php, Arduino + Ethernet Shield

Uno de nuestros tutoriales mas comentados es Capturando datos en MySQL usando Apache, php, Arduino + Ethernet Shield. Por este motivo quise darle una actualización y al mismo tiempo responder con un ejemplo a muchas de las consultas que nos realizaron en ese tutorial, a continuación los pasos para implementar una estación meteorológica usando el sensor DHT11, un LDR, un Arduino y una Ethernet Shield.
arduino_ethernet_45grados
Este proyecto es similar al anterior, un Arduino Uno con una Ethernet Shield, pero esta vez agregué 2 variables mas, ahora mide temperatura, humedad y luminosidad; estos datos los envía al igual que antes mediante una instrucción GET a un servidor remoto y aquí algo nuevo, el servidor remoto responde en XML indicándole al Arduino cual de los tres leds que posee debe encender o apagar. Les parece interesante?

1. Materiales

  • Arduino Uno Release 3
  • Ethernet Shield
  • Sensor DHT11 o DHT22
  • LDR – Fotoresistencia
  • 3 Leds
  • 2 resistencias de 10K (Ppara los sensores)
  • 3 resistencias de 1k (Para los leds)
  • Cables de conexión
  • Protoboard
  • Servidor Web Apache / PHP / MySQL

2. Diagrama

El proyecto al tener mas componentes se ve un poco mas complejo, pero con observación y cuidado es fácil construir el prototipo en el protoboard.
Hay que tener cuidado con la polaridad de los LEDs y los 4 pines del sensor DHT11 (o DHT22 según sea el caso).
Otro punto importante a recordar es que Arduino usa los pines 10, 11, 12 y 13 (SPI) para comunicarse con la Ethernet Shield por lo cual no pueden ser utilizados como Entrada/Salida.
Arduino-EthernetShield-DHT11-LDR

3. Programación de Arduino

El sketch para Arduino esta basado en los que utilizamos en los tutoriales Midiendo Temperatura y Humedad con Arduino y el sensor DHT11 y  Capturando datos en MySQL usando Apache, php, Arduino + Ethernet Shield, este sketch es una fusion de ambos considerando eso si  que ahora agregamos un sensor mas y 3 leds. Recomiendo leer ambos tutoriales para entender mejor como trabaja este proyecto.
Esquema de Pines
Arduino Pin 2 : Pin 2 del Sensor DHTxx
Arduino Pin 5 : + Led 1
Arduino Pin 6 : + Led 2
Arduino Pin 7 : + Led 3
Arduino Pin A0:  - LDR
Arduino +5V   : + Protoboard
Arduino GRD   : - Protoboard
Las demas conexiones deben verse en el diagrama.
El sketch que pueden copiar y pegar en la interfaz de desarrollo para Arduino  es el siguiente:
// InternetDeLasCosas.cl
// Script que obtiene la temperatura y humedad desde un sensor DHTxx
// y envia estos datos a un servidor web.
// El servidor web procesa los datos y responde en xml indicando que
// Leds deben ser encendidos o apagados en el Arduino
//
// Escrito por @joniuz

#include <SPI.h>
#include <Ethernet.h>
// Libreria para Sensores DHT
#include "DHT.h"

#define DHTPIN 2     // Pin del Arduino al cual esta conectado el pin 2 del sensor

// Descomentar segun el tipo de sensor DHT usado
#define DHTTYPE DHT11   // DHT 11 
//#define DHTTYPE DHT22   // DHT 22  (AM2302)
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

// Inicializa el sensor DHTxx
DHT dht(DHTPIN, DHTTYPE);

// Configuracion de fotocelda
int fotocelda = 0;
int luminosidad;

// Configuracion Ethernet Shield
// Mac unica de cada EthernetShield
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x4E, 0xD7 };

// Direccion IP Fija en caso de que no pueda obtenerla por DHCP
IPAddress ip(172,17,17,217);

// Direccion del DSN en caso de que no pueda obtenerla por DHCP
//IPAddress myDns(172,17,17,1);

// Inicializa la instancia client
EthernetClient client;

// Direccion del servidor (cambiar por su direccion)
char server[] = "www.iot.cl";

// Ultima conexion al servidor medida en millisegundos
unsigned long ultimaConexion = 0;          
              
// Intervalo en milisegundos entre conexiones
const unsigned long intervaloConexion = 20000;   

// Leds conectados a Salidas Digitales
int led_1; // Umbral de temperatura
int led_2; // Umbral de humedad
int led_3; // Umbral de luminosidad

// Setup de Arduino
void setup() {
  
  // Configura salidas digitales para los Leds
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  
  // Inicializa puerto serial
  Serial.begin(9600);
  Serial.println("######### Internetdelascosas.cl #########");
  Serial.print("Sensor de temperatura-humedad DHT");
  Serial.print(DHTTYPE);
  Serial.println(" / web");
  Serial.println();
  
  // Espera 1 segundo para que se inicie la tarjeta Ethernet
  delay(1000);
  
  // Intenta inicializar la EthernetShield via DCHCP
  Serial.println("Iniciando EthernetShield via DHCP");
  if(!Ethernet.begin(mac)) {
    // Si el DHCP falla, inicia la EthernetShield con IP estatica
    Serial.println("Falla al obtener IP desde DHCP, iniciando con IP estatica");
    Ethernet.begin(mac, ip);
  }
  
  // Imprime la direccion IP de la tarjeta
  Serial.print("Direccion IP: ");
  Serial.println(Ethernet.localIP());
  Serial.println();
  
  // Inicializa Sensor DHTxx
  Serial.print("Iniciando Sensor DHT");
  Serial.println(DHTTYPE);
  Serial.println();
  dht.begin();
  // Espera dos segundos para dar tiempo al sensor mientras obtiene muestra
  delay(2000);
}
// Loop principal
void loop() {
  // Si hay conexion con el servidor
  if (client.connected()) {
    if (client.available()) {
      // Obtiene la respuesta del servidor y busca los tags xml <led_1> <led_2> y <led_3>
      if(client.find("<led_1>")) {
        led_1 = client.parseInt();
      }
      if(client.find("<led_2>")) {
        led_2 = client.parseInt();
      }
      if(client.find("<led_3>")) {
        led_3 = client.parseInt();
      }
      // Imprime valores enviados por servidor
      Serial.println("Valores enviados por servidor");
      Serial.print("Led 1: ");
      Serial.println(led_1);
      Serial.print("Led 2: ");
      Serial.println(led_2);
      Serial.print("Led 3: ");
      Serial.println(led_3);
      // Cierra conexion
      Serial.println("Cerrando conexion..."); 
      Serial.println();
      client.stop();
      // Enciende Leds segun valores
      if (led_1)
        digitalWrite(5, HIGH);
      else
        digitalWrite(5, LOW);
      if (led_2)
        digitalWrite(6, HIGH);
      else
        digitalWrite(6, LOW);
      if (led_3)
        digitalWrite(7, HIGH);
      else
        digitalWrite(7, LOW);
    }
  }
  else if(millis() - ultimaConexion > intervaloConexion) {
    httpRequest();
  }
}
// Fin del loop principal

// Funcion que realiza la conexion http al servidor y obtiene la respuesta
void httpRequest() {
  // Obtiene los datos del sensor DHTxx
  // Obtiene la Humedad
  float h = dht.readHumidity();
  // Obtiene la Temperatura en Celsius
  float t = dht.readTemperature();
  
  // Control de errores, valida que se obtuvieron valores para los datos medidos
  if (isnan(h) || isnan(t)) {
    Serial.println("Falla al leer el sensor DHTxx!");
    return;
  }
  
  Serial.print("Temperatura: ");
  Serial.println(t);
  Serial.print("Humedad: ");
  Serial.println(h);
  
  // Obtiene datos de la fotocelda
  luminosidad = analogRead(fotocelda);  
  
  Serial.print("Luminosidad = ");
  Serial.print(luminosidad);
  Serial.println();
  // Se conecta al servidor en el puerto 80 (web)
  if (client.connect(server, 80)) {
    // Envia el dato al puerto serial
    Serial.println("Iniciando conexion...");
    // Envia el requerimiento via GET
    client.print("GET /sensorarduino.php?id=joniuz&temperatura=");
    client.print(t);
    client.print("&humedad=");
    client.print(h);
    client.print("&luminosidad=");
    client.print(luminosidad);
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.println(server);
    client.println("User-Agent: Arduino-Ethernet");
    client.println("Connection: close");
    client.println();

    // Actualiza el tiempo en milisegundos de la ultima conexion
    ultimaConexion = millis();
  } 
}
Este sketch envia informacion para verificar como esta operando el Arduino a la interfaz serial asi que recomiendo que la observen cuando comiencen las pruebas.

4. Servidor Apache – MySQL – PHP

Asumimos que el servidor posee Apache, PHP y MySQL y que estos se encuentran configurados y funcionando sin problemas.
Utilizaremos la misma tabla que en el proyecto anterior llamada “variable” que se puede crear con el siguiente script:
CREATE TABLE IF NOT EXISTS `variable` (
  `fecha` datetime NOT NULL,
  `id` varchar(30) NOT NULL,
  `nombre` varchar(100) NOT NULL,
  `valor` float NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
El script que recibira las variables desde el Arduino se debe llamar sensorarduino.php y debe ser puesto en la raíz del sitio web ya que el código del Arduino lo llama con un “GET /sensorarduino.php…” donde el “/” hace referencia a la raíz del servidor. El codigo del script es el siguiente:
<?php
// www.internetdelascosas.cl
//
// Script para recolectar datos enviados por arduinos conectados a la red
//
// contacto@internetdelascosas.cl
//

// Parametros para encender leds
$umbralTemperatura = 22;
$umbralHumedad = 80;
$umbralLuminosidad = 500;

// Parametros de base de datos
$mysql_servidor = "localhost";
$mysql_base = "iot";
$mysql_usuario = "iot";
$mysql_clave = "contraseña_super_segura_que_no_es_hola123";

$id = htmlspecialchars($_GET["id"],ENT_QUOTES);
$temperatura = htmlspecialchars($_GET["temperatura"],ENT_QUOTES);
$humedad = htmlspecialchars($_GET["humedad"],ENT_QUOTES);
$luminosidad = htmlspecialchars($_GET["luminosidad"],ENT_QUOTES);

// Valida que esten presente todos los parametros
if (($id!="") and ($temperatura!="") and ($humedad!="") and ($luminosidad!="")) {
    mysql_connect($mysql_servidor,$mysql_usuario,$mysql_clave) or 
       die("Imposible conectarse al servidor.");
    mysql_select_db($mysql_base) or die("Imposible abrir Base de datos");

    $sql = "insert into variable (fecha, id, nombre, valor) 
            values (NOW(),'$id','temperatura','$temperatura')";
    mysql_query($sql);

    $sql = "insert into variable (fecha, id, nombre, valor) 
            values (NOW(),'$id','humedad','$humedad')";
    mysql_query($sql);

    $sql = "insert into variable (fecha, id, nombre, valor) 
            values (NOW(),'$id','luminosidad','$luminosidad')";
    mysql_query($sql);

    // Genera respuesta en XML para que el Arduino lo procese
    if ($temperatura < $umbralTemperatura)
        echo "<led_1>1</led_1>";
    else
        echo "<led_1>0</led_1>";

    if ($humedad > $umbralHumedad)
        echo "<led_2>1</led_2>";
    else
        echo "<led_2>0</led_2>";

    if ($luminosidad < $umbralLuminosidad)
        echo "<led_3>1</led_3>";
    else
        echo "<led_3>0</led_3>";
    echo "\n";
}
?>
Recuerden cambiar las credenciales de la base de datos MySQL por las de su base de datos.
Este código php genera una salida en XML como la siguiente
<led_1>1</led_1><led_2>0</led_2><led_3>0</led_3>
La cual es procesada por el Arduino el cual lee el valor encerrado en cada tag XML (<led_1> </led_1>) como el valor binario de encendido o apagado del led que corresponde al tag.

5. Prueba Final

Si han realizado todos los pasos correctamente entonces al verificar la interfaz serial del Arduino deberían ver el mensaje de inicio, la dirección IP que asume el Arduino,  los valores que se obtienen desde los sensores y que son enviados al servidor y la respuesta que el servidor envía procesada por el Arduino que indica en binario (0/1) si el led debe encenderse o no
ArduinoSerial
Y al revisar el registro log en el servidor web deberian ver las conexiones que realiza el Arduino
[root@iot]# tail -f /var/log/httpd/iot.cl_access_log
210.1.221.117 - - [14/Jul/2014:18:39:14 +0400] "GET /sensorarduino.php?id=joniuz&temperatura=20.00&humedad=48.00&luminosidad=685 HTTP/1.1" 200 49 "-" "Arduino-Ethernet"
210.1.221.117 - - [14/Jul/2014:18:40:14 +0400] "GET /sensorarduino.php?id=joniuz&temperatura=20.00&humedad=47.00&luminosidad=687 HTTP/1.1" 200 49 "-" "Arduino-Ethernet"

No hay comentarios:

Publicar un comentario