Domotiza tu casa – Día 7. Programador de riego Parte I

Bueno, bueno, bueno, ya estamos aquí otro día más.

Hacia tiempo que queria publicar el programador de riego, y alguno que otro direis ¿lo podrías haber publicado antes de vacaciones, no?

Pues no, porque imaginaros que por lo que sea al volver de las vacaciones os encontrais las plantas muertas, o peor aún, habeis utilizado el programador para regar un cuenco y dar agua al gato. Es demasiada responsabilidad, y cualquier fallo podría provocar mucho reencor hacia mi persona. Así que una vez pasadas las vacaciones empezamos con el tutorial del programador de riego.

Este tutorial constará de varias partes.

La primera, la de hoy, en que haremos el código básico para el funcionamiento del riego.

La segunda, donde montaremos el riego y probaremos el funcionamiento de lo que hemos hecho.

Y una tercera con mejoras que tengo previstas, mas las que podeis vosotros a partir de los comentarios sugerir.

Empecemos por lo primero. El código de hoy es sencillo, sin mucha complicación, breve, e interesante.

Constará de las siguientes partes importantes:

– En el setup, osease, lo que se ejecuta una única vez al iniciar arduino, vamos a sincronizar el reloj interno de arduino con la hora, y definiremos cada cuanto se ha de recalibrar el reloj.

– En el loop, o rutina que ejecutará infinitamente, comprobaremos si es hora de regar o no, y le pondremos un retardo de 10 segundos. Esta comprobación la realizará llamando a una función que nos dirá si es hora de regar o no.

– La función de riego que compara las horas de riego que tiene definidas con la hora actual y nos devuelve “true” o “verdadero” si es hora de regar, y “false” o “falso” si no es momento de regar.

– La función que obtiene la hora la ponemos también en una función aparte

Siempre tenemos que programar de la manera más limpia posible, separando en funciones, clases, etc… de esta manera nos quedará un codigo fácil de entender y de mantener.

 

El código sería el siguiente:

//Inclusión de librerías

#include <Time.h>
#include <SPI.h>
#include <Ethernet.h>
#include <Udp.h>

// MAC e IP de Arduino
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = {
192,168,1,40 };

unsigned int localPort = 8888;      // Puerto para escuchar los paquetes UDP

byte timeServer[] = {
192, 43, 244, 18}; // time.nist.gov el servidor NTP

const int NTP_PACKET_SIZE= 48; // Cuando el servidor nos devuelve la hora en el paquete UDP, La hora viene en los primeros 48 bytes del paquete

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer para almacenar los paquetes entrantes y salientes

void setup()
{
// Inicializamos el Ethernet, el UDP y el Serial
Ethernet.begin(mac,ip);
Udp.begin(localPort);
Serial.begin(9600);

//función importante del dia. “setSyncProvider” selecciona cual es la función que utilizaremos para sincronizar la hora, y “setSyncInterval” define, en segundos, cada cuanto queremos sincronizar la hora.
setSyncProvider(getNtpTime);
//Hacemos que cada hora se sincronice la hora.
setSyncInterval(3600);

//almaceno la hora en la variable timestamp llamando a la función getNtpTime()
unsigned long timestamp = getNtpTime();
Serial.print(“Hora establecida Time:”);
Serial.println(timestamp);
//segunda función importante del día. setTime, asigna al reloj interno de arduino la hora que le indiquemos en la variable.
setTime(timestamp);

}

void loop()
{
//Muestro por el puerto serie la hora
Serial.print(“Son las: “);
Serial.println(String(hour()) + “:” + String(minute()));
//comprobamos si es la hora del riego
if(esHoraRiego()){
//Si es la hora del riego, mostramos un mensaje indicándolo por el puerto serie
Serial.println(“Es hora riego!!”);
} else {
//Si no es la hora del riego, mostramos un mensaje indicándolo por el puerto serie también
Serial.println(“No es hora riego”);
}
delay(10000);

}

boolean esHoraRiego(){
//Defino horas de riego Inicio a las 19:39 y termina a las 19:40 (poned las horas a las que hagais las pruebas)
byte horaInicio = 19;
byte minutoInicio = 39;
byte horaFin = 19;
byte minutoFin = 40;

//Para hacer las comparaciones de cuando empezar y cuando terminar, lo paso todo a minutos. Por eso la hora de inicio serian las (19 x 60) + 39 = 1.179 y la de fin 1.180. Esto lo hago porque el código de intentar comparar horas con horas es algo más complejo, y yo amo la simplicidad.

int momentoInicio = (horaInicio * 60) + minutoInicio;
int momentoFin = (horaFin * 60) + minutoFin;
int momentoAhora = (hour() * 60) + minute();

//Esto es que si hemos pasado o estamos en el momento de inicio , pero antes del momento del fin…
if((momentoInicio<=momentoAhora) && (momentoAhora<momentoFin)){
//devolver “Cierto” en esta función “esHoraRiego”
return true;
} else {
//devolver “Falso” en esta función “esHoraRiego”
return false;
}
}

