Sensor de nivel de agua Arduino: calibración, alarma y bomba
Sensor de nivel de agua con Arduino: calibración vacío/medio/lleno, alimentación por pin contra la corrosión, alarma con zumbador, bomba y código ESP32/Pico.
Un sensor de nivel de agua es la forma más barata y sencilla de detectar con Arduino hasta dónde llega el agua en un vaso, un acuario, el plato de una maceta o un depósito pequeño. A medida que las pistas conductoras descubiertas de la placa se sumergen, sube la tensión en su salida analógica; Arduino lee esa tensión con analogRead() y decide si el recipiente está «vacío», «a medias» o «lleno». Se conecta con tres cables, funciona con unas pocas líneas de código y es la base de muchos proyectos, desde alarmas de desbordamiento hasta el control automático de una bomba.
En esta guía verás qué hay dentro del módulo, por qué la lectura nunca llega a 1023, cómo hacer la calibración vacío/medio/lleno y cómo evitar la corrosión que destroza el sensor en pocas semanas. Después montarás una alarma de desbordamiento con zumbador y un control de bomba que rellena un depósito por sí solo, lo compararás brevemente con un interruptor de flotador y con el XKC-Y25 sin contacto y, por último, verás cómo hacer lo mismo con el ESP32 y la Raspberry Pi Pico.

