Home»Desarrollos»Medidor de consumo. Conectamos a Internet

Medidor de consumo. Conectamos a Internet

2
Shares
Pinterest WhatsApp

Por fin conectamos a Internet nuestro pequeño medidor de consumo. No olvidemos que el objetivo del proyecto es ir recopilando el consumo de nuestro hogar y poder posteriormente analizar la información para ver en donde podemos ahorrar (bueno, también aprender a trabajar con microcontroladores, algo de electrónica básica, programación en C …)

Ethernetmodule1

Para ello utilizaremos la interfaz ethernet ENC28J60 muy conocida en el mundo del Arduino y con un precio muy reducido. Como vamos a ver, es muy fácil su configuración y utilización, y podremos ir enviado a un servidor los datos de consumo recogidos de forma sencilla.

Podéis entender un poco mejor como funciona la interfaz revisando su datasheet, pero no os preocupéis, ya alguien ha estado desarrollando una librería para facilitarnos el hablar con el módulo. Utilizaremos la librería EtherCard (https://github.com/jcw/ethercard) para acceder a la interfaz y poder realizar la configuración inicial y luego el envío y recepción de información del servidor web.

Para la configuración inicial emplearemos el protocolo DHCP para inicializar la interfaz de forma automática cogiendo de nuestro router la dirección IP, puerta de enlace y servidor DNS. Es posible hacer una configuración estática de estos datos, pero para nosotros es más sencillo emplear la configuración automática. También nos va a permitir resolver nombre de direcciones por DNS.

Conexión de la interfaz Ethernet
IMG_20151220_131955

 

 

ENC28J60 Arduino
CS D10
SI D11
SO D12
SCK D13
5v 5v
GND GND

 

 

 

 

Tanto en la foto como en la tabla tenemos el detalle de las conexiones que seguiremos.Utilizaremos los pines 10,11,12 y 13 digitales del Arduino para comunicarnos con la interfaz, y conectaremos la salida +5v y GND al ENC28J60.

Podéis ver en el módulo que también se puede conectar a la salida de 3.3v y que hay mas conexiones con REST, INT, CLK que no son necesarias para nuestro pequeño medidor.

El montaje final debería quedar similar a este. Yo he utilizado una antigua faja IDE para conectar discos duros que me permite de forma fácil conectar muchos dispositivos y no tenerlos pegados a la placa del Arduino.

IMG_20151220_131045

Programamos nuestro Arduino

Al código que ya tenemos del anterior artículo, vamos a incorporar toda la configuración necesaria para realizar el envío de nuestros datos a un servidor en internet.

  • Antes de nada descargaremos la librería EtherCard y la incluiremos en nuestro IDE como ya hemos visto, copiándola en la carpeta «libraries».
  • Copiaremos el siguiente código y programaremos el arduino como ya sabemos
#include <EmonLib.h>    // Incluimos Emon Library
#include <EtherCard.h>     // Incluimos EtherCard Library
 
#define REQUEST_RATE 5000  // Frecuencia de envío al servidor
 
EnergyMonitor emon1;       // Creamos la instancia de la librería
 
// Dirección mac de la interfaz
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x33 };
 
// Dirección del servidor web
char const website[] PROGMEM = "www.gonzalogalvan.es";
 
byte Ethernet::buffer[750]; 
char irmsChar[10];
static long timer;
 
void setup() {
  Serial.begin(9600);
  emon1.current(2, 60.60);             // Inicializamos la librería: input pin, calibration.
 
  Serial.println( "Inicio");
 
  //Inicializamos la interfaz Ethernet
  if (ether.begin(sizeof Ethernet::buffer, mymac,10) == 0) 
    Serial.println( "Problemas accediendo a la interfaz !!");
 
  //Confiramos la interfaz por DHCP
  Serial.println(F("Configurando por DHCP ..."));
  if (!ether.dhcpSetup())
    Serial.println(F("Fallo en DHCP !!"));
 
  ether.printIp("Mi IP: ", ether.myip);
  ether.printIp("Puerta de Enlace IP: ", ether.gwip);
  ether.printIp("DNS IP: ", ether.dnsip);
 
  //Resolvemos el nombre del servidor para obtener la IP
  if (!ether.dnsLookup(website)) {
    Serial.println("Fallo en DNS!!");
  }
 
  ether.printIp("Servidor: ", ether.hisip);
 
}
 