unsigned long getNtpTime(){
sendNTPpacket(timeServer); // enviar paquete NTP al servidor de la hora

// esperar para ver si hay respuesta
delay(1000);
if ( Udp.available() ) {
Udp.readPacket(packetBuffer,NTP_PACKET_SIZE);  // leer el paquete

//Extraer la hora del paquete (Ya explicado en el tutorial del servidor NTP

unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);

// la hora obtenida son los segundos desde 1 de Enero de 1900
unsigned long secsSince1900 = highWord << 16 | lowWord;

//Convertir la hora recibida al formato en que trabajan las funciones (hora Unix, 1 de enero de 1970), En segundos, son 2208988800:
const unsigned long seventyYears = 2208988800UL;
//restar 70 años
unsigned long epoch = secsSince1900 – seventyYears;
// retornar Unix time: sumando dos horas por la diferencia horaria

return epoch+7200;

}
}

//Función para enviar el paquete NTP
unsigned long sendNTPpacket(byte *address)
{

memset(packetBuffer, 0, NTP_PACKET_SIZE);

packetBuffer[0] = 0b11100011;
packetBuffer[1] = 0;
packetBuffer[2] = 6;
packetBuffer[3] = 0xEC;

packetBuffer[12]  = 49;
packetBuffer[13]  = 0x4E;
packetBuffer[14]  = 49;
packetBuffer[15]  = 52;

Udp.sendPacket( packetBuffer,NTP_PACKET_SIZE,  address, 123);
}

 

Si teneis cualquier problema, adjunto os dejo el archivo.

Domotiza tu casa – Dia 7 – Programador de riego

Si os ha gustado, dadle al Me gusta del facebook o el linkedI!
Espero vuestros comentarios

Domotiza tu casa – Día 6. Leer Temperatura con Arduino

En el día de hoy vamos a trabajar con unos sensores sencillos de temperatura, montaremos un sencillo circuito y haremos que nuestro arduino lea la temperatura y la muestre en su aplicación.

En primer conozcamos el material:

– El sensor(<1€).

El sensor que utilizaré es el LM35 (ojo, no confundir con el LM335) del cual podemos tener su datasheet u hoja de especificaciones para los hispanohablantes en http://www.national.com/ds/LM/LM35.pdf.

OJO MUY IMPORTANTE. ¿Cómo saber qué pata es el positivo, cual el negativo y cual la señal? ¿Qué pensabais ir probando hasta que funcionara? Pues no, solo a alguien con el intelecto de un mosquito se le ocurría hacerlo así, y os explico porqué.

Si cambiais el positivo por el negativo y viceversa, en unos segundos se sobrecalienta el sensor, hasta el punto de poder quemarnos, y deja de funcionar.

De esta manera, aquí el menda del intelecto de mosquito, se cargó tres sensores. El primero por leer la especificación del LM335 y no del LM35, el segundo por ponerlo del revés, y el tercero por creer que el segundo estaba defectuoso y volverlo a probar en el mismo circuito….

Ahora que he captado vuestra atención para las próximas lineas, os enseñaré a identificar las patas del sensor correctamente. Cogiendo el sensor como muestro en la imagen

Cómo usar sensor LM35
Cómo usar sensor LM35

Con la parte curva hacia abajo y las patas mirando hacia vosotros, el pin de la izquierda es el positivo, el de la derecha el negativo o tierra, y el del medio es la señal.

– Resistencia(<1€)

Para el circuito del sensor de temperatura necesitaremos una resistencia de 100K (o lo que es lo mismo una que tenga el código de colores marron, negro, amarillo, dorado)

– Protoboard o tabla de prototipos(<6€)

No es más que una tabla donde montar el circuito de manera provisional para hacer nuestras pruebas y experimentos.

Protoboard
Protoboard

– Accesorios(<3€)

Necesitaremos cables y alicates de corte de momento.

 

El circuito que montaremos tendrá el siguiente esquema:

Esquema circuito LM35
Esquema circuito LM35

