Componentes · 14 min de lectura

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.

Módulo sensor de nivel de agua para Arduino
Módulo sensor de nivel de agua: las pistas conductoras entrelazadas de la parte inferior se sumergen y los pines S, + y − de la parte superior se conectan a Arduino; la electrónica debe estar siempre seca.

¿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ísticaValor
Tensión de funcionamiento3,3–5 V CC
Corriente de funcionamientoMenos de 20 mA (máxima cuando está totalmente mojado)
SalidaTensión analógica (pin S), aumenta al subir el agua
Zona de detecciónUnos 40 × 16 mm, es decir, como máximo unos 4 cm de altura de agua
Tamaño de la placaUnos 62 × 20 mm
Temperatura de trabajo10–30 °C (dato del fabricante)
PinesS (señal), + (VCC), − (GND)

Conexión del sensor de nivel de agua: Arduino Uno, ESP32 y Pico

Pin del sensorArduino UnoESP32Raspberry Pi Pico
S (señal)A0GPIO 34 (ADC1)GP26 (ADC0)
+ (VCC)D7 (lo alimenta solo al medir)GPIO 25GP15
− (GND)GNDGNDGND
No conectes el pin + del sensor a 5V de forma permanente. Cuando circula corriente continua sin parar por las pistas mojadas comienza la electrólisis: el recubrimiento de las pistas unidas al + se disuelve, las pistas se oscurecen y en pocas semanas las lecturas empiezan a desviarse. Además, solo la parte inferior de la placa, la de las pistas conductoras, puede entrar en el agua; si se moja la parte superior con el transistor, el LED y los pines, se produce un cortocircuito.

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

  1. 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.
  2. Abre el código de abajo en el Arduino IDE, elige Arduino Uno como placa y el puerto correcto, y súbelo.
  3. Abre el Monitor Serie y ajústalo a 9600 baudios. Comprueba que, con el sensor seco, el valor está cerca de 0.
  4. 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.
C++ (Arduino IDE)
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.

NivelProfundidad sumergidaValor típico en Uno (5 V, agua del grifo)
Vacío0 mm (seco)0–20
BajoUnos 5–10 mm250–400
MedioUnos 20 mm400–480
LlenoUnos 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.

C++ (Arduino IDE)
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}
Cuando sacas el sensor del agua, el valor no cae a 0 al momento; la fina película de agua y las gotas que quedan entre las pistas mantienen la lectura claramente por encima de cero durante un rato. Por eso conviene poner el umbral de «vacío» un poco por encima de 0 y, para decisiones de encendido y apagado como una alarma, usar dos umbrales distintos: uno para activar y otro para desactivar. Este método se llama histéresis y evita que un relé o un zumbador se encienda y se apague cada segundo mientras el nivel oscila justo alrededor del umbral.

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().

C++ (Arduino IDE)
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.

Mini bomba de agua sumergible de 6 V
Mini bomba sumergible de 3–6 V: funciona dentro del agua y consume unos 100–250 mA, así que se controla mediante un relé o un MOSFET, no directamente desde un pin de Arduino.

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.

C++ (Arduino IDE)
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}
Agua y electricidad en el mismo proyecto: coloca el Arduino, el relé y la fuente por encima y lejos de los recipientes de agua, y aísla los empalmes con tubo termorretráctil o silicona caliente. Si vas a usar una bomba o una electroválvula de 220 V, encarga la conexión a la red a una persona cualificada y trabaja en un circuito protegido por un diferencial. Las bombas sumergibles pequeñas se calientan y se estropean rápido si funcionan en seco; poner además un interruptor de flotador en el cubo de reserva es una buena segunda capa de seguridad.

Sensor de nivel de agua, interruptor de flotador y XKC-Y25: comparativa

CaracterísticaSensor de nivel de agua (pistas conductoras)Interruptor de flotadorXKC-Y25 (sin contacto)
Método de detecciónConductividad del aguaImán flotante y contacto reedCambio de capacitancia tras la pared del recipiente
SalidaAnalógica (unos pocos niveles)Contacto abierto o cerradoDigital (hay líquido o no)
Rango de medidaUnos 0–4 cmUn punto (altura de montaje)Un punto (altura de montaje)
Contacto con el aguaSí, las pistas están en el aguaSí, el cuerpo está en el aguaNo, se pega por fuera del recipiente
CorrosiónSí; alimentarlo desde un pin es obligatorioPrácticamente ningunaNinguna
Alimentación3,3–5 VNo necesita (contacto pasivo)5–24 V, unos 5 mA
Ideal paraExperimentos, alarmas de desbordamiento, recipientes pequeñosDepósitos fijos, protección de la bombaDepósitos cerrados de plástico o vidrio, líquidos corrosivos
PrecioEl más baratoBaratoMá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.

Interruptor de flotador como sensor de nivel de agua
Interruptor de flotador: el flotador magnético sube con el agua y abre o cierra el contacto reed del vástago.
C++ (Arduino IDE)
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.

Sensor de nivel de líquido sin contacto XKC-Y25
XKC-Y25: sensor capacitivo que se pega por fuera del depósito; como nunca toca el agua, no se corroe.

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.

C++ (Arduino IDE)
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.

MicroPython
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íntomaCausa probableSolución
El valor es siempre 0, incluso en el aguaEl pin + no recibe alimentación (POWER_PIN nunca pasa a HIGH) o S está en el pin equivocadoRevisa las líneas de pinMode y digitalWrite y que S esté en un pin analógico
El valor salta al azar incluso en secoEl pin S está al aire o falta la conexión de GNDRevisa los tres cables; la GND debe ser común
Nunca llega a 1023, ni siquiera sumergido del todoEs normal; la salida viene de un seguidor de emisorFija los umbrales según el valor más alto que hayas medido tú
En agua pura no se lee nadaEl agua destilada o purificada apenas conduceCon este tipo de agua usa un XKC-Y25 o un interruptor de flotador
Los valores bajan o se desvían en unas semanasElectrólisis y depósitos en las pistasAlimenta 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 umbralSe usa un solo umbral; la superficie en movimiento hace oscilar el valorUsa 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 wifiEl sensor está en un pin del ADC2Pasa S a un pin del ADC1 entre GPIO 32 y 39
Para alargar la vida del sensor, colócalo vertical en el agua, sumerge solo la parte de las pistas y cubre la electrónica de arriba con silicona caliente o barniz transparente; eso sí, no recubras las pistas, porque entonces no podrían medir la conductividad. En una instalación fija que vaya a pasar meses en el agua, lo más robusto es usar este sensor para el prototipo y pasar en el sistema definitivo a un interruptor de flotador o a un sensor sin contacto.

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.

Ver todos los proyectos
Uso del zumbador
#13Principiante

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

4.7(89)
161
Medir la intensidad de luz con LDR
#11Principiante

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

4.6(81)
139
Lectura de la intensidad luminosa con el módulo LDR del ESP32
#113Principiante

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.

4.6(36)
55
Estación de riego inteligente
#83Avanzado
Premium

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

5.0(42)
57
Lectura de un interruptor reed
#37Principiante

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;

4.4(21)
27
Servidor web asíncrono ESP32 (con indicación de IP en la pantalla LCD)
#129Avanzado

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).

4.8(16)
26
Sistema de Alarma de Movimiento ESP32 (PIR + Buzzer + LED + Telegram)
#145Avanzado
Premium

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

0.0(0)
9