¿Qué es un sensor de nivel de agua y cómo funciona?
La parte inferior del módulo tiene diez pistas conductoras que no se tocan entre sí y se entrelazan como los dientes de dos peines. Cinco son pistas de alimentación unidas al +, y las otras cinco son pistas de detección que van a la base del transistor NPN S8050 situado en la parte superior de la placa. Con la placa seca solo hay aire entre las pistas, el transistor está cortado y el pin S queda cerca de 0 V. Al sumergirla, el agua une las pistas de alimentación con las de detección; una pequeña corriente entra en la base, el transistor empieza a conducir y sube la tensión de la salida S, que se toma del emisor. Cuanto más sube el agua, más longitud de pista se moja, menor es la resistencia entre las pistas y mayor la tensión de salida.
Este funcionamiento tiene tres consecuencias importantes. La primera es que el sensor no mide realmente el agua, sino su conductividad: los minerales disueltos en el agua del grifo elevan la lectura, mientras que el agua pura (destilada) apenas da valor. La segunda es que la salida procede de un transistor en configuración de seguidor de emisor, así que la tensión nunca alcanza la de alimentación; un sensor totalmente mojado y alimentado a 5 V suele leer entre 500 y 650 en un Arduino Uno y nunca se acerca a 1023. La tercera es que la relación no es lineal: el valor sube rápido en los primeros milímetros y luego cada vez más despacio. Por eso este sensor no es una regla con precisión milimétrica, sino un indicador práctico que distingue unos pocos niveles con fiabilidad.
| Característica | Valor |
|---|---|
| Tensión de funcionamiento | 3,3–5 V CC |
| Corriente de funcionamiento | Menos de 20 mA (máxima cuando está totalmente mojado) |
| Salida | Tensión analógica (pin S), aumenta al subir el agua |
| Zona de detección | Unos 40 × 16 mm, es decir, como máximo unos 4 cm de altura de agua |
| Tamaño de la placa | Unos 62 × 20 mm |
| Temperatura de trabajo | 10–30 °C (dato del fabricante) |
| Pines | S (señal), + (VCC), − (GND) |
Conexión del sensor de nivel de agua: Arduino Uno, ESP32 y Pico
| Pin del sensor | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| S (señal) | A0 | GPIO 34 (ADC1) | GP26 (ADC0) |
| + (VCC) | D7 (lo alimenta solo al medir) | GPIO 25 | GP15 |
| − (GND) | GND | GND | GND |
La forma más fácil de evitar la corrosión es alimentar el sensor desde un pin digital, como ves en la tabla: el código pone el pin en HIGH justo antes de medir, espera 10 ms, lee el valor y vuelve a ponerlo en LOW. En un sistema que mide una vez por segundo, las pistas solo están con tensión el 1 por ciento del tiempo, lo que frena el desgaste unas cien veces. Totalmente mojado, el módulo consume como mucho unos 20 mA. El límite recomendado para un pin del Arduino Uno es de 20 mA y el máximo absoluto de 40 mA, y el pin solo está encendido unos milisegundos, así que esta conexión es segura; los pines del ESP32 también dan esta corriente sin problema. Los pines de la Pico, en cambio, trabajan por defecto con una intensidad de salida menor, por lo que con el sensor totalmente mojado la tensión del pin baja un poco y las lecturas son más pequeñas. Mientras calibres con el mismo cableado no es un problema; si quieres valores más estables, puedes conmutar el + del sensor con un pequeño transistor PNP como el BC557: el emisor va al pin 3V3 de la placa, el colector al + del sensor y la base al pin GPIO a través de una resistencia de 1 kΩ; en ese caso el sensor se enciende cuando el pin está en LOW. Para elegir el transistor adecuado, echa un vistazo a la herramienta de transistores.
Paso a paso: la primera lectura con Arduino
- Conecta el pin S del sensor a A0, el pin + a D7 y el pin − a GND. Mantén la placa vertical, con las pistas hacia abajo.
- Abre el código de abajo en el Arduino IDE, elige Arduino Uno como placa y el puerto correcto, y súbelo.
- Abre el Monitor Serie y ajústalo a 9600 baudios. Comprueba que, con el sensor seco, el valor está cerca de 0.
- Sumerge el sensor poco a poco en un vaso de agua: primero solo la punta, luego hasta la mitad y después hasta la línea donde terminan las pistas. En cada paso espera unos segundos y apunta el valor.
1const int SENSOR_PIN = A0; // S → A0
2const int POWER_PIN = 7; // + → D7 (yalnızca ölçerken besle / power only while measuring)
3
4int readSensor() {
5 digitalWrite(POWER_PIN, HIGH); // sensörü aç / power the sensor
6 delay(10); // değerin oturmasını bekle / let the reading settle
7 long sum = 0;
8 for (int i = 0; i < 8; i++) { // 8 ölçümün ortalaması / average of 8 readings
9 sum += analogRead(SENSOR_PIN);
10 }
11 digitalWrite(POWER_PIN, LOW); // sensörü kapat / power off
12 return sum / 8;
13}
14
15void setup() {
16 pinMode(POWER_PIN, OUTPUT);
17 digitalWrite(POWER_PIN, LOW); // kapalı başla / start powered off
18 Serial.begin(9600);
19}
20
21void loop() {
22 int raw = readSensor();
23 Serial.print("Ham deger / Raw value: ");
24 Serial.println(raw);
25 delay(1000); // saniyede bir ölç / measure once a second
26}La función readSensor() mantiene el sensor encendido solo unos 11 ms en cada medida. La espera de 10 ms deja que el transistor y el agua entre las pistas se asienten en un valor estable; después, la media de 8 lecturas suaviza las pequeñas fluctuaciones de cada muestra. En el Uno cada analogRead() tarda unos 0,1 ms, así que 8 lecturas llevan menos de 1 ms. Si remueves el agua o mueves el vaso, verás que los valores bailan en el Monitor Serie; es normal, porque la superficie en movimiento cambia continuamente la longitud mojada de las pistas.
Vacío, medio, lleno: cómo calibrar el sensor
No uses tal cual los umbrales de códigos que encuentres por internet; cada sensor, cada tipo de agua y cada tensión de alimentación dan valores distintos. Calibra en el recipiente donde de verdad se usará el sensor y con la misma agua: agua del acuario para el acuario, agua con abono para un depósito de riego con abono. Marca con un rotulador líneas a 0, 10, 20, 30 y 40 mm sobre el sensor, sumerge la placa hasta cada línea, espera 3–4 segundos a que el valor se estabilice y apunta el número del Monitor Serie. La tabla muestra rangos típicos para agua del grifo y 5 V; anota tus propios valores al lado.
| Nivel | Profundidad sumergida | Valor típico en Uno (5 V, agua del grifo) |
|---|---|---|
| Vacío | 0 mm (seco) | 0–20 |
| Bajo | Unos 5–10 mm | 250–400 |
| Medio | Unos 20 mm | 400–480 |
| Lleno | Unos 40 mm (línea donde terminan las pistas) | 480–650 |
Lo que llama la atención en la tabla es lo rápido que suben los valores en el primer centímetro y lo apretados que quedan después: entre 0 y 10 mm puede haber varios cientos de unidades de diferencia, pero entre 20 y 40 mm solo unas pocas decenas. Por eso, en lugar de trazar una sola recta con map(), la interpolación lineal por tramos, que usa una proporción distinta entre cada par de puntos medidos, da un resultado mucho más preciso. El código siguiente guarda los cinco puntos que mediste en dos arrays, convierte el valor bruto en milímetros y escribe el nivel por su nombre. Solo tienes que poner tus propias lecturas en el array RAW, de menor a mayor.
1const int SENSOR_PIN = A0;
2const int POWER_PIN = 7;
3
4// Kendi kalibrasyon ölçümlerin / your own calibration readings
5const int N = 5;
6const int RAW[N] = {0, 330, 440, 490, 520}; // ham değer, küçükten büyüğe / raw value, ascending
7const int MM[N] = {0, 10, 20, 30, 40}; // batma derinliği (mm) / immersion depth (mm)
8
9int readSensor() {
10 digitalWrite(POWER_PIN, HIGH);
11 delay(10);
12 long sum = 0;
13 for (int i = 0; i < 8; i++) sum += analogRead(SENSOR_PIN);
14 digitalWrite(POWER_PIN, LOW);
15 return sum / 8;
16}
17
18int rawToMm(int raw) {
19 if (raw <= RAW[0]) return MM[0];
20 for (int i = 1; i < N; i++) {
21 if (raw <= RAW[i]) { // iki nokta arasında oran kur / interpolate between two points
22 return map(raw, RAW[i - 1], RAW[i], MM[i - 1], MM[i]);
23 }
24 }
25 return MM[N - 1]; // en üst noktanın üstü / above the top point
26}
27
28const char* levelName(int mm) {
29 if (mm < 3) return "Bos / Empty";
30 if (mm < 15) return "Az / Low";
31 if (mm < 30) return "Yarim / Half";
32 return "Dolu / Full";
33}
34
35void setup() {
36 pinMode(POWER_PIN, OUTPUT);
37 digitalWrite(POWER_PIN, LOW);
38 Serial.begin(9600);
39}
40
41void loop() {
42 int raw = readSensor();
43 int mm = rawToMm(raw);
44 Serial.print(raw);
45 Serial.print(" -> ");
46 Serial.print(mm);
47 Serial.print(" mm, ");
48 Serial.println(levelName(mm));
49 delay(1000);
50}Alarma de desbordamiento con zumbador
Una de las tareas más útiles de un sensor de nivel de agua es avisar de un desbordamiento: colocado bajo la lavadora o la caldera, en el plato de una maceta, en la bandeja de condensados del aire acondicionado o en el borde de un cubo que se está llenando, el sensor dispara la alarma en cuanto el agua toca su punta. Para ello basta incluso con el nivel «bajo» de la tabla de calibración. El código de abajo usa un zumbador activo y el LED integrado del Uno; cuando el valor supera ALARM_ON, el zumbador suena cada cuarto de segundo, y cuando baja de ALARM_OFF, se calla. Como para los tiempos se usa millis() en lugar de delay(), la medición y el zumbador no se bloquean entre sí. Sobre los tipos de zumbador tienes ¿Qué es un buzzer? y sobre la idea de millis(), millis() y delay().
1const int SENSOR_PIN = A0; // S → A0
2const int POWER_PIN = 7; // + → D7
3const int BUZZER_PIN = 8; // aktif buzzer + ucu / active buzzer +
4const int LED_PIN = 13; // Uno'nun dahili LED'i / Uno's built-in LED
5
6const int ALARM_ON = 200; // bu değer ve üstü taşma / at or above: overflow (kendin ölç / measure yours)
7const int ALARM_OFF = 100; // bunun altına inince alarm biter / alarm clears below this
8
9bool alarmActive = false;
10bool buzzerOn = false;
11unsigned long lastRead = 0;
12unsigned long lastBeep = 0;
13
14int readSensor() {
15 digitalWrite(POWER_PIN, HIGH);
16 delay(10);
17 long sum = 0;
18 for (int i = 0; i < 8; i++) sum += analogRead(SENSOR_PIN);
19 digitalWrite(POWER_PIN, LOW);
20 return sum / 8;
21}
22
23void setup() {
24 pinMode(POWER_PIN, OUTPUT);
25 pinMode(BUZZER_PIN, OUTPUT);
26 pinMode(LED_PIN, OUTPUT);
27 digitalWrite(POWER_PIN, LOW);
28 Serial.begin(9600);
29}
30
31void loop() {
32 unsigned long now = millis();
33
34 if (now - lastRead >= 1000) { // saniyede bir ölç / measure once a second
35 lastRead = now;
36 int level = readSensor();
37 if (!alarmActive && level >= ALARM_ON) alarmActive = true; // taşma başladı / overflow started
38 if (alarmActive && level < ALARM_OFF) alarmActive = false; // su çekildi / water receded
39 Serial.print("Seviye / Level: ");
40 Serial.println(level);
41 }
42
43 if (alarmActive) {
44 if (now - lastBeep >= 250) { // 250 ms öt, 250 ms sus / 250 ms on, 250 ms off
45 lastBeep = now;
46 buzzerOn = !buzzerOn;
47 digitalWrite(BUZZER_PIN, buzzerOn ? HIGH : LOW);
48 }
49 } else if (buzzerOn) {
50 buzzerOn = false;
51 digitalWrite(BUZZER_PIN, LOW);
52 }
53 digitalWrite(LED_PIN, alarmActive ? HIGH : LOW);
54}Control de bomba: rellenar un depósito automáticamente
La segunda aplicación clásica es el rellenado automático que mantiene el nivel dentro de una franja. Quizá quieras reponer el agua que se evapora de un acuario desde un cubo de reserva, mantener lleno el bebedero de tu mascota o alimentar el depósito de un invernadero. La lógica es sencilla: cuando el nivel baja de START_BELOW, la bomba arranca, y cuando llega a STOP_ABOVE, se para. El hueco entre estos dos umbrales es la histéresis que evita que la bomba se encienda y se apague sin parar. Recuerda que el sensor solo tiene una zona de detección de unos 4 cm; fija la placa a una altura en la que la franja de agua que quieres mantener quede dentro de esos 4 cm.

