Hệ thống giám sát chất lượng nước
Trung cấp20/6/2026

Hệ thống giám sát chất lượng nước

Xây dựng hệ thống giám sát chất lượng nước với các tính năng: đo độ đục của nước, đo nhiệt độ, TDS, pH, độ đục của nước, hiển thị trạng thái cảnh báo và mở rộng gửi dữ liệu realtime qua MQTT. Phù hợp cho theo dõi chất lượng nước hồ cá, thủy canh, bể chứa nước hoặc mô hình giám sát nước tham khảo. Lưu ý: Kết quả đo từ cảm biến phổ thông không thay thế thiết bị kiểm định chuyên dụng hoặc xét nghiệm phòng lab.

ESP32IoTWater QualityMQTTArduino IDETDSpHDS18B20
0 lượt thích2 người đã làm1 giờ7 bước9 linh kiện
← Quay lại dự án
Hướng dẫn chi tiết

Phần 4: Lập trình firmware đọc chất lượng nước

Xây dựng chương trình Arduino IDE hoàn chỉnh để đọc nhiệt độ, TDS, pH, độ đục và đánh giá trạng thái nước.

Cập nhật 20/06/2026

Phần 4: Lập trình firmware đọc chất lượng nước

Ở phần này, chúng ta ghép các cảm biến thành một chương trình hoàn chỉnh. Firmware sẽ đọc dữ liệu, lọc trung bình nhiều mẫu, tính TDS, tính pH, tính độ đục tương đối và đánh giá trạng thái nước.

4.1. Luồng xử lý chính

1. Đọc nhiệt độ từ DS18B20
2. Đọc điện áp TDS, pH và turbidity qua ADC
3. Lọc dữ liệu bằng cách lấy trung bình nhiều mẫu
4. Bù nhiệt đơn giản cho TDS
5. Tính pH dựa trên hiệu chuẩn 2 điểm
6. Tính độ đục tương đối 0–100%
7. Đánh giá trạng thái NORMAL / WARNING / DANGER / SENSOR_ERROR
8. Điều khiển LED và buzzer
9. In kết quả ra Serial Monitor

4.2. Code Arduino IDE hoàn chỉnh

#include <OneWire.h>
#include <DallasTemperature.h>

#define PIN_ONE_WIRE    4
#define PIN_TDS         34
#define PIN_PH          35
#define PIN_TURBIDITY   32

#define PIN_BUZZER      25
#define PIN_LED_GREEN   26
#define PIN_LED_RED     27

const float ADC_MAX = 4095.0;
const float ESP32_ADC_REF_VOLTAGE = 3.3;
const float TURBIDITY_DIVIDER_FACTOR = 1.5;

float PH7_VOLTAGE = 2.50;
float PH4_VOLTAGE = 3.00;

float CLEAR_WATER_VOLTAGE = 4.10;
float DIRTY_WATER_VOLTAGE = 2.50;

const float PH_MIN_NORMAL = 6.5;
const float PH_MAX_NORMAL = 8.5;
const float TDS_WARNING = 500.0;
const float TDS_DANGER = 1000.0;
const float TURBIDITY_WARNING = 50.0;
const float TURBIDITY_DANGER = 80.0;

OneWire oneWire(PIN_ONE_WIRE);
DallasTemperature tempSensor(&oneWire);

float readAdcVoltage(int pin) {
  const int sampleCount = 30;
  long total = 0;

  for (int i = 0; i < sampleCount; i++) {
    total += analogRead(pin);
    delay(5);
  }

  float rawAverage = total / (float)sampleCount;
  return rawAverage * ESP32_ADC_REF_VOLTAGE / ADC_MAX;
}

float readTemperatureC() {
  tempSensor.requestTemperatures();
  float temperatureC = tempSensor.getTempCByIndex(0);

  if (temperatureC < -50 || temperatureC > 125) {
    return NAN;
  }

  return temperatureC;
}

float calculateTds(float voltage, float temperatureC) {
  if (isnan(temperatureC)) {
    temperatureC = 25.0;
  }

  float compensationCoefficient = 1.0 + 0.02 * (temperatureC - 25.0);
  float compensationVoltage = voltage / compensationCoefficient;

  float tdsValue =
    (133.42 * compensationVoltage * compensationVoltage * compensationVoltage
    - 255.86 * compensationVoltage * compensationVoltage
    + 857.39 * compensationVoltage) * 0.5;

  if (tdsValue < 0) {
    tdsValue = 0;
  }

  return tdsValue;
}

float calculatePh(float voltage) {
  float slope = (7.0 - 4.0) / (PH7_VOLTAGE - PH4_VOLTAGE);
  float intercept = 7.0 - slope * PH7_VOLTAGE;
  return slope * voltage + intercept;
}

