Pond Water Level Monitor for Aquaculture
Intermediate1/8/2026- Author: IoTSpark Maker

Pond Water Level Monitor for Aquaculture

Uses an HC-SR04 ultrasonic sensor on an ESP32 to measure aquaculture pond water level in real time, with a local buzzer alert when the level is too low or too high.

esp32hc-sr04water-levelaquaculturesmart-farmalertiot
0 steps5 components

In this project, you'll build a pond water level monitoring system for aquaculture using an HC-SR04 ultrasonic sensor mounted on an ESP32 board. The system measures the pond's water level in real time and sounds a buzzer alert when the level is too low or too high. It's a fun project that puts IoT concepts to practical use in aquaculture.

What You'll Learn

  • How to use an HC-SR04 ultrasonic sensor to measure distance.

  • How to configure and program an ESP32 to connect to and process sensor data.

  • How to detect and handle alert conditions when the water level is out of range.

  • How to integrate a buzzer for audible alerts.

  • How to apply IoT concepts in a real-world project.

Key Features

  • Fast, accurate water level measurement with the HC-SR04.

  • Instant local buzzer alert when the water level crosses a set threshold.

  • Simple, easy-to-follow design suitable for beginners and experienced makers alike.

  • Easy to extend with data logging or network reporting features.

Why This Project Is Worth Building

This project doesn't just sharpen your programming and IoT skills — it delivers real practical value for aquaculture. Water level is a critical factor for the survival of farmed fish and shrimp, so monitoring and controlling it matters. This system lets farmers stay ahead of water-level problems and protect their stock, ultimately improving yield and product quality.

Detailed guide

Uses an HC-SR04 ultrasonic sensor on an ESP32 to measure aquaculture pond water level in real time, with a local buzzer alert when the level is too low or too high.

1. Introduction

In aquaculture (shrimp, fish farming), pond/tank water level directly affects animal health — too little water causes heat stress and low dissolved oxygen, while overflow causes water loss and pollutes the surrounding area. This project mounts an HC-SR04 ultrasonic sensor above the pond to measure the distance down to the water surface in real time, converts it to a water-level percentage, and sounds a local buzzer alert when the level drops too low (needs a top-up) or rises too high (risk of overflow/flooding).

This is a non-contact measurement approach well suited to pond environments, since the sensor never touches the water — reducing the risk of corrosion or fouling compared to float-type or electrode-based water-level sensors.

2. Components Needed

Component

Qty

Reference Price

ESP32 DevKit V1 (30-pin)

1

~90,000 - 120,000₫

HC-SR04 — Ultrasonic Distance Sensor

1

~15,000 - 25,000₫

Active Buzzer — local alarm

1

~5,000 - 10,000₫

1kΩ + 2kΩ resistors (voltage divider for the ECHO pin)

1 set

~5,000₫

Waterproof enclosure (IP65+) for mounting the sensor at the pond's edge

1

Varies by material

Jumper wires, a sensor mount, 5V power supply

1 set

~20,000 - 30,000₫

3. Wiring Diagram

HC-SR04

ESP32

VCC

VIN (5V)

GND

GND

TRIG

GPIO26

ECHO

GPIO27 (through a voltage divider — see the note below)

Active Buzzer

ESP32

VCC

3V3

GND

GND

IO

GPIO25

Important hardware safety note:

  • The HC-SR04 outputs its ECHO pulse at 5V, but the ESP32's GPIO only tolerates up to about 3.3V (~3.6V absolute maximum). When deploying on real hardware,

  • you must use a resistor voltage divider (e.g. 1kΩ in series to GND through a 2kΩ, tapping the midpoint into GPIO27) or a level-shifter module on the ECHO line before connecting it to the ESP32 — otherwise you risk damaging the GPIO pin/chip over time.

  • The sensor also needs to be mounted in a watertight enclosure when placed outdoors or over the pond, to prevent damage from rain/humidity.

