Crear una estacion meteorologica con raspberry pi y un sensor dth11

Ya puestos a trastear con la raspberry y sus conexiones al GPIO, vamos a ver como podemos crear una pequeña estacion meteorologica con la raspberry pi, y un sensor dth11.

Que necesitamos??

Una raspberry pi
Un sensor dth11 (unos 2 € en dealextreme)
Cables para conectarlo

Notas sobre los materiales necesarios
El sensor que utilizo yo, y el que aparece en la imagen, viene con una resistencia de 10k(amarillo violeta rojo oro) incorparada entre el conector de señal y nuestra conexion al gpio. Si lo compramos suelto, habra que hacer un circuito en un protoboard tal como aparece en esta imagen:

Montaje de los componentes:

Conectamos el sensor dth11 al gpio de la raspberry asi:

RPi VCC (pin 1) -> DHT11 pin 1
RPi GPIO4 (pin 7) -> DHT11 pin 2
RPi GND (pin 6) -> DHT11 pin 4 (pin3 si solo tiene 3 pins)
 
Creando un programa para poder acceder al sensor y leer temperatura y humedad:
 
Una vez realizadas las conexiones, vamos a crearnos un programa que realice 
las lecturas, y que nos saque los resultados por la pantalla.
 
He elegido el lenguaje de programacion en C

Instalamos lo necesario:
nota: Todo lo voy a hacer desde el terminal. Esto me permitira hacerlo todo, 
con una conexion SSH hacia mi raspberry.


Me situo en mi directorio HOME
cd ~

Ejecuto estos comandos:
sudo apt-get install git-core build-essential
git clone git://git.drogon.net/wiringPi
cd wiringPi
./build
 
Con esto ya tenemos lista la libreria wiringPi, para poder usar el puerto GPIO 
de la raspberry de una manera mas sencilla
 
Creamos el siguiente archivo con este comando:
nano dth11.c
 
Escribimos el siguiente codigo:
 
------------------------------------------ 
CODIGO DESDE AQUI - Archivo dth11.c
------------------------------------------
 
 //Incluimos librerias necesarias
#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

//Definimos constantes
#define MAX_TIME 85
#define DHT11PIN 7
#define ATTEMPTS 5

//Definimos un vector global
int dht11_val[5]={0,0,0,0,0};

/////////////////////////////////////////////////////////////
//Funcion principal para leer los valores del sensor.
int dht11_read_val(){
uint8_t lststate=HIGH;
uint8_t counter=0;
uint8_t j=0,i;
for(i=0;i<5;i++){
dht11_val[i]=0;
}
pinMode(DHT11PIN,OUTPUT);
digitalWrite(DHT11PIN,LOW);
delay(18);
digitalWrite(DHT11PIN,HIGH);
delayMicroseconds(40);
pinMode(DHT11PIN,INPUT);
for(i=0;i<MAX_TIME;i++){
counter=0;
while(digitalRead(DHT11PIN)==lststate){
counter++;
delayMicroseconds(1);
if(counter==255){
break;
}
}
lststate=digitalRead(DHT11PIN);
if(counter==255){
break;
}
//Las 3 primeras transiciones son ignoradas
if((i>=4)&&(i%2==0)){
dht11_val[j/8]<<=1;
if(counter>16){
dht11_val[j/8]|=1;
}
j++;
}
}

// Hacemos una suma de comprobacion para ver si el dato es correcto. Si es asi, lo mostramos
if((j>=40)&&(dht11_val[4]==((dht11_val[0]+dht11_val[1]+dht11_val[2]+dht11_val[3])& 0xFF))){
printf("%d.%d,%d.%dn",dht11_val[0],dht11_val[1],dht11_val[2],dht11_val[3]);
return 1;
}else{
return 0;
}
}

////////////////////////////////////////////////////////////////
//Empieza nuestro programa principal.
int main(void){
//Establecemos el numero de intentos que vamos a realizar
//la constante ATTEMPTS esta definida arriba
int attempts=ATTEMPTS;

//Si la libreria wiringPi, ve el GPIO no esta listo, salimos de la aplicacion
if(wiringPiSetup()==-1){
exit(1);
}

while(attempts){
//Intentamos leer el valor del gpio, llamando a la funcion
int success = dht11_read_val();

//Si leemos con exito, salimos del while, y se acaba el programa
if (success){
break;
}

//Si no lee con exito, restamos 1, al numero de intentos
attempts--;

//Esperamos medio segundo antes del siguiente intento.
delay(500);
}
return 0;
}
 
------------------------------------------ 
CODIGO HASTA AQUI-------- FIN DE ARCHIVO dth11.c
------------------------------------------
   
Se puede cambiar esto...:
printf("%d.%d,%d.%dn",dht11_val[0],dht11_val[1],dht11_val[2],dht11_val[3]); 

por esto:
printf("%d,%dn",dht11_val[0]*256+dht11_val[1],dht11_val[2]*256+dht11_val[3]); 
 
Y asi saldra correctamente los datos. Gracias a seta43 por el aviso! 
 
Una vez escrito, lo compilamos con el siguiente comando:
gcc -o dth11 dth11.c -L /usr/local/lib -l wiringPi

 
Si compila bien, ejecutamos con este comando:
sudo ./dth11
 
(GRACIAS A seta43 por la advertencia!!, habia confundido dth11 por dht11, asi que cuidar a ver!)
 
Deberia mostrarnos la temperatura, y la humedad separadas por comas.
 
 
Siguiente paso!!!
 