La bomba consume mucha más corriente de la que puede dar un pin de Arduino, así que contrólala con un módulo de relé o con un MOSFET de nivel lógico y un diodo de protección, aliméntala con una fuente aparte y une las GND de ambas fuentes. Tienes los detalles en ¿Qué es un módulo de relé?, cómo usar un MOSFET y la mini bomba de agua. La parte más importante del código es una medida de seguridad: si la bomba funciona durante todo el tiempo MAX_RUN_MS y el nivel sigue sin llegar al objetivo, el sistema bloquea la bomba y te avisa con pitidos cortos. Puede que la manguera se haya salido, que el cubo de reserva esté vacío o que el sensor se haya movido; sin este bloqueo, la bomba podría funcionar en seco durante horas o inundarlo todo.
1const int SENSOR_PIN = A0;
2const int POWER_PIN = 7;
3const int PUMP_PIN = 8; // röle IN / relay IN
4const int BUZZER_PIN = 9; // aktif buzzer / active buzzer
5const bool RELAY_ACTIVE_LOW = true; // çoğu röle modülü LOW ile çeker / most relay modules switch on LOW
6
7const int START_BELOW = 300; // bunun altında doldur / start filling below this (kendin ölç / measure yours)
8const int STOP_ABOVE = 480; // bu değerde dur / stop at this value
9const unsigned long MAX_RUN_MS = 30000; // en uzun çalışma 30 sn / max run time 30 s
10
11bool pumpOn = false;
12bool fault = false;
13unsigned long pumpStart = 0;
14
15int readSensor() {
16 digitalWrite(POWER_PIN, HIGH);
17 delay(10);
18 long sum = 0;
19 for (int i = 0; i < 8; i++) sum += analogRead(SENSOR_PIN);
20 digitalWrite(POWER_PIN, LOW);
21 return sum / 8;
22}
23
24void setPump(bool on) {
25 pumpOn = on;
26 bool pinHigh = RELAY_ACTIVE_LOW ? !on : on;
27 digitalWrite(PUMP_PIN, pinHigh ? HIGH : LOW);
28}
29
30void setup() {
31 setPump(false); // pin çıkış olmadan önce kapalı konuma al / set off before the pin becomes an output
32 pinMode(PUMP_PIN, OUTPUT);
33 pinMode(POWER_PIN, OUTPUT);
34 pinMode(BUZZER_PIN, OUTPUT);
35 digitalWrite(POWER_PIN, LOW);
36 Serial.begin(9600);
37}
38
39void loop() {
40 if (fault) { // arıza: pompa kilitli, kesik kesik öt / fault: pump locked out, beep
41 digitalWrite(BUZZER_PIN, HIGH);
42 delay(200);
43 digitalWrite(BUZZER_PIN, LOW);
44 delay(1800);
45 return; // yeniden başlatmak için reset / press reset to restart
46 }
47
48 int level = readSensor();
49
50 if (!pumpOn && level < START_BELOW) {
51 setPump(true); // seviye düştü, doldur / level low, start filling
52 pumpStart = millis();
53 } else if (pumpOn && level >= STOP_ABOVE) {
54 setPump(false); // istenen seviyeye ulaşıldı / target level reached
55 } else if (pumpOn && millis() - pumpStart > MAX_RUN_MS) {
56 setPump(false); // süre doldu, seviye yükselmedi / timed out, level did not rise
57 fault = true;
58 }
59
60 Serial.print("Seviye / Level: ");
61 Serial.print(level);
62 Serial.println(pumpOn ? " pompa / pump ON" : " pompa / pump OFF");
63 delay(500);
64}Sensor de nivel de agua, interruptor de flotador y XKC-Y25: comparativa
| Característica | Sensor de nivel de agua (pistas conductoras) | Interruptor de flotador | XKC-Y25 (sin contacto) |
|---|---|---|---|
| Método de detección | Conductividad del agua | Imán flotante y contacto reed | Cambio de capacitancia tras la pared del recipiente |
| Salida | Analógica (unos pocos niveles) | Contacto abierto o cerrado | Digital (hay líquido o no) |
| Rango de medida | Unos 0–4 cm | Un punto (altura de montaje) | Un punto (altura de montaje) |
| Contacto con el agua | Sí, las pistas están en el agua | Sí, el cuerpo está en el agua | No, se pega por fuera del recipiente |
| Corrosión | Sí; alimentarlo desde un pin es obligatorio | Prácticamente ninguna | Ninguna |
| Alimentación | 3,3–5 V | No necesita (contacto pasivo) | 5–24 V, unos 5 mA |
| Ideal para | Experimentos, alarmas de desbordamiento, recipientes pequeños | Depósitos fijos, protección de la bomba | Depósitos cerrados de plástico o vidrio, líquidos corrosivos |
| Precio | El más barato | Barato | Más caro que los otros |
Un interruptor de flotador consta de un vástago con un contacto reed en su interior y un flotador con imán que se desliza por él. Al subir el agua, el flotador se eleva, el imán se alinea con el contacto reed y el contacto se cierra o se abre. Si colocas el flotador al revés en el vástago, cambias entre normalmente abierto (NO) y normalmente cerrado (NC). Para conectarlo a Arduino basta con llevar un cable a un pin digital y el otro a GND y configurar el pin como INPUT_PULLUP; como no sufre el desgaste por electrólisis, dura mucho más en instalaciones fijas. Los contactos de los modelos pequeños suelen estar limitados a unos 0,5 A y 10 W, así que controla la bomba a través de un relé y no directamente. Para entender cómo funciona un contacto reed, mira el artículo Interruptor reed.