void loop() {
  double Irms = emon1.calcIrms(1480);  // Calculamos el irms
  if(Irms &lt;0.20) Irms = 0.0;
 
  Serial.print(" Consumo: ");
  Serial.println(Irms*230);
 
  //Procesamos la respuesta de la petición al servidor
  ether.packetLoop(ether.packetReceive());
 
  //Cada 5s hacemos un envío de los datos al servidor
  if (millis() > timer + REQUEST_RATE) {
    timer = millis();
    Serial.println("\n>>> REQ");
 
    //Convertimos el double a cadena
    String(Irms*230,2).toCharArray(irmsChar,10);
    ether.browseUrl(PSTR("/arduino/saveData.php?consumo="),irmsChar , website, procesarRespuesta);
  }
} 
 
 
static void procesarRespuesta (byte status, word off, word len) {
  Serial.print("<<< reply ");
  Serial.print(millis() - timer);
  Serial.println(" ms");
  Serial.println((const char*) Ethernet::buffer + off);
}

Vamos a ver en detalle las nuevas líneas de código que hemos introducido en nuestro pequeño microcontrolador:

  • Añadimos la librería EtherCard al proyecto
    #include <EtherCard.h>    // Incluimos EtherCard Library
  • Se define una serie de variables y constantes necesarias para poder trabajar con el módulo ethernet
     
    #define REQUEST_RATE 5000  // Frecuencia de envío al servidor
     
    // Dirección mac de la interfaz
    static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x33 };
     
    // Dirección del servidor web
    char const website[] PROGMEM = "www.gonzalogalvan.es";
     
    byte Ethernet::buffer[750]; 
    char irmsChar[10];
    static long timer;
    • REQUEST_RATE: Constante definida a 5000ms que será la frecuencia con la que vamos a enviar los datos a nuestro servidor.
    • mymac: Array de bytes con la dirección MAC de nuestra interfaz. Esta dirección debe ser única en nuestra red local. Si conectáis varias Arduinos, recordad cambiar por lo menos el último byte 0x33 por otro valor.
    • website: Array con el nombre del servidor que almacenará los datos. La palabra clave PROGMEM se utiliza para almacenar esta variable en la memoria flash del microcontrolador y no en la SRAM. Esto se emplea cuando la memoria RAM se empieza a quedar pequeña y necesitamos almacenar más datos …. pero esa es otro tema que trataremos en algún post.
    • Ethernet::buffer: Buffer de bytes donde se almacenará la respuesta de las peticiones al servidor.
    • irmsChar: Buffer para realizar la conversión de double a char.
    • timer: Variable utilizada para poder determinar cuando hemos superado los 5 segundos entre envío y envío.
  • Dentro del método setup() hacemos varias configuraciones:
    • Inicializamos la interfaz ethernet indicando la dirección MAC y el pin del Arduino que utilizaremos para seleccionar el módulo, en nuestro caso el pin 10.
       //Inicializamos la interfaz Ethernet
        if (ether.begin(sizeof Ethernet::buffer, mymac,10) == 0) 
          Serial.println( "Problemas accediendo a la interfaz !!");
    • Llamamos al método dhcpSetup() para que se haga todo el proceso de negociación para obtener los datos de configuración TCP/IP: IP, puerta de enlace y DNS.
        //Confiramos la interfaz por DHCP
        Serial.println(F("Configurando por DHCP ..."));
        if (!ether.dhcpSetup())
          Serial.println(F("Fallo en DHCP !!"));
       
        ether.printIp("Mi IP: ", ether.myip);
        ether.printIp("Puerta de Enlace IP: ", ether.gwip);
        ether.printIp("DNS IP: ", ether.dnsip);
    • Por último, obtenemos la IP del servidor al que vamos a ir enviado la información. Llamando al método dnsLookup() que dejará en la variable ether.hisip la IP obtenida, y será la utilizada por la librería.
        //Resolvemos el nombre del servidor para obtener la IP
        if (!ether.dnsLookup(website)) {
          Serial.println("Fallo en DNS!!");
        }
        ether.printIp("Servidor: ", ether.hisip);
  • Ahora toca modificar el método loop() para ir realizando el envío al servidor cada 5 segundos:
    • Primero indicamos a la librería EtherCard que procese la posible respuesta que hayamos obtenido del servidor web. Hay que tener en cuenta que el microcontrolador que estamos utilizando nos es multitarea y solo hay un hilo de ejecución. Al ser la petición al servidor asíncrona, deberemos estar continuamente verificando si hemos obtenido respuesta, y una vez recibida se llamará al método que definamos en las lineas siguientes de código.
        //Procesamos la respuesta de la petición al servidor
        ether.packetLoop(ether.packetReceive());
    • Comprobamos que ha pasado 5 segundos desde la última actualización, convertimos el valor double del consumo a un array de chars, y por último hacemos el envío a la URL con la función ether.browseUrl.
        //Cada 5s hacemos un envío de los datos al servidor
        if (millis() &gt; timer + REQUEST_RATE) {
          timer = millis();
          Serial.println("\n>>> REQ");
       
          //Convertimos el double a cadena
          String(Irms*230,2).toCharArray(irmsChar,10);
          ether.browseUrl(PSTR("/arduino/saveData.php?consumo="),irmsChar , website, procesarRespuesta);
        }

      Detallando un poco más los parámetros de la función browseUrl:

      • PSTR(«/arduino/saveData.php?consumo=»): String con la URL del script PHP. Definimos la variable «consumo» para enviar el valor numérico al servidor.
      • irmsChar: Array con el valor del consumo
      • website: Nombre del servidor web
      • procesarRespuesta: Método que será llamado cuando se procese la respuesta del servidor. Este método será llamado desde packetLoop.
  • Por último tenemos definido el método encargado de procesar la respuesta del servidor. En nuestro caso únicamente muestra por consola la información recibida.
    static void procesarRespuesta (byte status, word off, word len) {
      Serial.print("<<< reply ");
      Serial.print(millis() - timer);
      Serial.println(" ms");
      Serial.println((const char*) Ethernet::buffer + off);
    }

     