Y quedará en nuestra protoboard de la siguiente manera:

Circuito LM35 para Arduino
Circuito LM35 para Arduino

Al lado izquierdo queda el sensor LM35, el cual es alimentado por el cable rojo, que obtendrá la energía desde la salida de 5V de nuestra placa de Arduino, todo y que la alimentación también podría ser externa.

El cable de debajo del rojo es el cable de señal. Esta señal será analógica, es decir, a mayor temperatura mayor voltaje. Esta señal, ha de ser conectada a la entrada A0 de Arduino.

Finalmente, el último cable, el que corresponde a la pata de abajo del sensor en esta imagen, es el negativo o tierra, el cual irá conectado a la toma de tierra de la placa identificada con GND(GrouND o tierra en ingles).

Importante, conectar la resistencia entre la señal y la tierra, de esta manera podremos obtener valores de temperatura negativos (si teneis curiosidad, para más info ver el datasheet del sensor que he puesto en el link del principio de la entrada).

Como conectar circuito sensor LM35 a Arduino
Como conectar circuito sensor LM35 a Arduino

Todo y que la imagen puede engañar el ángulo, vuelvo a destacar, que el cable rojo va conectado al 5V, el negro al GND, y el cable de señal al A0.

Una vez que está todo conectado como se indica en las imágenes anteriores, es momento de empezar a programar. Seguramente con todo lo que habreis hecho en las anteriores entradas del tutorial, lo que programaremos hoy os parecerá bien sencillo.

 

Para empezar, al principio de todo, en las definiciones, justo debajo de los # include y #define de la anterior sesión insertamos lo siguiente:

//Declaro las variables para leer la temperatura
int sensorTemperatura = 0; //Este será el PIN al que conectaré el sensor de temperatura LM35.
int temperatura = 0; //inicializamos el valor de la variable temperatura a cero.

Dentro del setup, incluyo lo siguiente:

//declaro que el pin de la entrada analogica será de lectura
pinMode(sensorTemperatura, INPUT);

Esta temperatura obtenida la quiero mostrar en el apartado de “Balcón”, (por escoger alguno… si vosotros lo quereis colocar en otro sitio sois totalmente libres de hacerlo 🙂  ).

Por lo tanto, dentro de la función “body”, justo después del

else if (modulo == “Balcon”){

colocamos lo siguiente:

float temperatura = getTemperatura(sensorTemperatura);//declaro la variable de tipo “float” (para que pueda tener decimales) y le asigno el valor que me devuelva la llamada a la función de obtener temperatura. Llamo a la función para obtener temperatura y le envio como parámetro el pin al que está conectado el sensor.

 

Ahora una vez que tengo el valor de la temperatura en la variable “temperatura” lo muestro en pantalla dentro de la web de la siguiente manera:

client.println(“<ul><li>Temperatura balc&oacute;n: “);
client.println(temperatura);

client.println(” oC</li><li>Luminosidad: XX</li><li>Humedad:XX</li><li>PH:XX</li><li>Riego programado de: XX a XX, y de YY a YY</li></ul>”);
}

Por lo tanto para no liaros, esto es lo que subtituiria el contenido del apartado de balcon del body:

float temperatura = getTemperatura(sensorTemperatura);
client.println(“<ul><li>Temperatura balc&oacute;n: “);
client.println(temperatura);
client.println(” oC</li><li>Luminosidad: XX</li><li>Humedad:XX</li><li>PH:XX</li><li>Riego programado de: XX a XX, y de YY a YY</li></ul>”);

Una vez que el cuerpo de la web hace la llamada para obtener la temperatura, vamos a realizar que lea el voltaje que nos llega en A0, y nos lo transforme a un número que será nuestra temperatura.

Al final del todo del Sketch (al final del todo del programa =) ), creamos la siguiente función:

float getTemperatura(int sensor){
int valorLectura = analogRead(sensor); //declaramos la variable valorLectura y le asignamos como valor la lectura del sensor que le hayamos dicho que lea.
float temperatura = (5.0 * valorLectura * 100.0)/1023.0; //conversión del voltaje (que va de 0V a 5V) a temperatura.
return temperatura;//retornar la temperatura
}

El factor de conversión sale de que a la entrada analógica le va a entrar un valor de tensión de entre 0 y 5V, lo cual arduino eso nos lo convierte en una escala del 0 al 1023.

¡¡Y con esto ya nuestra página web en la sección de “Balcón” ya nos daría la temperatura que esté captando nuestro sensor!!

Mejora posible:

Muy posiblemente, una de las primeras cosas que podeis el dedo en el sensor para que suba la temperatura y comprobar como sube la temperatura. Luego quitareis el dedo y volverá a a la temperatura ambiente. Luego probareis a soplarle, y también probareis a irle dando a actualizar a la web y vais viendo como a temperatura ambiente, va variando ligeramente la temperatura. Y os preguntareis, ¿Y esto porque es variable? Sencillo. La corriente no es completamente estable, el nivel de precisión del sensor es limitado, y la escala en la que lo mide arduino tampoco es para trabajar con elementos de precisión. Me explico.

Si el sensor abarca desde los -55ºC hasta los 150ºC, esto quiere decir que tenemos un rango de 205 grados por medir. Por lo tanto si esa escala que nos devuelve arduino va de 0 a 1023, quiere decir que 1023/205 = 4,99…  Es decir que de grado a grado solo nos puede dar esos aproximadamente 5 valores. Pero por ejemplo, si queremos captar decimales, de un grado a otro ¡tenemos 10 decimales! Por lo que por ejemplo si el valor 870 de la escala de arduino, corresponde a 25,5ºC, y el valor 871 corresponde a 25,7ºC,  si tenemos 25,6ºC la mas mínima fluctuación nos hará variar dos decimas, cuando sin embargo, la fluctuación es menor.

No puedo mejorar la precisión de arduino ni modificar las características de este sensor. Pero lo que sí que puedo hacer es realizar diversas mediciones y calcular su media. De esta manera, obtendré un valor más estable y más fiable que si solo tomo una lectura. Así que a continuación os pongo otro código para la función de obtener temperatura:

float getTemperaturaPro(int sensor){
int i = 0;
float temperaturas = 0;
float nTemperaturas = 5;

while(i< nTemperaturas){
temperaturas += (5.0 * analogRead(sensor) * 100.0)/1024.0;
i++;
delay(20);
}
return temperaturas/nTemperaturas;
}

Le podeis poner a nTemperaturas, que es el numero de lecturas a tomar, el valor que querais. Cuanto más alto sea nTemperaturas, mayor precisión, pero más se tardará en ejecutarse.

A continuación, si os habeis perdido en alguno de los capítulos anteriores, o teneis algún problema y quereis comparar con el programa del tutorial, os dejo un enlace para descargar el archivo:

houseboxmain-dia6

Espero que este tutorial os haya gustado y espero vuestros comentarios.

 

¡Hasta pronto!

Domotiza tu casa – Día 5. El tiempo, protocolo NTP

Ahora que ya hemos hecho una estructura sencilla para nuestra web (podeis irla decorando con vuestros colores etc mientras os preparo algo más bonito), vamos pronto a ir trabajando con los datos de los sensores.

Pero antes de empezar a recibir datos de los sensores, necesitaremos dos cosas, el tiempo y almacenamiento (el próximo tutorial).

Dado que cada vez que se ejecuta el código que tenemos en arduino se reinician todas las variables, necesitamos conocer el tiempo a través de un medio externo.

Por suerte, tenemos el protocolo NTP (Network Time Protocol), uno de los protocolos más antiguos de internet (estaba incluso antes del 1985), que se creó para sincronizar la hora de los sistemas informáticos.

Este protocolo nos dará una precisión de milisegundos. Esto es mucho más de lo que necesitamos para controlar el riego o programar tareas 🙂 Si quereis más información acerca de este protocolo, lo podeis encontrar aquí :http://es.wikipedia.org/wiki/Network_Time_Protocol

A lo que íbamos. Si queremos programar un riego, saber a qué hora ha saltado una alarma, y mil cosas más en las que tenemos que comprobar la hora, necesitamos esta función.

Esta función nos devolverá un número, este número a simple vista no nos permite saber qué hora es, ya que ese número son los segundos que han pasado desde el 1 de enero de 1900.

Por lo tanto utilizaremos la librería de tiempo Time, la cual debereis importar en Sketch>Import Library>Time

Libreria Time
Libreria Time

Esta libreria consta de las funciones necesarias para manejar este número que a simple vista no sabríamos entender.

La idea entonces es la siguiente:

– Obtener la hora del servidor NTP

– Traducir la hora obtenida al formato humano

 

Empecemos a programar!!

Os pongo el código y lo voy comentando detalladamente:

//Declaramos las variables e incluimos librerias

 

#include <Time.h>

#include <SD.h>

#include <SPI.h>

#include <Udp.h>

#include <Ethernet.h>
#define BUFSIZ 100;