1const int FLOAT_PIN = 2; // bir kablo D2'ye, diğeri GND'ye / one wire to D2, the other to GND
2
3void setup() {
4 pinMode(FLOAT_PIN, INPUT_PULLUP); // dahili pull-up direnci / internal pull-up resistor
5 Serial.begin(9600);
6}
7
8void loop() {
9 // Kontak kapalıyken pin LOW okunur / the pin reads LOW when the contact is closed
10 if (digitalRead(FLOAT_PIN) == LOW) {
11 Serial.println("Kontak kapali / Contact closed");
12 } else {
13 Serial.println("Kontak acik / Contact open");
14 }
15 delay(500);
16}El XKC-Y25, en cambio, es un sensor capacitivo que nunca toca el agua: se pega por fuera de un depósito de plástico o vidrio y detecta si hay líquido al otro lado de la pared. Según el fabricante funciona con 5–24 V, consume unos 5 mA, detecta a través de paredes no metálicas de hasta 13 mm de grosor y responde en unos 500 ms. El nivel alto de su salida es igual a la tensión de alimentación, así que si conectas a un ESP32 o una Pico un XKC-Y25 alimentado a 5 V debes usar un divisor de tensión (la herramienta de divisor de tensión calcula las resistencias adecuadas). Explicamos con detalle el ajuste de sensibilidad y los modelos con otras salidas en el artículo sensor de nivel sin contacto XKC-Y25.

