Monitoreo remoto de nivel de agua en tanque hogareño usando ultrasonidos

Javier Navarro
8 min readAug 26, 2018

--

En zonas con crisis hídricas recurrentes como en las Sierras Chicas (provincia de Córdoba), tarde o temprano llegan los cortes rotativos o en el peor de los casos la presión de agua no es suficiente para que el agua llegue al tanque. Monitorear el nivel de agua en los tanques se convierte en una necesidad para evitar sorpresas.

Los tanques en cuestion: dos tanques de 1000 litros instalados en casa. Parece excesivo pero dadas los problemas de suministro es un buena desicion.

Buscando en internet opciones para medir el nivel de agua, y descartando las opciones comprando HW costoso, encontré un caso exitoso en Zapala donde la cooperativa de aguas utilizó un Arduino y un sensor de ultrasonido (link acá).

Si bien el principio es el mismo, realicé algunos cambios para simplificar la instalación y la conectividad. A grosso modo utilicé los siguientes componentes:

  1. Sensor de ultrasonido HC-SR04. El dispositivo que realiza la medición del nivel de agua. Este sensor emite un ultrasonido y calcula el tiempo de rebote. Con matemática simple se puede calcular la distancia contra el objeto. En este caso se utiliza para medir la distancia desde el sensor hasta la superficie del agua. Dado que el sensor va instalado en la tapa, cuanta mas distancia se observa, implica que el nivel de agua es mas bajo.
Sensor HC-SR04

2. Chipset D1 Mini: realiza el calculo de la distancia, se conecta via wifi y transmite el valor a Thingspeak.com

D1 Mini

3. Para dar potencia al chipset descarté llevar 220 volts a los tanques y luego utilizar un conector USB al D1 Mini (por obvios motivos de seguridad). Buscando otras opciones decidí utilizar energía solar. Consta de los siguientes elementos:

  • Pila Recargable de Litio (modelo 18650 de 4200 mAh, $133 en MercadoLibre, link)
  • Placa solar para recargar la pila (~ $240 en MercadoLibre, link)
  • Chip TP4056 para controlar la carga de la pila, incluye protección contra descarga para evitar descarga total, que arruinaría la pila (~ $89 en MercadoLibre, link)
  • Chip Elevador de tension MT3608, para elevar la tension que entrega la pila y la placa solar, a los 5 volts que necesita el chip D1 Mini

Una característica interesante del chip D1 Mini es que puede entrar en “Deep Sleep” para consumir menos energía. Dado que el nivel de agua en el tanque no es algo que cambie minuto a minuto, configuré para que el D1 Mini mida la distancia y luego de enviarla vía WiFi a internet, ingrese al modo “Deep Sleep” durante 15 minutos, al cabo de los cuales debiera despertar (wake up) para repetir el proceso. Con este método el consumo electrico se minimiza por lo que la bateria se descarga menos y no se agota durante la noche o periodos de poca luminosidad solar. Para habilitar el Deep Sleep hay que ejecutar una línea de comando:

ESP.deepSleep(sleepSeconds * 1000000);

Asimismo se deben soldar los terminales D0 y RST en el D1 Mini (requiere soldador y estaño).

Conectando todo

En la foto inferior se pueden observar todos los componentes conectados entre sí. El panel solar entrega energia al TP4056, que a su vez le entrega energia a la pila (ambos arriba a la derecha ) y a su vez la traspasa al elevador de tensión (a la derecha), que a su vez le entrega los 5v al chip D1 mini (abajo a la izquierda). Finalmente, el sensor HC-SR04 (arriba a la izquierda, con el sensor apuntando hacia abajo) es el que realiza la medición y se la entrega al chip D1 Mini que lo transmite via wifi.

Instalación

El primer intento resultó en instalar el panel solar en el exterior de la tapa del tanque, dentro de un panel de plexiglás para protegerlo de la lluvia o granizo. La caja estanca en el centro de la tapa fue solo para proteger el pasaje del cable.

Instalación — Se aprecia el panel solar

Del lado interno de la tapa se atornilló la segunda caja estanca, conteniendo el sensor de ultrasonido, la pila y el chip D12 mini. Se observa en la foto el sensor apuntando hacia la superficie del agua.

Instalación — Interior de la tapa — se aprecia el sensor ultrasonico asomando de la caja estanca

Se observaron dos problemas: primero, el sensor estaba en el centro de la tapa, y tenia dudas sobre si la boya de flotacion que estaba muy cerca del centro podria llegar a quedar en el camino del ultrasonido, lo que imposibilitaría “pegarle” al agua. El segundo problema, y más grave, fue que la no había conectividad al router desde la ubicacion del tanque. El motivo es que los volumenes de agua absorben la señal de WIFI (en especial la banda de 2.4 GHZ de la mayoria de los routers hogareños). Si bien mi router es multibanda (2.4 y 5 GHZ), el chip D1 Mini trabaja solo en 2.4.

Para salvar este problema decidí separar fisicamente el sensor de ultrasonido del resto de los componentes por varios metros. Para ello reutilicé un patch-cord de red que tenia guardado. Si bien tenia dudas sobre cuanta distancia soportaria la señal sin degradarse, funcionó bien.