/************ ETHERNET CONFIG ************/
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //definimos la MAC
byte ip[] = { 192, 168, 1, 177 };//definimos la IP
String ipString = “192.168.1.177”; //IP en formato String (para pruebas)
Server server = Server(80);// definimos el puerto para las peticiones web
unsigned int localPort = 8888;
byte timeServer[] = {
192, 43, 244, 18}; // IP de time.nist.gov es el servidor NTP utilizado
const int NTP_PACKET_SIZE= 48; // El paquete de tiempo NTP  que recibimos está en los primeros 48 bytes del paquete como podreis ver en la wikipedia

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer para paquetes entrantes y salientes

void setup() {
/* Inicializando Serial para debug */
Serial.begin(9600);
/* Inicialiciando ethernet y server */
Ethernet.begin(mac, ip);
server.begin();
Udp.begin(localPort);

}

void loop()
{

//Aquí va el código del anterior tutorial, el cual me saltaré para centrarnos en lo que nos interesa hoy
String clientline= “”;

…..

header(client, modulo);
body(client, modulo);
pie(client);
client.stop();
delay(1000);
}
}
}
}
void header(Client client, String title){
… el código de la cabecera…
}
String modulos(Client client){
…el código del menú lateral…
}
void body(Client client, String modulo){
… el código del cuerpo de la página…
}

void pie(Client client){
String hora = “”; //definimos la variable de la hora
hora = timestamp(); //llamamos a la función que nos devolverá la hora y asignamos el valor a la anterior variable
client.println(“la hora es: –>” + hora + “<–“); //Mostramos la hora en la web
client.print(“</body></html>”);//cerramos la estructura HTML
}

//Esta es la función para obtener el tiempo y entregar la hora

String timestamp(){
String timestamp = “”;
sendNTPpacket(timeServer); // enviamos un paquete NTP al servidor de tiempo (ver la función más abajo)
delay(500);  //esperamos una respuesta…
if ( Udp.available() ) {  //si recibimos paquete…
Udp.readPacket(packetBuffer,NTP_PACKET_SIZE);  // leemos el paquete del buffer

//El número que nos interesa empieza en el byte 40 del paquete recibido y ocupa 4 bytes, que son dos words. Vamos a extraerlos:
// or two words, long. First, esxtract the two words:

unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combinamos estos dos enteros en un entero largo (Long Integer), que será el tiempo que nos ha devuelto el servidor NTP
unsigned long secsSince1900 = highWord << 16 | lowWord;
//Ahora vamos a convertir el tiempo que nos ha dado el servidor NTP, en tiempo de UNIX, que empieza el 1 de enero de 1970. 70 años de diferencia, que son 2208988800 (veis como era un poco dificil de saber a ojo y que habia que convertir el valor… 😉   )

const unsigned long seventyYears = 2208988800UL;
//restamos 70 años
unsigned long epoch = secsSince1900 – seventyYears;

//Y aquí en la variable “timestamp” creamos una cadena de fecha en formato “dia/mes/año hora:minuto”. Tenemos el tiempo en la variable epoch, y de ahí con las funciones de la librería Time(day, month, year, hour, minute, second) obtenemos los datos que nos van interesando

timestamp = String(day(epoch)) + “/” + String(month(epoch)) + “/” + String(year(epoch)) + ” ” + String(hour(epoch)+2) + “:” + String(minute(epoch)) + “:” + String(second(epoch));
}
return (timestamp);
}

// enviamos una petición NTP al servidor del tiempo en la dirección que nos llega como parámetro
unsigned long sendNTPpacket(byte *address)
{
// ponemos todos los bytes del buffer a 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Inicializamos los valores necesarios para una petición NTP

packetBuffer[0] = 0b11100011;
packetBuffer[1] = 0;
packetBuffer[2] = 6;
packetBuffer[3] = 0xEC;

packetBuffer[12]  = 49;
packetBuffer[13]  = 0x4E;
packetBuffer[14]  = 49;
packetBuffer[15]  = 52;

//todos los campos del paquete NTP tienen valor. Ahora ya lo podemos enviar para solicitar el tiempo al servidor indicado y al puerto 123
Udp.sendPacket( packetBuffer,NTP_PACKET_SIZE,  address, 123); //NTP requests are to port 123
}

 

Espero que os haya sido de interés, de momento vamos preparandonos las funciones que iremos necesitando. En el próximo tutorial veremos como ir almacenando datos en una tarjeta microSD, y nos encontraremos con nuevos problemas…. 🙂

Hasta pronto!