4. Example #1 — Basic Distance Measurement with the HC-SR04

#define TRIG_PIN 26
#define ECHO_PIN 27

void setup() {
  Serial.begin(115200);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
}

void loop() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH, 25000);
  float distanceCm = duration * 0.0343 / 2.0;

  if (duration == 0) {
    Serial.println("Khong doc duoc cam bien (timeout)");
  } else {
    Serial.print("Khoang cach: ");
    Serial.print(distanceCm);
    Serial.println(" cm");
  }

  delay(1000);
}

5. Example #2 — Buzzer Alert When Water Level Crosses a Threshold

#define BUZZER_PIN 25

const float DISTANCE_LOW_WATER_CM = 130.0;  // qua xa cam bien = nuoc thap

void setup() {
  pinMode(BUZZER_PIN, OUTPUT);
  digitalWrite(BUZZER_PIN, LOW);
}

void loop() {
  float distanceCm = 140.0; // thay bang gia tri do tu HC-SR04 thuc te

  if (distanceCm > DISTANCE_LOW_WATER_CM) {
    digitalWrite(BUZZER_PIN, HIGH); // canh bao nuoc thap
  } else {
    digitalWrite(BUZZER_PIN, LOW);
  }

  delay(1000);
}

6. Example #3 — The Complete Pond Water-Level Monitoring Application

/*
  Theo doi muc nuoc ao nuoi thuy san
  Board: ESP32 DevKit V1 (30 pins)
  Cam bien: HC-SR04 (sieu am do khoang cach tu mep ao xuong mat nuoc)
  Canh bao tai cho: Active Buzzer

  Wiring (khop voi diagram tren IoTLabs Maker):
    HC-SR04   TRIG -> GPIO26     ECHO -> GPIO27
              VCC  -> VIN(5V)    GND  -> GND
    Buzzer    IO   -> GPIO25     VCC  -> 3V3   GND -> GND

  LUU Y QUAN TRONG (an toan phan cung):
    HC-SR04 xuat xung ECHO muc 5V nhung GPIO ESP32 chi chiu duoc toi da 3.3V (~3.6V).
    Trien khai thuc te BAT BUOC dung cau phan ap tro (vi du 1kOhm + 2kOhm) tren chan ECHO
    truoc khi noi vao GPIO27, neu khong se co nguy co hong chan GPIO/chip ve lau dai.
    Ngoai ra can op ky watertight cho dau do khi lap ngoai troi/tren mat ao.

  Nguyen ly do muc nuoc:
    distance_cm = khoang cach tu cam bien (gan mieng ao) xuong mat nuoc.
    muc nuoc CAO  <-> distance_cm NHO (nuoc gan cam bien)
    muc nuoc THAP <-> distance_cm LON (nuoc xa cam bien)
  Canh bao khi muc nuoc qua thap (can bom bo sung) hoac qua cao (nguy co tran/ngap).
*/

#define TRIG_PIN 26
#define ECHO_PIN 27
#define BUZZER_PIN 25

// Hieu chinh theo kich thuoc ao thuc te (khoang cach tu cam bien den day/mep ao)
const float SENSOR_TO_EMPTY_CM = 150.0; // khoang cach khi ao can (muc nuoc = 0%)
const float SENSOR_TO_FULL_CM  = 20.0;  // khoang cach khi ao day (muc nuoc = 100%)

const float LOW_LEVEL_ALERT_PCT  = 20.0;  // canh bao muc nuoc thap
const float HIGH_LEVEL_ALERT_PCT = 95.0;  // canh bao muc nuoc qua cao / sap tran

const unsigned long MEASURE_INTERVAL_MS = 3000;
const unsigned long PULSE_TIMEOUT_US = 25000; // ~4.3m, du cho khoang cach thuc te trong ao

unsigned long lastMeasure = 0;
bool sensorTimeoutSeen = false;