Como lo que nos interesa realmente, es tener unos datos actualizados cada minuto, 
y en forma de grafica, vamos a instalar un servidor web, y crearnos asi una
pagina web donde podamos consultar los resultados que nos dara nuestra medicio
de una forma grafica. Para eso, instalamos apache, y creamos la web necesaria.
 
Instalacion de apache:
 
Ejecutamos el siguiente comando:
apt-get install apache2
 
Arrancamos apache:
service apache2 start
 
Una vez instalado el 
 
 
Creacion automatica de la medicion de temperatura y humedad:

Vamos a crearnos un fichero, para que vaya guardando de forma automatica
los valores de temperatura y humedad, asi como la fecha en la que se ha 
tomado dicha medicion.

Nos situamos de nuevo en el directorio HOME:
cd ~

Creamos el siguiente fichero con el siguiente codigo:
nano dth11.sh

------------------------------------------ 
CODIGO DESDE AQUI - Archivo dth11.sh
------------------------------------------

#!/bin/bash
FECHA=$(date +%Y%m%d%H%M%S)
COMA=","
TEMP=$(/home/usuario/dth11)
echo "$FECHA$COMA$TEMP" >> /var/www/temp.log
 
------------------------------------------ 
CODIGO HASTA AQUI-------- FIN DE ARCHIVO dth11.sh
------------------------------------------ 
 
Con esto lo que hacemos, es un script que nos dara como resultado la fecha
en el formato adecuado, seguido de la temperatura y humedad, y lo almacenara 
en un archivo llamado temp.log, en el directorio raiz de APACHE por defecto, 
para su lectura posterior.
 
Tarea programada con cron
 
A continuacion, le vamos a decir a cron (nuestro programador de tareas en linux), 
que ejecute el script cada minuto. Para eso ejecutamos el siguiente comando:
 
sudo crontab -e
 
Y añadimos la siguiente linea al final:
 
* * * * * /home/usuario/dth11.sh
 
Creamos la pagina web para mostrarnos los resultados leidos:
 
Nos situamos en el directorio de nuestro servidor web con el siguiente comando:
cd /var/www 

Si existe un archivo index.html, lo borramos con el comando:
rm index.html

Descargamos la libreria dygraphs para poder generar la grafica:
wget -P /var/www http://dygraphs.com/dygraph-combined.js
 
Nos creamos el archivo index.html para almacenar la web:
nano index.html
 
------------------------------------------ 
CODIGO DESDE AQUI - Archivo index.html
------------------------------------------
 
 
<html>
<head>
<script type="text/javascript" src="dygraph-combined.js"></script>
</head>
<body>

<h1>Grafica con temperaturas y humedad</h1>

<p>Esta gr&aacute;fica, esta generada a partir de las mediciones tomadas por un sensor dth11, conectado a una raspberry pi. Se accede al sensor mediante lenguaje de programacion C, usando las librerias wiringPi, para poder leer y utilizar el conector GPIO de la raspberry Pi.</p>



<hr/>

<div id="graphdiv" style="width:750px; height:400px;"></div>
<script type="text/javascript">

//Funcion para añadir ceros a los numeros de un solo digito
function addZero(num){
var s=num+"";
if (s.length < 2){
s="0"+s;
}
return s;
}

//Funcion para dar formato a la fecha, devolviendo la misma formateada
function dateFormat(indate){
var hh = addZero(indate.getHours());
var MM = addZero(indate.getMinutes());
//var ss = addZero(indate.getSeconds()); //No usamos los segundos
var dd = addZero(indate.getDate());
var mm = addZero(indate.getMonth()+1);
var yyyy = addZero(indate.getFullYear());
return dd+'/'+mm+' '+hh+':'+MM;
}

//Funcion principal para generar el grafico. Se genera en el id="graphdiv"
g = new Dygraph(
document.getElementById("graphdiv"),
"temp.log",
{
xValueParser: function(x) {
var date = new Date(x.replace(
/^(d{4})(dd)(dd)(dd)(dd)(dd)$/,
'$4:$5:$6 $2/$3/$1'
));
return date.getTime();
},
axes: {
x: {
ticker: Dygraph.dateTicker,
axisLabelFormatter: function(x) {
return dateFormat(new Date(x));
},
valueFormatter: function(x) {
return dateFormat(new Date(x));
}
}
},
labelsDivWidth: 310,
rollPeriod: 30,
strokeWidth: 2.0,
labels: ['Date','Humedad (%)','Temp (&deg;C)']
}
);
</script>

<hr/>

</body>
</html>
 
------------------------------------------ 
CODIGO HASTA AQUI-------- FIN DE ARCHIVO index.html
------------------------------------------
 
Probandolo todo!!!

Si todo va bien, podemos probar que todo esto funciona, desde nuestro navegador
de paginas web, apuntando a la direccion ip de nuestra raspberry

http://ip.de.mi.pi

Deberia aparecer algo como esto:




Resumen:

Espero que os sirva de utilidad. A mi me ha funcionado todo a la perfeccion.

Un saludo a todos!!!


Fuente de informacion:

http://chrisbaume.wordpress.com/2013/02/10/beer-monitoring/

http://dygraphs.com/

http://rpidude.blogspot.com.es/2012/11/temp-sensor-and-wiringpi.html

http://dx.com/es/p/arduino-digital-temperature-humidity-sensor-module-121350

http://ubuntuone.com/6mT9cTREz90BUfvQD1AGNy


Agradecimientos:

Muchas gracias a Alberto, que me ha dejado todo el hardware necesario para poder
hacer mis pinitos con todo esto. Un abrazo!!!