Hace tiempo que tengo un sensor de temperatura y humedad DTH11 dando vueltas por los cajones, así que ha llegado el momento de probarlo. Junto con un Arduino y un módulo Wifly, voy a mostraros un sensor de temperatura y humedad que envíe datos periódicamente por WiFi a un servidor. Es la base de cualquier proyecto enmarcado en el Internet de las cosas (IoT).
El sensor DHT11
Este sensor es muy barato y fácil de usar, así que es perfecto para un pequeño proyecto como éste. El siguiente esquema sacado del datasheet del fabricante muestra cómo ha de conectarse el sensor.
Se puede encontrar en versión de tres y cuatro patillas. En la versión de cuatro, una simplemente está desconectada y no se utiliza. Además de los dos pines de alimentación (a 5V), la información se transmite por un único pin conectado al microcontrolador a través de una resistencia pull-up de 5K. En mi diseño he añadido un condensador entre VCC y GND para filtrar la entrada de alimentación. En la fotografía de la cabecera se ve el montaje completo en la protoboard.
Módulo Wifly
Para enviar los datos al servidor tenemos varias opciones como Bluetooth o GSM. Pero como tenía un módulo Wifly a mano, lo haremos por WiFi. Esta basado en el chip RN-171, que está muy probado y es bastante robusto. Además de tener una gran cantidad de funcionalidades. En este proyecto sólo vamos a mostrar su uso más básico, para el cuál sólo necesitamos cuatro conexiones, dos para la alimentación (a 3.3V) y otras dos para al comunicación serie (TX y RX). Si ya has trabajado con un módulo XBee, Wifly es totalmente compatible a nivel de conexiones, por lo que podrías sustituir uno por otro sin tener que modificar el resto del circuito.
Montaje con Arduino
El montaje del sensor DHT11 y Wifly con Arduino se muestra en el siguiente esquema. Como ves no hay nada fuera de lo común, lo único más delicado es la conexión del módulo Wifly, cuyas patillas son más pequeñas y están más juntas de lo habitual, lo que es un poco problemático para conectarlo con cables dupont, pero forzando un poquito no hay mayor problema.
El sensor se alimenta de la salida de 5V del Arduino, cuya patilla central por donde van los datos de temperatura he conectado al pin 7 del Arduino. El módulo Wifly lo he conectado al pin de 3.3V del Arduino (cuidado con no conectarlo al de 5V si no queréis freír el módulo Wifly). Los pines RX y TX del Wifly se pueden conectar directamente a los pines RX y TX de Arduino (pines 0 y 1), pero yo he preferido usar un puerto serie por software (pines 2 y 3) y dejar libre el puerto serie nativo para depurar la comunicación con el Wifly. El montaje completo queda así.
Funcionamiento
El código encargado de de leer el sensor y enviar los datos por el puerto serie al Wifly es el siguiente.
#include "DHT.h" #include #define DHTPIN 7 // Pin // Tipo de sensor #define DHTTYPE DHT11 // DHT 11 // Inicializar sensor DHT dht(DHTPIN, DHTTYPE); SoftwareSerial wifly(2, 3); // RX, TX void setup() { Serial.begin(9600); // usamos serial normal para debug wifly.begin(9600); dht.begin(); // Preparar Wifly delay(5000); // esperamos a que wifly esté listo wifly.print("$$$"); // entrar en modo comando delay(1000); wifly.println("join myssid"); // nos asociamos al ssid delay(2000); wifly.println("set com remote 0"); // evitar que se envíe la cadena HELLO al servidor delay(1000); } void loop() { float h = dht.readHumidity(); float t = dht.readTemperature(); // por defecto en Celsius // Comprobar si hay error if (isnan(h) || isnan(t) ) { Serial.println("Error de lectura en el sensor"); return; } // Calculo de la sensación térmica // float hic = dht.computeHeatIndex(t, h, false); wifly.println("open 172.26.0.9 8080"); // abrimos conexión al servidor web delay(1000); wifly.println("GET /readsensor?t="+String(t,2)+"&h="+String(h,2)+" HTTP/1.1"); wifly.println(); delay(60000); // leer cada minuto wifly.print("$$$"); }
En la función setup() se inicializa el sensor DHT11 y se realiza la conexión del módulo Wifly a la red WiFi. En este caso es una red WiFi abierta y sin protección, por lo que no es necesario establecer la clave de cifrado. Para conectar a una red WiFi cifrada habrá que realizar algún paso más que puede consultarse en el manual de WiFly.
Una vez en marcha, la función loop() lee cada minuto el valor de temperatura y humedad del sensor y se envía al servidor como una petición GET mediante HTTP. El servidor, como veremos enseguida, registra cada petición y almacena los datos. Quiero hacer notar que este código es ilustrativo y que no es válido para un sistema en producción ya que, además de no ser muy óptimo (entre otras cosas por ese delay de un minuto), tampoco se comprueban errores de comunicación o se chequea el estado del módulo Wifly.
Como servidor web se podría haber usado Apache con PHP, Tomcat con Java o cualquier otra alternativa. Para simplificar he usado el pequeño servidor web que trae Python (para un sistema en producción habría que usar algo más serio). El código es el siguiente:
#!/usr/bin/python from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer import urlparse import datetime PORT_NUMBER = 8080 datos=[] class myHandler(BaseHTTPRequestHandler): # Manejador para peticiones GET def do_GET(self): if "readsensor" in self.path: o = urlparse.urlparse(self.path) params = urlparse.parse_qs(o.query) t = params["t"][0] h = params["h"][0] now = datetime.datetime.now() datos.append([str(now.hour)+":"+str(now.minute), t, h]); self.send_response(200) self.send_header('Content-type','text/html') self.end_headers() self.wfile.write('Temperatura: '+t) self.wfile.write('<BR>Humedad: '+h) self.wfile.write("<BR>OK!") return else: # gerenar datos muestra = "['Hora', 'Temperatura', 'Humedad']," for d in datos: muestra=muestra + "['"+d[0]+"',"+d[1]+","+d[2]+"]," self.send_response(200) self.send_header('Content-type','text/html') self.end_headers() self.wfile.write(""" <html> <head> <script type='text/javascript' src='https://www.gstatic.com/charts/loader.js'></script> <script type='text/javascript'> google.charts.load('current', {'packages':['corechart']}); google.charts.setOnLoadCallback(drawChart); function drawChart() { var data = google.visualization.arrayToDataTable([""" + muestra +"""]); var options = { title: 'Registro humedad/temperatura', curveType: 'function', legend: { position: 'bottom' } }; var chart = new google.visualization.LineChart(document.getElementById('curve_chart')); chart.draw(data, options); } </script> </head> <body> <div id='curve_chart' style='width: 900px; height: 500px'></div> </body> </html> """); try: server = HTTPServer(('', PORT_NUMBER), myHandler) print 'Iniciando servidor HTTP en puerto ' , PORT_NUMBER server.serve_forever() except KeyboardInterrupt: print 'CTRL+C: Saliendo...' server.socket.close()
Se utiliza la librería BaseHTTPServer de Python para crear el servidor web escuchando en el puerto 8080. En el manejador de peticiones se distinguen dos tipos, si se trata de una lectura del sensor (es una llamada GET con readsensor en la URL) se almacena la información. En caso contrario se muestra una gráfica en pantalla con las mediciones. Para generar la gráfica he optado por la librería Javascript Google Charts.
Más allá del prototipo
Para ir un paso más allá, además de mejorar el software tanto en el Arduino como en el servidor, habría que hacer algunas mejoras. De entrada, eliminar el Arduino y sustituirlo por un Atmega328P junto con su circuiteria en una placa de circuito impreso. En lugar del módulo Wifly usaríamos un RN171 también en la placa, y probablemente con una antena externa. Finalmente, nos queda el asunto de la alimentación. Tanto si vamos a usar una pila como alimentación a través de un transformador o incluso una fuente de alimentación, necesitaremos al menos un regulador de tensión tipo 7805 para obtener los 5V para el sensor. Para obtener los 3.3V del RN171, podemos usar un 7833 o, si queremos ahorrárnoslo, un divisor de tensión para obtener 3.3V a partir del 7805. Pues con esto y una bonita caja, ya estaría listo nuestro dispositivo IoT.
Veo que en el proyecto utilizaste un capacitor. Tengo tres dudas al respecto. ¿Podrías decirme de qué tipo es? ¿De cuánto es su capacidad de conservación? ¿Es completamente necesario para este proyecto?
Si no recuerdo mal, era un condensador cerámico de 22 picofaradios. No recuerdo bien por qué decidí ponerlo (supongo que para filtrar algo la alimentación del circuito), pero estoy casi seguro de que si no lo pones, el montaje funciona sin problemas.
Una consulta soy nuevo en el tema, pero si hay la posibilidad de poder guardar en una Base de Datos SQL y de ahí poder mostrar en una interfaz al usuario. De antemano gracias por el aporte espero me sepan contestar.
En principio no hay problema para que desde el programa Python puedas almacenar los datos que llegan desde el sensor en una base de datos (de hecho es lo más lógico). Python puede «hablar» con diferentes bases de datos, por ejemplo con sqlite: https://docs.python.org/2/library/sqlite3.html