float calculateTurbidityPercent(float sensorVoltage) {
  float percent =
    (CLEAR_WATER_VOLTAGE - sensorVoltage)
    * 100.0
    / (CLEAR_WATER_VOLTAGE - DIRTY_WATER_VOLTAGE);

  if (percent < 0) percent = 0;
  if (percent > 100) percent = 100;

  return percent;
}

String evaluateWaterStatus(float temperatureC, float ph, float tds, float turbidityPercent) {
  if (isnan(temperatureC) || isnan(ph) || isnan(tds) || isnan(turbidityPercent)) {
    return "SENSOR_ERROR";
  }

  if (ph < 4.0 || ph > 11.0) {
    return "DANGER";
  }

  if (tds >= TDS_DANGER || turbidityPercent >= TURBIDITY_DANGER) {
    return "DANGER";
  }

  if (ph < PH_MIN_NORMAL || ph > PH_MAX_NORMAL || tds >= TDS_WARNING || turbidityPercent >= TURBIDITY_WARNING) {
    return "WARNING";
  }

  return "NORMAL";
}

void updateAlertOutput(String status) {
  if (status == "NORMAL") {
    digitalWrite(PIN_LED_GREEN, HIGH);
    digitalWrite(PIN_LED_RED, LOW);
    digitalWrite(PIN_BUZZER, LOW);
  } else if (status == "WARNING") {
    digitalWrite(PIN_LED_GREEN, LOW);
    digitalWrite(PIN_LED_RED, HIGH);
    digitalWrite(PIN_BUZZER, LOW);
  } else {
    digitalWrite(PIN_LED_GREEN, LOW);
    digitalWrite(PIN_LED_RED, HIGH);
    digitalWrite(PIN_BUZZER, HIGH);
  }
}

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

  analogReadResolution(12);
  analogSetAttenuation(ADC_11db);

  tempSensor.begin();

  pinMode(PIN_BUZZER, OUTPUT);
  pinMode(PIN_LED_GREEN, OUTPUT);
  pinMode(PIN_LED_RED, OUTPUT);

  digitalWrite(PIN_BUZZER, LOW);
  digitalWrite(PIN_LED_GREEN, LOW);
  digitalWrite(PIN_LED_RED, LOW);

  Serial.println("System started");
  Serial.println("ESP32 Water Quality Monitor");
}

void loop() {
  float temperatureC = readTemperatureC();
  float tdsVoltage = readAdcVoltage(PIN_TDS);
  float phVoltage = readAdcVoltage(PIN_PH);
  float turbidityEsp32Voltage = readAdcVoltage(PIN_TURBIDITY);
  float turbiditySensorVoltage = turbidityEsp32Voltage * TURBIDITY_DIVIDER_FACTOR;

  float tds = calculateTds(tdsVoltage, temperatureC);
  float ph = calculatePh(phVoltage);
  float turbidityPercent = calculateTurbidityPercent(turbiditySensorVoltage);

  String status = evaluateWaterStatus(temperatureC, ph, tds, turbidityPercent);
  updateAlertOutput(status);

  Serial.println("====================================");
  Serial.println("ESP32 Water Quality Monitor");
  Serial.print("Temperature: "); Serial.print(temperatureC, 2); Serial.println(" °C");
  Serial.print("TDS Voltage: "); Serial.print(tdsVoltage, 3); Serial.println(" V");
  Serial.print("TDS: "); Serial.print(tds, 1); Serial.println(" ppm");
  Serial.print("pH Voltage: "); Serial.print(phVoltage, 3); Serial.println(" V");
  Serial.print("pH: "); Serial.println(ph, 2);
  Serial.print("Turbidity ESP32 Voltage: "); Serial.print(turbidityEsp32Voltage, 3); Serial.println(" V");
  Serial.print("Turbidity Sensor Voltage: "); Serial.print(turbiditySensorVoltage, 3); Serial.println(" V");
  Serial.print("Turbidity Relative: "); Serial.print(turbidityPercent, 1); Serial.println(" %");
  Serial.print("Status: "); Serial.println(status);
  Serial.println("====================================");
  Serial.println();

  delay(3000);
}

4.3. Kết quả Serial Monitor mong đợi

ESP32 Water Quality Monitor
Temperature: 28.37 °C
TDS Voltage: 0.732 V
TDS: 184.5 ppm
pH Voltage: 2.496 V
pH: 7.02
Turbidity Relative: 2.2 %
Status: NORMAL

Nếu trạng thái là WARNING hoặc DANGER, cần kiểm tra lại mẫu nước, cảm biến và giá trị hiệu chuẩn.