Vigilar el nivel de agua desde el móvil con el ESP32
Con el ESP32 puedes llevar la medida a tu móvil por wifi. Conecta siempre el pin S del sensor a un pin del ADC1 (GPIO 32–39); los pines del ADC2 no se pueden leer con el wifi activo. El ADC del ESP32 es de 12 bits, así que los valores van de 0 a 4095, y como el sensor se alimenta a 3,3 V los números no son comparables con los del Uno; tendrás que calibrar de nuevo. El ADC del ESP32 no es del todo lineal cerca de 0 V ni cerca del extremo superior, pero como aquí importa la diferencia entre niveles y no la tensión absoluta, no supone un problema. El código siguiente mide cada dos segundos y sirve una pequeña página web que se recarga sola cada cinco segundos y que puedes abrir desde el móvil en la misma red.
1#include <WiFi.h>
2#include <WebServer.h>
3
4const char* WIFI_SSID = "WIFI_ADIN"; // ağ adın / your network name
5const char* WIFI_PASS = "WIFI_SIFREN"; // ağ şifren / your network password
6
7const int SENSOR_PIN = 34; // S → GPIO 34 (ADC1, Wi-Fi ile çalışır / works with Wi-Fi)
8const int POWER_PIN = 25; // + → GPIO 25
9const int HALF = 1500; // yarım eşiği / half threshold (kendin ölç / measure yours)
10const int FULL = 2000; // dolu eşiği / full threshold (kendin ölç / measure yours)
11
12WebServer server(80);
13int lastRaw = 0;
14unsigned long lastRead = 0;
15
16int readSensor() {
17 digitalWrite(POWER_PIN, HIGH);
18 delay(10);
19 long sum = 0;
20 for (int i = 0; i < 16; i++) sum += analogRead(SENSOR_PIN); // 0–4095
21 digitalWrite(POWER_PIN, LOW);
22 return sum / 16;
23}
24
25const char* levelName(int raw) {
26 if (raw < 100) return "Bos / Empty";
27 if (raw < HALF) return "Az / Low";
28 if (raw < FULL) return "Yarim / Half";
29 return "Dolu / Full";
30}
31
32void handleRoot() {
33 String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>"
34 "<meta name='viewport' content='width=device-width'>"
35 "<meta http-equiv='refresh' content='5'></head><body>"
36 "<h1>Su seviyesi / Water level</h1><h2>";
37 html += levelName(lastRaw);
38 html += "</h2><p>Ham deger / Raw: ";
39 html += lastRaw;
40 html += "</p></body></html>";
41 server.send(200, "text/html", html);
42}
43
44void setup() {
45 Serial.begin(115200);
46 pinMode(POWER_PIN, OUTPUT);
47 digitalWrite(POWER_PIN, LOW);
48 WiFi.begin(WIFI_SSID, WIFI_PASS);
49 while (WiFi.status() != WL_CONNECTED) { // bağlanana kadar bekle / wait until connected
50 delay(500);
51 Serial.print(".");
52 }
53 Serial.println();
54 Serial.print("Adres / Address: http://");
55 Serial.println(WiFi.localIP());
56 server.on("/", handleRoot);
57 server.begin();
58}
59
60void loop() {
61 server.handleClient();
62 if (millis() - lastRead >= 2000) { // 2 sn'de bir ölç / measure every 2 s
63 lastRead = millis();
64 lastRaw = readSensor();
65 }
66}Antes de subir el código, cambia WIFI_SSID y WIFI_PASS por los datos de tu red; el ESP32 solo se conecta a redes de 2,4 GHz. Al abrir el Monitor Serie a 115200 baudios, basta con escribir en el navegador del móvil la dirección que aparece. Si quieres recibir un aviso en el móvil cuando el nivel esté «lleno», puedes convertir la misma lectura en un mensaje con el método del artículo bot de Telegram con ESP32.
Alarma de desbordamiento con Raspberry Pi Pico y MicroPython
En la Raspberry Pi Pico se usan los pines GP26, GP27 y GP28 para las lecturas analógicas. La función read_u16() de MicroPython escala la medida de 12 bits de la Pico al rango 0–65535, así que tus umbrales serán números mucho mayores que en el Uno. El código de abajo alimenta el sensor desde GP15, lee la salida S en GP26 y avisa del desbordamiento con tres pitidos cortos de un zumbador activo en GP14. Igual que en el primer programa, fija los umbrales a partir de tus propias medidas.
1from machine import ADC, Pin
2import time
3
4sensor = ADC(26) # GP26 (ADC0) → S
5power = Pin(15, Pin.OUT, value=0) # GP15 → sensör + / sensor +
6buzzer = Pin(14, Pin.OUT, value=0) # GP14 → aktif buzzer / active buzzer
7
8ALARM_ON = 20000 # bu değer ve üstü taşma / at or above: overflow (kendin ölç / measure yours)
9ALARM_OFF = 10000 # bunun altında alarm biter / alarm clears below this
10
11def read_level(samples=8):
12 power.value(1)
13 time.sleep_ms(10) # değerin oturmasını bekle / let the reading settle
14 total = 0
15 for _ in range(samples):
16 total += sensor.read_u16() # 0–65535
17 power.value(0)
18 return total // samples
19
20alarm = False
21while True:
22 level = read_level()
23 if not alarm and level >= ALARM_ON:
24 alarm = True
25 elif alarm and level < ALARM_OFF:
26 alarm = False
27 print("Seviye / Level:", level, "ALARM" if alarm else "")
28 if alarm:
29 for _ in range(3): # üç kısa bip / three short beeps
30 buzzer.value(1)
31 time.sleep_ms(150)
32 buzzer.value(0)
33 time.sleep_ms(150)
34 else:
35 time.sleep(1)Ideas de proyectos con un sensor de nivel de agua
- Aviso de desbordamiento del plato de la maceta: Un zumbador que suena cuando se acumula agua en el plato después de regar; si lo combinas con un sensor de humedad del suelo, tendrás un sistema de riego completo.
- Rellenado automático del acuario: Un sistema de rellenado con tiempo limitado que repone con una mini bomba el agua evaporada desde un cubo de reserva.
- Bebedero para mascotas: Un avisador que enciende un LED o envía una notificación al móvil con el ESP32 cuando queda poca agua.
- Detector de inundación: Una alarma de fugas con el sensor tumbado en el suelo bajo la lavadora, junto a la caldera o en el sótano.
- Depósito inteligente para el invernadero: Una protección que vigila el nivel del depósito de riego y bloquea la bomba cuando se vacía; se añade fácilmente al proyecto de invernadero inteligente.
- Indicador para el bidón de agua de lluvia: Un panel que muestra el nivel como vacío, medio o lleno en una pantalla LCD I2C; también puedes añadir un sensor de lluvia para detectar cuándo empieza a llover.
Errores frecuentes y cómo solucionarlos
| Síntoma | Causa probable | Solución |
|---|---|---|
| El valor es siempre 0, incluso en el agua | El pin + no recibe alimentación (POWER_PIN nunca pasa a HIGH) o S está en el pin equivocado | Revisa las líneas de pinMode y digitalWrite y que S esté en un pin analógico |
| El valor salta al azar incluso en seco | El pin S está al aire o falta la conexión de GND | Revisa los tres cables; la GND debe ser común |
| Nunca llega a 1023, ni siquiera sumergido del todo | Es normal; la salida viene de un seguidor de emisor | Fija los umbrales según el valor más alto que hayas medido tú |
| En agua pura no se lee nada | El agua destilada o purificada apenas conduce | Con este tipo de agua usa un XKC-Y25 o un interruptor de flotador |
| Los valores bajan o se desvían en unas semanas | Electrólisis y depósitos en las pistas | Alimenta el sensor desde un pin, limpia las pistas con un cepillo suave y cámbialo si hace falta |
| La bomba o el zumbador se encienden y apagan sin parar en el umbral | Se usa un solo umbral; la superficie en movimiento hace oscilar el valor | Usa dos umbrales distintos para encender y apagar (histéresis) y promedia las lecturas |
| En el ESP32 no se puede leer el valor al conectar el wifi | El sensor está en un pin del ADC2 | Pasa S a un pin del ADC1 entre GPIO 32 y 39 |
El sensor de nivel de agua enseña lecturas analógicas, calibración, histéresis y problemas reales como la corrosión con un único módulo barato. Si necesitas medir centímetro a centímetro el nivel de un depósito grande, puedes pasarte a una solución ultrasónica como el sensor de distancia HC-SR04. En la aplicación BlueGrays encontrarás la estación de riego inteligente y proyectos de alarma con zumbador, con esquemas y código paso a paso, y podrás añadirles fácilmente el sensor de nivel de agua.
Preguntas frecuentes
¿Cómo funciona un sensor de nivel de agua?
Cuando las pistas conductoras entrelazadas de la placa se sumergen, el agua las une y circula corriente hacia la base del transistor S8050 del módulo. Cuanto más conduce el transistor, más sube la tensión en el pin S; Arduino lee esa tensión con analogRead() para saber hasta dónde llega el agua.
¿Por qué se corroe mi sensor de nivel de agua?
Cuando circula corriente continua sin parar por las pistas mojadas comienza la electrólisis y se disuelve el recubrimiento de las pistas unidas al +. Si alimentas el sensor desde un pin digital en lugar de 5V y solo lo enciendes unos milisegundos en cada lectura, el desgaste se reduce muchísimo y el sensor dura meses.
¿Funciona un sensor de nivel de agua con agua destilada?
Casi no. Como el sensor mide la conductividad del agua, el agua destilada o purificada, sin minerales disueltos, da lecturas muy bajas. Para este tipo de agua es mejor elegir sensores que no dependen de la conductividad, como el XKC-Y25 sin contacto o un interruptor de flotador.
¿Por qué el sensor de nivel de agua no llega a 1023?
La salida S se toma del emisor del transistor, así que la tensión queda por debajo de la alimentación, y la corriente de base está limitada por la resistencia del agua. En un Arduino Uno a 5 V, un sensor totalmente mojado suele leer entre 500 y 650; fija tus umbrales a partir de ese máximo.
¿Se puede sumergir del todo un sensor de nivel de agua?
No. Solo la parte inferior, la de las pistas conductoras, debe entrar en el agua; si se moja la parte superior con el transistor, el LED y los pines, hay un cortocircuito y el sensor lee mal o se estropea. Proteger la electrónica con silicona caliente o barniz alarga su vida.
¿Cómo se mide el nivel de un depósito de agua grande?
Este sensor solo abarca unos 4 cm, así que no sirve para depósitos grandes. Para medir el nivel de forma continua se usan sensores ultrasónicos estancos como el JSN-SR04T montados en la tapa del depósito; para vigilar solo unos pocos puntos críticos se colocan interruptores de flotador a distintas alturas.
Proyectos para hacer después de leer esto
Ver todos los proyectos
Uso del zumbador
¿Alguna vez te has preguntado cómo suena un timbre o una alarma? El Arduino hace pitar un pequeño zumbador a intervalos cortos: pip, silencio, pip, silencio. Ves cómo se crea sonido con electricidad y