float measureDistanceCm() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  unsigned long duration = pulseIn(ECHO_PIN, HIGH, PULSE_TIMEOUT_US);
  if (duration == 0) {
    return -1.0; // timeout / khong doc duoc - cam bien mat ket noi hoac ngoai tam
  }
  return duration * 0.0343 / 2.0; // toc do am thanh ~343 m/s
}

void setBuzzer(bool on) {
  digitalWrite(BUZZER_PIN, on ? HIGH : LOW);
}

void setup() {
  Serial.begin(115200);
  delay(300);
  Serial.println();
  Serial.println(F("=== Theo doi muc nuoc ao nuoi IoTLabs - Boot OK ==="));

  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  digitalWrite(TRIG_PIN, LOW);
  setBuzzer(false);

  Serial.println(F("HC-SR04 + Buzzer san sang. Bat dau do muc nuoc dinh ky."));
}

void loop() {
  unsigned long now = millis();
  if (now - lastMeasure < MEASURE_INTERVAL_MS) {
    return;
  }
  lastMeasure = now;

  float distanceCm = measureDistanceCm();

  if (distanceCm < 0) {
    sensorTimeoutSeen = true;
    setBuzzer(false); // khong doan canh bao khi khong co du lieu tin cay
    Serial.println(F("{\"distance_cm\":null,\"level_pct\":null,\"alert\":null,\"status\":\"sensor_timeout\"}"));
    return;
  }
  sensorTimeoutSeen = false;

  // Quy doi khoang cach -> % muc nuoc, gioi han 0-100
  float levelPct = (SENSOR_TO_EMPTY_CM - distanceCm) /
                    (SENSOR_TO_EMPTY_CM - SENSOR_TO_FULL_CM) * 100.0;
  if (levelPct < 0) levelPct = 0;
  if (levelPct > 100) levelPct = 100;

  const char* alert = "normal";
  bool buzzerOn = false;
  if (levelPct <= LOW_LEVEL_ALERT_PCT) {
    alert = "low_water";
    buzzerOn = true;
  } else if (levelPct >= HIGH_LEVEL_ALERT_PCT) {
    alert = "high_water";
    buzzerOn = true;
  }
  setBuzzer(buzzerOn);

  Serial.print(F("{\"distance_cm\":"));
  Serial.print(distanceCm, 1);
  Serial.print(F(",\"level_pct\":"));
  Serial.print(levelPct, 1);
  Serial.print(F(",\"alert\":\""));
  Serial.print(alert);
  Serial.println(F("\",\"status\":\"ok\"}"));
}

7. Common Issues

Issue

Cause

Fix

pulseIn() always returns 0 (timeout)

The sensor isn't aimed straight down at the flat water surface, or the distance exceeds the HC-SR04's 400cm range

Make sure the sensor is perpendicular to the water surface, and mounted within the 2-400cm measuring range

Readings jump around erratically when there's wind/waves

Ripples on the water surface make the sound reflection unstable

Apply a moving average filter across several readings, or increase the measurement interval to a few seconds

The ESP32's GPIO fails after long-term outdoor use

No voltage divider on the ECHO pin — the GPIO is continuously exposed to a 5V pulse beyond its tolerance

Always use a resistor voltage divider (1kΩ+2kΩ) or a level-shifter on ECHO before connecting it to GPIO27

The buzzer sounds continuously even at a normal water level

The alert thresholds are set incorrectly (LOW/HIGH swapped), or SENSOR_TO_EMPTY_CM/SENSOR_TO_FULL_CM haven't been calibrated for the real pond

Measure the actual distance when the pond is empty and when it's full to calibrate these two constants

8. Summary

This pond water-level monitoring system catches a too-low or too-high water level early, without a sensor that touches the water directly — well suited to the harsh conditions of an aquaculture pond.

The local buzzer alert lets operators know right away, even with no network connection.

Possible extensions: send water-level data over MQTT to a dashboard monitoring multiple ponds at once, or integrate automatic pump control via a relay when the level drops below a safe threshold.