Más adelante haremos una pequeña optimización a este programa para evitar estar enviando continuamente datos al servidor cuando no ha variado la lectura.

Pegueño script PHP para ver que funciona todo nuestro montaje

En el siguiente capítulo entraremos a fondo en como almacenar la información recibida desde el Arduino en un servidor utilizando un script PHP y una base de datos MySQL. También veremos como recuperar y mostrar esta información de forma gráfica.

Por ahora crearemos un pequeño script que nos permite comprobar que todo nuestro montaje esta bien hecho. Subiremos a nuestro servidor el siguiente script PHP con el nombre «saveData.php«. En el ejemplo, la ruta donde debemos colocarlo es «/arduino«:

<?php 
 
$consumo= $_GET['consumo']; 
if(!$consumo) $consumo = 0; 
echo date("d/m/Y H:i:s")." - ".$consumo; 
 
?>

El script simplemente coge el valor del consumo enviado por el Arduino y lo devuelve junto a la fecha actual.

Probando todo!

Si hemos conectado correctamente la interfaz ethernet con el Arduino, configurado el programa con nuestro servidor web, el Arduino es capaz de coger IP del router que tengamos en casa y hemos subido el script PHP al servidor, podemos ver como funciona todo en conjunto.

En el siguiente pantallazo podemos ver las lecturas y los envíos en la consola del Arduino,a la izquierda, y en la derecha, el log del servidor web donde se va registrando las peticiones cada 5 segundos.