Medir la intensidad de luz con LDR
¿Quieres ver en números cuánta luz hay en tu habitación? El LDR, una pequeña pieza sensible a la luz, mide la luz ambiente y el Arduino escribe el valor en la pantalla del ordenador cada medio segundo

Lectura de la intensidad luminosa con el módulo LDR del ESP32
Visualización en tiempo real en el monitor serie del valor bruto del ADC del módulo LDR y del porcentaje relativo de luz calculado a partir de referencias de oscuridad y claridad. Este porcentaje no es una medición en lux. Explica el funcionamiento de la calibración del módulo. Es recomendable realizarlo antes del Proyecto 10, ya que se utiliza para determinar el valor umbral.

Estación de riego inteligente
Un jardinero que riega solo tus plantas para que no se sequen mientras estás de vacaciones. Un sensor de humedad mide lo mojada que está la tierra; cuando se seca, el Arduino enciende la bomba de agua

Lectura de un interruptor reed
¿Alguna vez te has preguntado cómo funciona el interruptor magnético de las alarmas de puertas y ventanas? Cuando un imán se acerca al módulo de relé reed, el diminuto interruptor de dentro se cierra;

Servidor web asíncrono ESP32 (con indicación de IP en la pantalla LCD)
En este proyecto, convertimos el ESP32 en un servidor web asíncrono que puedes controlar desde tu teléfono o tu ordenador, siempre que estén conectados a la misma red Wi-Fi. Gracias a la biblioteca ESPAsyncWebServer, el servidor puede procesar varias solicitudes al mismo tiempo (a diferencia del clásico WebServer.h, que se bloquea con una sola solicitud).

Sistema de Alarma de Movimiento ESP32 (PIR + Buzzer + LED + Telegram)
Un sistema inteligente de alarma de seguridad que activa el buzzer y el LED cuando el sensor PIR detecta movimiento, y envía simultáneamente una notificación instantánea al propietario vía Telegram. Cuenta con un tiempo de espera de 30 segundos para limitar la frecuencia de las alarmas repetidas; este mecanismo no comprueba la validez de las detecciones del sensor PIR ni elimina las falsas detecciones. Ideal para seguridad del hogar, vigilancia de garajes, almacenes o salas de trabajo. Con ESP32
Más artículos
App BlueGrays
Monta este circuito paso a paso en tu teléfono
Esquema, código y lista de piezas en una sola pantalla. Más de 200 proyectos de Arduino, ESP32 y Pico listos para montar.
Escanea con tu teléfono
Apunta la cámara al código y se abrirá la tienda de apps de tu teléfono.
o ábrela en la tienda

