IoTLabs

Nghiên cứu, Sáng tạo và Thử nghiệm

Series ESP32 & Cảm biến: Bài 9 – Đọc cảm biến Water Level Sensor: đo mực nước & theo dõi realtime

Trong bài này, chúng ta sử dụng Water Level Sensor (cảm biến mực nước) để đo mức nước theo dạng analog, sau đó chuẩn hoá thành % mực nước và gửi dữ liệu lên IoTLabs Cloud MQTT để theo dõi realtime.
Đây là cảm biến DIY rất phổ biến, thường dùng cho:

  • Bồn nước gia đình
  • Cảnh báo tràn / cạn nước
  • Trạm thời tiết mini
  • Ứng dụng nông nghiệp, thủy canh

Bài viết gồm 2 ví dụ code:

  1. Đọc mực nước local (Serial)
  2. Gửi mực nước lên IoTLabs Cloud MQTT để theo dõi realtime

1) Water Level Sensor là gì?

  • Water Level Sensor hoạt động dựa trên độ dẫn điện của nước
  • Khi mực nước tăng:
    • Nhiều vạch đồng tiếp xúc nước hơn
    • Điện trở giảm → giá trị ADC thay đổi

📌 Khác với Rain Sensor:

  • Rain: phát hiện mưa / ướt
  • Water Level: đo mức nước tuyến tính

2) Chuẩn bị

Phần cứng

  • ESP32-C3 SuperMini (Tenstar Robot)
  • Water Level Sensor module
  • Breadboard + dây nối

Chân sử dụng

  • AO → GPIO1 (ADC)
  • VCC → 5V
  • GND → GND

⚠️ Khuyến nghị cấp 5V cho module để tín hiệu ổn định
ESP32 chỉ đọc analog (3.3V safe)

3) Nối dây Water Level Sensor với ESP32

Water Level Sensor   ESP32-C3 SuperMini
-------------------------------------
VCC   ------------ 5V
GND   ------------ GND
AO    ------------ GPIO1 (ADC)

4) Giá trị đọc & chuẩn hoá mực nước

ESP32 ADC (12-bit):

  • Giá trị đọc: 0 → 4095
Trạng tháiADC (ước lượng)
Không có nước0 – 500
Thấp500 – 1500
Trung bình1500 – 3000
Cao / đầy> 3000

📌 Giá trị thay đổi theo loại cảm biến & chất lượng nước → cần hiệu chỉnh.

Ví dụ 1 — Code local đơn giản (đo mực nước)

Mục tiêu: in mực nước (%) ra Serial.

// ===== Water Level Sensor Local Read =====
const int WATER_PIN = 1; // ADC

void setup() {
  Serial.begin(115200);
  delay(200);

  Serial.println("Water level sensor monitor started...");
}

void loop() {
  int raw = analogRead(WATER_PIN);

  // Chuẩn hoá % (0 = cạn, 100 = đầy)
  int waterPct = map(raw, 0, 4095, 0, 100);
  waterPct = constrain(waterPct, 0, 100);

  Serial.print("ADC: ");
  Serial.print(raw);
  Serial.print(" | Water level: ");
  Serial.print(waterPct);
  Serial.println("%");

  delay(1000);
}

5) Chuẩn dữ liệu realtime cho IoTLabs Cloud

Topic

iotlabs/<orgId>/devices/<deviceId>/telemetry

Payload JSON

{
  "ts": 1760000000,
  "metrics": {
    "water_level": 72
  },
  "status": {
    "level": "normal"
  }
}
water_levelÝ nghĩa
0–20thấp
20–80bình thường
>80cao

Ví dụ 2 — Gửi mực nước lên IoTLabs Cloud MQTT

Chiến lược:

  • Gửi định kỳ 5–10 giây
  • Có thể kết hợp cảnh báo ngưỡng (Level 2)
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>

// ===== CONFIG =====
const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_PASS";

const char* MQTT_HOST = "mqtt.iotlabs.vn";
const int   MQTT_PORT = 8883;
const char* MQTT_USER = "YOUR_MQTT_USER";
const char* MQTT_PASS = "YOUR_MQTT_PASS";
const char* MQTT_TOPIC =
  "iotlabs/<orgId>/devices/<deviceId>/telemetry";

// ===== WATER =====
const int WATER_PIN = 1;

WiFiClientSecure net;
PubSubClient mqtt(net);

unsigned long lastSend = 0;
const unsigned long SEND_INTERVAL = 5000;

void connectWiFi() {
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(400);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected");
}

void connectMQTT() {
  net.setInsecure(); // demo
  mqtt.setServer(MQTT_HOST, MQTT_PORT);

  while (!mqtt.connected()) {
    if (mqtt.connect("esp32c3-water", MQTT_USER, MQTT_PASS)) {
      Serial.println("MQTT connected");
      break;
    }
    delay(1000);
  }
}

void setup() {
  Serial.begin(115200);
  connectWiFi();
  connectMQTT();
}

void loop() {
  if (!mqtt.connected()) connectMQTT();
  mqtt.loop();

  unsigned long now = millis();
  if (now - lastSend > SEND_INTERVAL) {
    lastSend = now;

    int raw = analogRead(WATER_PIN);
    int waterPct = map(raw, 0, 4095, 0, 100);
    waterPct = constrain(waterPct, 0, 100);

    long ts = millis() / 1000;

    String payload = "{";
    payload += "\"ts\":" + String(ts) + ",";
    payload += "\"metrics\":{\"water_level\":" + String(waterPct) + "},";
    payload += "\"status\":{\"level\":\"normal\"}";
    payload += "}";

    mqtt.publish(MQTT_TOPIC, payload.c_str());
    Serial.println(payload);
  }
}

6) Lỗi thường gặp & kinh nghiệm thực tế

  • Ăn mòn cảm biến
    • Không để ngâm lâu ngày
    • Lau khô sau khi test
  • ADC nhảy loạn
    • Lấy trung bình 5–10 mẫu
  • Sai %
    • In raw ADC để tự hiệu chỉnh min/max

7) Ứng dụng thực tế

  • Giám sát bồn nước
  • Cảnh báo cạn / tràn
  • Kết hợp Rain Sensor (Bài 8)
  • Nâng cấp cảnh báo thông minh (Level 2)

Bài tiếp theo (Level 1 – bài cuối)

👉 Bài 10: Hướng dẫn đọc cảm biến Sound Sensor (KY-038 / KY-037) bằng ESP32: đo mức âm thanh & theo dõi realtime