Por fin podemos hablar de el primer proyecto más o menos serio que he hecho con ESP8266 y esta vez se trata de un medidor de nivel agua con los datos guardados en la nube, de manera que sean accesibles desde cualquier sitio.
Principios de funcionamiento
Para empezar, imaginemos que tenemos una cisterna donde tenemos agua. Primero debemos asumir que las medidas de la cisterna se mantienen constantes en todo momento, esto es, ancho, largo y alto. Para conocer el volumen de agua que reside en el interior tan solo necesitaremos saber cuál es la altura del agua, ya que es la única variable del sistema.
Con esto claro, necesitamos un mecanismo que sea capaz de medir a qué altura de encuentra el agua. Mi idea ha sido utilizar un sensor ultrasónico, cuyo funcionamiento es el siguiente:
- El altavoz emite un sonido de frecuencia ultrasónica (imperceptible al oido humano)
- Se pone un cronómetro en marcha.
- El micrófono recibe la señal que había sido emitida por el altavoz.
- Se para el cronómetro que se había puesto en marcha al emitir el sonido
- Se calcula sabiendo la velocidad del sonido, la distancia a la que está el objeto sobre el cual ha rebotado la pulsación ultrasónica.
Materiales
Para empezar los materiales que he utilizado son:
- ESP-01 (ESP8266)
- Fuente de alimentación de 3.3V
- Fuente de alimentación de 5V
- Programador FTDI
- Sensor ultrasónico HC-SR04
Montaje hardware
El módulo ultrasónico HC-SR04 tiene 4 pines:
- Vdd: debemos conectar 5V. No podemos conectar directamente los 3.3V con los que alimentamos el ESP-01. Una lástima.
- Trig: es el encargado de dar la orden al altavoz de que emita el pulso.
- Echo: es el micrófono que espera el rebote del pulso emitido.
- GND: es importante unificar la masa del ESP-01 con la propia de la fuente de 5V para evitar problemas de grounding.
En mi caso he utilizado los 5V que tiene disponible el Arduino, aunque es algo bastante engorroso. Para la versión final, utilizaré un convertidor lineal (para conseguir los 3.3V) y una sola alimentación.
La conexión entre el ESP-01 y el HC-SR04 es extremadamente sencilla:
- GPIO0 – Echo
- GPIO2 – Trig
Software
Para hacer funcionar el HC-SR04 con NodeMCU, he utilizado el código que ha subido sza2 en GitHub modificándolo un poco.
Se trata de dos archivos: init.lua y hcsr04.lua. Cabe destacar que el ESP8266 ejecuta init.lua en cuanto se enchufa. La base de su funcionamiento reside en el uso de la función tmr.alarm(), que ejecuta una función cada intervalo de tiempo que nosotros definamos. En este caso, la función de medir distancia.
tmr.alarm(0, 3600000, 1, function() send(device.measure()) end)
El código de sza2 envía vía serie el resultado cada 0,5s, pero podemos configurarlo como nosotros queramos. Solo recordar que hay que introducir el tiempo en milisegundos.
En el código original se imprime por pantalla el resultado, pero como hemos dicho anteriormente nuestro objetivo es que la lectura sea subida a un servidor para poder ver el nivel de agua desde cualquier sitio.
Para ello he utilizado una plataforma llamada ThingSpeak, que sirve precisamente para esto. Su funcionamiento es muy sencillo. La información se guarda en los que ThingSpeak llama canales. En cada canal podemos añadir hasta 8 variables que queramos monitorizar, y la manera en que podemos guardar nuevos datos es haciendo una petición HTTP con el método GET. Las variables que tenemos que incluir en la petición HTTP es el código del canal (para saber dónde hay que guardar la información), el número del campo a guardar seguido del valor.
conn:send("GET /update?key=CodigoAPI&field1="..value1.." &field2="..value2.."HTTP/1.1\r\n")
De esta manera quedará registrado automáticamente en ThingSpeak, como podemos ver en este applet:
También decir que el HC-SR04 devuelve valores contiguos que difieren unos de otros por motivos obvios, por lo que he modificado el código para que devuelva el valor medio de 500 medidas.
El código completo del archivo init.lua es:
dofile("hcsr04.lua") wifi.setmode(wifi.STATION) wifi.sta.config("SSID","pass") print(wifi.sta.getip()) device = hcsr04.init() print("Loading...") function send(value) if value ~= -1 then print(value) conn=net.createConnection(net.TCP, 0) conn:on("receive", function(conn, payload) print(payload) end) conn:connect(80,'184.106.153.149') conn:send("GET /update?key=CodigoAPI&field1="..value.." HTTP/1.1\r\n") conn:send("Host: api.thingspeak.com\r\n") conn:send("Accept: */*\r\n") conn:send("User-Agent: Mozilla/4.0 (compatible;ESP8266; Windows NT 5.1)\r\n") conn:send("\r\n") end end tmr.alarm(0, 60000, 1, function() send(device.measure()) end)
hcsr04 = {}; function hcsr04.init(pin_trig, pin_echo) local self = {} self.time_start = 0 self.time_end = 0 self.trig = pin_trig or 4 self.echo = pin_echo or 3 gpio.mode(self.trig, gpio.OUTPUT) gpio.mode(self.echo, gpio.INT) function self.echo_cb(level) if level == 1 then self.time_start = tmr.now() gpio.trig(self.echo, "down") else self.time_end = tmr.now() end end function self.measure() medidas = 500 mean = 0 for i=1,medidas,1 do gpio.trig(self.echo, "up", self.echo_cb) gpio.write(self.trig, gpio.HIGH) tmr.delay(100) gpio.write(self.trig, gpio.LOW) tmr.delay(100000) if (self.time_end - self.time_start) < 0 then return -1 end mean = mean + (self.time_end - self.time_start) / 58 end print(mean/medidas) return mean/medidas end return self end
Amigo como puedo conectar ese sensor solo parA medir distancias, tienes algun Codigo sencillo sin eso del host online.y ese lo has usado. Con blynk? Como
Hola Josue,
Gracias por tu comentario. Todo depende de cómo quieras leer las medidas. Siempre puedes utilizar el puerto serie para enviar las lecturas al ordenador o utilizar cualquier API REST de servicios como Blynk, Sparkfun, etc.
Saludos,
R
buena pero el ESP8266 funciona a 3.3v y el sensor a 5 v el pulso que embia el sensor no es de 5v eso no puede quemar el modulo
hola muy bueno tu proyecto, sabes como puedo programar un sensor de flujo de agua para que levante una bomba de agua a una determinada presión, es para evitar que levante por fugas en el circuito y levante solo al abrir una llave, gracias.
Te agradezco mucho tu trabajo y quisiera preguntarte porque siempre me da como resultado -1, conecto el hcsr04 a los GPIOS directamente, pero no logro que tome la medida, Gracias de antemano
Yo modifique un poco el codigo para que jalara igual ya esta desactualizado este codigo en la parte de los alarm:
hcsr04 = {};
function hcsr04.init(pin_trig, pin_echo, average)
local self = {}
self.time_start = 0
self.time_end = 0
self.trig = pin_trig or 5
self.echo = pin_echo or 6
gpio.mode(self.trig, gpio.OUTPUT)
gpio.mode(self.echo, gpio.INT)
self.average = average or 2
function self.echo_cb(level)
if level == 1 then
self.time_start = tmr.now()
gpio.trig(self.echo, «down»)
else
self.time_end = tmr.now()
end
end
function self.measure()
medidas = 300
mean = 0
for i=1,medidas,1 do
gpio.trig(self.echo, «up», self.echo_cb)
gpio.write(self.trig, gpio.HIGH)
tmr.delay(100)
gpio.write(self.trig, gpio.LOW)
if (self.time_end – self.time_start) < 0 then
return -1
end
mean = mean + (self.time_end – self.time_start) / 58
end
print (medida)
return (mean/medidas)
end
return self
end