Enviar datos a Azure desde Arduino (parte 2, la electrónica)

En el artículo anterior vimos como podías configurar lo necesario para poder tener un repositorio de información que te sirviera para comenzar con tu proyecto de internet de las cosas. Ahora continuamos con la segunda parte (la más divertida) que es armar el prototipo para generar la información a partir del sensor.

Los materiales

Para este artículo, vamos a utilizar los siguientes materiales:

1 Arduino (de preferencia UNO, no importa siempre y cuando pueda soportar un shield de ethernet).

1 Un shield de ethernet.

1 Sensor DHT11.

1 Pantalla LCD con I2C (puede ser sin el módulo, solo por ahorrar pines).

Si no tienes los componentes, puedes escribir a este correo, hacen entregas a todo el país y pueden mandarte hasta armado el prototipo.

El montaje del prototipo

Viene la parte más divertida, montar todo tu equipo. Sigue el siguiente diagrama para poder hacerlo.

DigitalThermometer_bb¿Listo? Vamos por el código de Arduino por partes. Primero las declaraciones de variables y bibliotecas de clases requeridas.

#include <dht.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <Ethernet.h>
 
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
dht weatherSensor;
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0F, 0xEC, 0x6C };
String bodyMessage;
EthernetClient client;

Las referencias a las bibliotecas de clases son para el sensor DHT11, las dos siguientes son para la pantalla LCD y las dos últimas para la conexión vía ethernet. Por el lado de las variables, la primera se refiere a la pantalla con el módulo I2C, la segunda al sensor de temperatura y humedad, el arreglo de bytes a la dirección mac del shield, la cuarta la usaremos para envío de información y por último la variable para ethernet.

El primer método indispensable para Arduino, el método setup establece los valores para el monitoreo serial y la pantalla, después para el cliente de conexión. Notarás que hay un método llamado printLcdMessage, ya lo escribiremos.

void setup()
{
Serial.begin(9600);
lcd.begin(16,2);
lcd.backlight();
printLcdMessage( 0, "Datos: Iniciando");
 
if (Ethernet.begin(mac) == 0)
{
printLcdMessage( 0, "Datos: Fallida");
for (;;) ;
}
}

En el segundo método básico para una aplicación de Arduino vamos a establecer los métodos necesarios que estarán repitiendose de manera cíclica con una frecuencia de cinco segundos.

void loop()
{
bodyMessage = BodyMessageGenerator();
send_request();
wait_response();
read_response();
end_request();
 
delay(5000);
}

Solo por el nombre de los métodos notarás para que es cada uno y serán muy fáciles de comprender por lo mismo. Vamos a ver a cada uno comenzando por el más importante, el que envía información vía el API REST a un mobile service de Azure. Utiliza los encabezados requeridos y es importante que la longitud del mensaje sea exacta.

void send_request()
{
printLcdMessage( 0, "Datos:Conectando");
 
if (client.connect("internetofthingsservice.azure-mobile.net", 80))
{
client.println("POST /tables/<<la tabla que estarás usando>> HTTP/1.1");
client.println("Host: <<la direccion de tu sitio>>");
client.println("X-ZUMO-APPLICATION: <<tus llaves de acces>>");
client.println("Accept: application/json");
client.println("Content-Length: 109");
client.println();
client.print(bodyMessage);
client.println();
 
printLcdMessage( 0, "Datos: Enviados ");
}
else
{
printLcdMessage(0, "Conexion: Fallida");
}
}

Vamos con el método que esperará pacientemente la respuesta que nos dará el resultado de la operación.

void wait_response()
{
while (!client.available())
{
if (!client.connected())
{
return;
}
}
}

Después el método que lee la respuesta.

void read_response()
{
bool print = true;
while (client.available())
{
char c = client.read();
if (c == '\n')
print = false;
if (print)
Serial.println(c);
}
}

Un método muy simple para cerrar conexión.

void end_request()
{
client.stop();
}

Después vamos por el método que se encargará de imprimir mensajes en la pantalla, todos los mensajes relacionados a nuestra conexión de datos, al final, no pensamos tener todo el tiempo el prototipo en modo de depuración.