Caja estanca con el Chip D1 Mini, Pila y demás chips mas lejos del tanque

Al segundo intento, quitando todos los componentes fuera del tanque -apoyándolos contra la pared-, tampoco funcionó. Tras varios intentos descubri un dark-spot donde cerca de las paredes tampoco llegaba la señal (el router y un extender estaban en linea recta a no mas de 7–8 metros pero igual la señal no llegaba).

Al tercer intento opté por usar un cable patch cord mas largo para poder ubicar la caja a un lugar donde no quedaba bloqueado para conectarse al wifi.

Finalmente, la conectividad quedó resuelta. La instalación en la tapa del tanque quedo simplificada a sólo un orificio para pasar el cable (ver abajo). Le agregué dos protecciones plásticas para evitar el pasaje de agua al interior del tanque. Cabe aclarar que los dos tanques están conectados entre si, por lo que por el efecto de los famosos “vasos comunicantes” el nivel de agua es el mismo en ambos, de este modo puedo medir el nivel total utilizando un solo sensor.

Código Fuente

El código fuente completo esta subido a GitHub para los que quieren curiosear. Se carga en en el IDE de Arduino y se selecciona el board D1 Mini, se sube el código via USB y voilá. Nota: cabe aclarar que no soy programador por lo que seguro hay 1000 veces mejores maneras de realizar la misma tarea incluso con menos código.

La funcionalidad clave para obtener la distancia esta contenida en la funcion:

long getDistance() {                         
initialize_variables();
for (i=0; i<qtysamples;i++) {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = (duration / 2) * 0.0343;
samples[i]=-1;
if (distance >= 400 || distance <= 2) {
if (enablelogging) Serial.println("Out of range, duration = ");
} else {
if (enablelogging) {
Serial.print(i);
Serial.print(": ");
Serial.print(" distance=");
Serial.print( distance);
Serial.println(" cm"); }
samples[i]=distance;
delay(100);
} }
if (enablelogging) Serial.println(" START PROCESSING----");
qtystats=0;
for (i=0; i<qtysamples; i++) {
if (samples[i]==-1) break;
for (j=0; j<qtystats;j++) {
if (stats[j][0]==samples[i]) {
stats[j][1]++;
break;
}
}
if (j>=qtystats) {
stats[qtystats][0]=samples[i];
stats[qtystats][1]=1;
qtystats++;
}
}
maxqty=-1;
maxqtyindex=-1;
for (j=0; j<qtystats;j++) {
if (enablelogging) {
Serial.print(stats[j][0]);
Serial.print(" qty.: ");
}
if (stats[j][1]>maxqty) {
maxqty=stats[j][1];
maxqtyindex=j;
if (enablelogging) Serial.print(" *");
}
if (enablelogging) Serial.println(stats[j][1]);
}
if (enablelogging) Serial.print(" Most reported distance: ");
if (maxqty != -1 && maxqty > 1) {// more than 1 obs for same dist
if (enablelogging) {
Serial.println(stats[maxqtyindex][0]);
Serial.println(" END LOOP -------------");
}
return stats[maxqtyindex][0]; }
else {
if (enablelogging) Serial.println(" END LOOP -------------");
return -1;
}
}

La primera parte de la función realiza 20 lecturas de distancia seguidas, luego en la segunda parte de la función las procesa para identificar la lectura que mas se repite. El motivo de esta lógica es que el sensor de ultrasonido tiene un margen de error pronunciado, por lo que para descartar metricas outliers, se realizan varias lecturas y se identifica las mas probable como la que tuvo mas repeticiones. Caso contrario devuelve un -1 y se ignora.

El resto de la funcionalidad realiza la conectividad a la red hogareña, y contiene la API Key de Thingspeak

String apiKey = "XXXXXXXXX";
const char* ssid = "XXXXX";
const char* password = "XXXXXXXXXXXXX";
const char* server = "api.thingspeak.com";

Puesta en marcha

Basta conectar la bateria y la placa solar para observar las metricas comenzar a aparecer en Thingspeak. El canal es público (link) por lo que cualquiera puede observar en tiempo real el nivel de agua en los tanques de casa.

Para probar diferentes escenarios procedí a cerrar la llave de paso en la vereda, por lo que puedo observar como se va consumiendo el agua de los tanques (los números son la distancia del sensor a la superficie del agua, en la última lectura indica ~32cm desde el sensor al agua).

Una vez subidos los datos a ThinkSpeak, via APIs REST se puede realizar cualquier acción que se desee. En mi caso, lo importo en un InfluxDB y un Grafana dentro de una RaspberriPi, para poder hacer gráficos mas dinámicos:

Empíricamente puedo decir que consumí 211 litros en dos días, lo que permite inferir empíricamente que los dos tanques me deberían durar entre 15 y 20 días dependiendo el uso.

Esto es todo! Cualquier duda pueden consultarlo con comentarios en esta nota o a mi email javier.e.navarro (en) gmail.com.

--

--

Javier Navarro

Lector ávido, programador hobbista, fan de la música en todas sus formas. [javier.e.navarro (at) gmail.com]