logsArduino

Aquí podemos ver como la comunicación ethernet es asíncrona. Siguiendo la secuencia marcada con los números rojos tenemos los siguientes pasos:

  1. Se realiza el envío del consumo al servidor web.
  2. El servidor web recibe la petición y ejecuta el script PHP
  3. El programa del Arduino sigue ejecutándose (sigue apareciendo en la consola las lecturas de la pinza)
  4. Se recibe la respuesta del servidor web que es procesada por el Arduino. En la consola podemos ver la respuesta que está formada por la fecha y el valor enviado en la petición.

Un pequeño vídeo viendo el funcionamiento del medidor con la consola del Arduino a la izquierda y la consola con los logs del servidor web a la derecha:

En el próximo artículo veremos como definir la base de datos que almacenará las lecturas, ampliaremos el script PHP para guardar esta información y veremos como recuperar los datos para poder trabajar con ellos.

Previous post

Medidor de consumo. Lectura de la corriente con Arduino

Next post

Librería LegoPF - Control con Arduino de motores Lego

6 Comments

  1. Albert
    19 marzo, 2016 at 5:15 pm — Responder

    hola una consulta, soy nuevo en esto de ethernet, me gustaria saber si alguna ves intentaste enviar los datos a un servidor FTP ? , estoy intentando hacer algo similar pero quiero guardar los datos en un servidor ftp, agradezco de antemano tu respuesta

    • gonzalo
      19 marzo, 2016 at 7:12 pm — Responder

      Hola Albert.

      No, no he hecho nunca ninguna conexión por FTP, pero no debe ser muy difícil al ser un protocolo relativamente sencillo. Si el FTP no es anónimo te tocará realizar el proceso de logado con usuario/clave.

      http://playground.arduino.cc/Code/FTP

      Dependiendo de tu interfaz ethernet, creo que hay librerías que ya traen implementado el protocolo. ¿que interfaz usas?

      Si ve algo lo comento por aquí.
      Gracias por el comentario.

  2. henry romero
    9 enero, 2017 at 3:00 am — Responder

    buemas tarde un consulta me gustaria saber como puede mandar la medicion a una web para monitorear el consumo si me pudiera ayudar en eso se lo agradeceria

    • gonzalo
      9 enero, 2017 at 8:33 pm — Responder

      Puedes enviar los datos mediante un POST o un GET a cualquier servidor ¿como piensas recoger los datos?¿es un servidor que has montado tú?

  3. Martin
    26 octubre, 2018 at 6:01 pm — Responder

    Hola Gonzalo, estoy armando algo similar, pero con la pagina web dentro del modulo, de modo que quien coloque la ip pueda ver los valores. Es un voltimetro que mediante divisor de tension con resistencias me permite leer un banco de baterias.
    Mi mayor problema radica en que no puedo obtener lectura de decimales de hecho, me entrega cualquier valor, mientras que a traves del terminal serie del soft arduino puedo ver los valores correctamente.
    Me podras orientar un poco? dejo la parte del codigo que es donde creo esta el problema.
    —————————————
    static word homePage() {
    BufferFiller bfill = ether.tcpOffset();
    bfill.emit_p(PSTR(
    «»
    «»
    «»
    «»
    «»
    «»
    «-Voltaje baterias: $V Vcc»
    «»),
    (((analogRead(0) * 4.77) / 1024.0) / 0.0909),
    return bfill.position();
    }
    ——————————————-

    Muchas gracias

    • gonzalo
      5 noviembre, 2018 at 8:12 pm — Responder

      No conozco BufferFiller pero yo intentaría primero obtener el valor calculado en un float por ejemplo y luego lo convertiría a String antes de meterlo a BufferFiller.

      Por ejemplo:

      float voltaje = ((analogRead(0) * 4.77) / 1024.0) / 0.0909;
      char voltajeChar[10];
      String(voltaje).toCharArray(voltajeChar,10);

      Y luego ya metes voltajeChar al buffer.

Leave a reply

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