void printLcdMessage(int line, String message)
{
lcd.setCursor(0,0);
lcd.print(message);
}

Una variable del método anterior te ayudará a mostrar en la pantalla la información que viene del sensor. Esta será una gran referencia para que puedas comprobar que lo que tienes en tu base de datos será lo que tienes también en tu pantalla.

void printLcdWeather(double temp, double humi)
{
lcd.setCursor(0,1);
lcd.print("T= ");
lcd.print(int(temp));
lcd.print(" C  H= ");
lcd.print(int(humi));
lcd.print(" %");
}

Por último, solo debes obtener el cuerpo del mensaje que desplegarás al servicio móvil de Azure para que vaya directo a la base de datos. Este mensaje estará en formato JSON y debes formarlo de esa manera para evitar cualquier error.

String BodyMessageGenerator()
{
weatherSensor.read11(A0);
 
printLcdWeather(weatherSensor.temperature, weatherSensor.humidity);
String sensorName = "\"SensorName\": \"Sensor Microsoft\", \"Latitude\": 19.3662, \"Longitude\": -99.2445";
String temperature = "\"Temperature\": " + String(int(weatherSensor.temperature));
String humidity = "\"Humidity\": " + String(int(weatherSensor.humidity));
String wrapper = "{" + sensorName + ", " + temperature + ", " + humidity + "}";
return wrapper;
}

El video a continuación te dará una mejor referencia de lo que debes tener hasta este momento.

¡Listo! Hemos cumplido con la aprte electrónica. Ahora es momento de ir con la siguiente. La creación de la infraestructura necesaria para almacenar todo esto.

Si quieres descargar el código de este ejercicio, puedes hacerlo desde aquí.

Si deseas descargar el código completo, puedes hacerlo desde aquí.

 

4 Comments

  • Manuel
    7 junio, 2016 - 4:51 am | Permalink

    Hola Amin, oye una duda me pudieras explicar como puedo mandar una cadena de longitud de datos variable a la nube de Azure, te adjunto el código.

    CuerpoMensaje = GeneradorCuerpoMensaje();

    client.println(“POST /tables/X HTTP/1.1”);
    client.println(“Host: XXX.azure-mobile.net”);
    client.println(“X-ZUMO-APPLICATION: XXX-YYY”);
    client.println(“Content-Type: application/json”);
    client.println(“Content-Length: “);
    client.println(CuerpoMensaje.length());
    client.println(CuerpoMensaje);
    client.println();
    Serial.println(“Datos enviados”);

    String GeneradorCuerpoMensaje()
    {
    float gps_lat = gps.location.lat();
    float gps_lng = gps.location.lng();
    String nombreSensor = “\”Nombresensor\”:\”GPS\””;
    String latitud = “\”Latitud\”:” + String((float)gps_lat);
    String longitud = “\”Longitud\”:” + String((float)gps_lng);
    String wrapper = “{” + nombreSensor + “,” + latitud + “,” + longitud + “}”;
    Serial.println(wrapper);
    return wrapper;
    }

    Lo que me gustaría seria enviar el String de datos sin necesidad agregar el numero de caracteres en la parte de Content-Length:, dado que la longitud puede variar.

    Quedo al pendiente de tu respuesta.
    Saludos.

    • Amin Espinoza
      28 junio, 2016 - 12:55 pm | Permalink

      Ops! Perdona la respuesta tan lenta! Es fácil, solo calcula la longitud de tu cadena final, colócala como una variable global en tu código y listo!!

  • Juan Manuel Malacara
    7 octubre, 2016 - 4:50 pm | Permalink

    Hola, como puedo hacer lo mismo pero por medio de wifi sin usar ethernet?

    • Amin Espinoza
      17 noviembre, 2016 - 6:13 pm | Permalink

      Solo usando un módulo de Wifi en lugar de uno de Ethernet, en cuanto al código es esencialmente el mismo.

  • Deja un comentario

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

    This blog is kept spam free by WP-SpamFree.