เนื้อหาในบทความ
ภาพรวมโปรเจกต์
ระบบเก็บน้ำฝนอัจฉริยะนี้เหมาะสำหรับฤดูฝนที่กำลังจะมาถึง โดยอัตโนมัติทั้งหมดและสามารถตรวจสอบระดับน้ำในถังเก็บน้ำฝน ควบคุมปั๊มน้ำเพื่อเติมน้ำเมื่อระดับต่ำ และส่งข้อมูลไปยังศูนย์กลางผ่านเครือข่าย LoRaWAN ที่มีระยะทางไกล
คุณสมบัติหลัก
- ✅ ตรวจสอบระดับน้ำแบบเรียลไทม์ด้วยเซ็นเซอร์ Ultrasonic กันน้ำ
- ✅ ควบคุมปั๊มน้ำอัตโนมัติเมื่อระดับน้ำต่ำหรือสูง
- ✅ สื่อสารไกลผ่าน LoRaWAN (ระยะทางได้ถึง 10 กม.)
- ✅ แสดงผลบนจอ OLED และเว็บแดชบอร์ด
- ✅ เตือนภัยผ่าน Line Notify เมื่อมีปัญหา
- ✅ รองรับพลังงานแสงอาทิตย์สำหรับการติดตั้ง outdoor
- ✅ เชื่อมต่อกับแพลตฟอร์ม CynoIoT สำหรับวิเคราะห์ข้อมูล
ข้อควรระวัง: โปรเจกต์นี้เกี่ยวข้องกับไฟฟ้าและน้ำ ควรใช้ความระมัดระวังและติดตั้งอุปกรณ์กันน้ำอย่างเหมาะสม หากไม่มั่นใจ ควรขอคำแนะนำจากช่างผู้เชี่ยวชาญ
อุปกรณ์ที่ต้องใช้
Hardware
Microcontroller
ESP32-C6 (WiFi 6, Bluetooth LE, 802.15.4) - ฿150-250
หรือใช้ HELTEC WiFi LoRa 32 V4 (ESP32-S3 + SX1262)
LoRa Module
SX1262 LoRa transceiver module (868/915 MHz) - ฿200-350
หรือใช้บอร์ดที่มี LoRa in-built (เช่น HELTEC)
Water Level Sensor
JSN-SR04T หรือ AJSR04M Waterproof Ultrasonic Sensor - ฿80-150
ระยะวัด 25cm - 4.5m, กันน้ำ IP67
Relay Module
5V Relay Module (1-channel หรือ 2-channel) - ฿40-80
สำหรับควบคุมปั๊มน้ำ
Display
OLED Display 0.96 inch (I2C) - ฿60-100
แสดงผลระดับน้ำและสถานะระบบ
Power Supply
Solar Panel 5V + TP4056 Charger + 18650 Battery - ฿200-350
สำหรับการติดตั้ง outdoor แบบไม่มีสายไฟ
Software & Tools
- • Arduino IDE 2.x หรือ PlatformIO
- • ESP32 Board Package (เวอร์ชันล่าสุด)
- • Library:
SX126x-Arduino - • Library:
NewPing - • Library:
Adafruit_SSD1306 - • Library:
WiFi,HTTPClient - • CynoIoT Account (ฟรี) - cynoiot.com
- • LoRaWAN Gateway (เช่าหรือสร้างเอง)
การต่อวงจร
ต่อไปนี้คือการเชื่อมต่ออุปกรณ์ต่างๆ กับ ESP32-C6:
// ESP32-C6 Pin Connections:
//
// Ultrasonic Sensor (JSN-SR04T / AJSR04M):
// VCC -> 3.3V หรือ 5V
// GND -> GND
// TRIG -> GPIO 4
// ECHO -> GPIO 5
//
// OLED Display (I2C):
// VCC -> 3.3V
// GND -> GND
// SDA -> GPIO 6
// SCL -> GPIO 7
//
// LoRa Module (SX1262 - SPI):
// VCC -> 3.3V
// GND -> GND
// SCK -> GPIO 15
// MISO -> GPIO 13
// MOSI -> GPIO 12
// NSS -> GPIO 10
// RESET -> GPIO 11
// DIO1 -> GPIO 14
// BUSY -> GPIO 16
//
// Relay Module:
// VCC -> 5V หรือ 3.3V (ตามขนาด)
// GND -> GND
// IN -> GPIO 8
💡 เคล็ดลับ:
- • ใช้ตัวต้านทาน pull-up 10kΩ สำหรับสาย NSS และ RESET ของ LoRa module
- • เพิ่ม capacitor 100µF ข้าม 3.3V และ GND เพื่อกรอง noise
- • วาง antenna ของ LoRa ให้ห่างจาก sensor และ relay
- • ใช้ enclosure กันน้ำ IP65 หรือ IP66 สำหรับ outdoor
ซอฟต์แวร์และโค้ด
โค้ดด้านล่างนี้สำหรับ ESP32-C6 ที่ทำงานเป็น LoRaWAN End Device และส่งข้อมูลระดับน้ำไปยัง Gateway:
#include <Arduino.h>
#include <LoRaWan.h>
#include <NewPing.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h>
// ===== ตั้งค่า LoRaWAN =====
// แก้ไขค่าตาม LoRaWAN Network ของคุณ (The Things Network หรือ ChirpStack)
#define LORA_WAKE_FREQ 923200000 // ความถี่ 923.2 MHz (ไทย)
#define LORA_WAKE_TX_POWER 20 // กำลังส่ง 20 dBm
#define LORA_WAKE_SPREADING 7 // Spreading Factor 7
#define LORA_WAKE_BANDWIDTH 125 // Bandwidth 125 kHz
// LoRaWAN Keys (ต้องแก้ไขตามที่ได้จาก LoRaWAN Network Server)
#define DEV_EUI "YOUR_DEV_EUI" // Device EUI
#define APP_EUI "YOUR_APP_EUI" // Application EUI
#define APP_KEY "YOUR_APP_KEY" // Application Key
// ===== ตั้งค่า Sensor =====
#define TRIGGER_PIN 4
#define ECHO_PIN 5
#define MAX_DISTANCE 450 // ระยะสูงสุด 450 cm
#define TANK_HEIGHT 200 // ความสูงถังน้ำ 200 cm
#define TANK_RADIUS 100 // รัศมีถังน้ำ 100 cm
// ===== ตั้งค่า OLED =====
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// ===== ตั้งค่า Relay =====
#define PUMP_RELAY_PIN 8
// ===== ตั้งค่าระดับน้ำ =====
#define WATER_LEVEL_LOW 30 // 30% - เปิดปั๊ม
#define WATER_LEVEL_HIGH 80 // 80% - ปิดปั๊ม
// สร้าง object
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
// ตัวแปรสำหรับเก็บข้อมูล
float waterLevel = 0; // ระดับน้ำเป็นเปอร์เซ็นต์
float waterVolume = 0; // ปริมาณน้ำเป็นลิตร
bool pumpStatus = false; // สถานะปั๊ม
// ฟังก์ชันสำหรับส่งข้อมูลผ่าน LoRaWAN
void sendLoRaMessage() {
// สร้าง payload (2 bytes: water level 0-100, pump status 0/1)
uint8_t payload[2];
payload[0] = (uint8_t)waterLevel;
payload[1] = pumpStatus ? 1 : 0;
// ส่งข้อมูลผ่าน LoRaWAN
if (LoRaWAN.send(payload, sizeof(payload), 1, false)) {
Serial.println("LoRaWAN message sent successfully");
// แสดงผลบน OLED
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Data sent via LoRaWAN");
display.print("Level: ");
display.print(waterLevel);
display.println("%");
display.print("Pump: ");
display.println(pumpStatus ? "ON" : "OFF");
display.display();
} else {
Serial.println("Failed to send LoRaWAN message");
}
}
// ฟังก์ชันวัดระดับน้ำ
void measureWaterLevel() {
// วัดระยะทางจาก sensor ไปยังผิวน้ำ
unsigned int distance = sonar.ping_cm();
if (distance == 0) {
distance = MAX_DISTANCE; // ถ้าไม่พบวัตถุ ให้ถือว่าเป็นระยะสูงสุด
}
// คำนวณระดับน้ำเป็นเปอร์เซ็นต์
float emptySpace = distance; // พื้นที่ว่างเหนือน้ำ
waterLevel = ((TANK_HEIGHT - emptySpace) / TANK_HEIGHT) * 100;
// จำกัดค่าระหว่าง 0-100
if (waterLevel < 0) waterLevel = 0;
if (waterLevel > 100) waterLevel = 100;
// คำนวณปริมาณน้ำ (ลิตร)
// ปริมาตรถัง = π × r² × h
float tankVolume = 3.14159 * (TANK_RADIUS * TANK_RADIUS) * TANK_HEIGHT / 1000; // ลิตร
waterVolume = tankVolume * (waterLevel / 100);
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
Serial.print("Water Level: ");
Serial.print(waterLevel);
Serial.println("%");
Serial.print("Volume: ");
Serial.print(waterVolume);
Serial.println(" liters");
}
// ฟังก์ชันควบคุมปั๊มน้ำ
void controlPump() {
if (waterLevel <= WATER_LEVEL_LOW && !pumpStatus) {
// ระดับน้ำต่ำ - เปิดปั๊ม
digitalWrite(PUMP_RELAY_PIN, HIGH);
pumpStatus = true;
Serial.println("Pump turned ON");
// ส่งแจ้งเตือน (ตัวอย่าง: เชื่อมต่อกับ CynoIoT ในฟังก์ชันถัดไป)
sendAlert("Pump started");
} else if (waterLevel >= WATER_LEVEL_HIGH && pumpStatus) {
// ระดับน้ำสูง - ปิดปั๊ม
digitalWrite(PUMP_RELAY_PIN, LOW);
pumpStatus = false;
Serial.println("Pump turned OFF");
sendAlert("Pump stopped");
}
}
// ฟังก์ชันแสดงผลบน OLED
void updateDisplay() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
// หัวข้อ
display.setCursor(0, 0);
display.println("Rainwater System");
// ระดับน้ำ
display.setCursor(0, 16);
display.print("Level: ");
display.print(waterLevel, 1);
display.println("%");
// ปริมาณน้ำ
display.setCursor(0, 26);
display.print("Volume: ");
display.print(waterVolume, 0);
display.println(" L");
// สถานะปั๊ม
display.setCursor(0, 36);
display.print("Pump: ");
display.println(pumpStatus ? "ON " : "OFF");
// สถานะ LoRaWAN
display.setCursor(0, 46);
display.print("LoRa: ");
display.println(LoRaWAN.isJoined() ? "Connected" : "Disconnected");
// Battery
display.setCursor(0, 56);
display.print("Battery: ");
display.print(getBatteryVoltage());
display.println("V");
display.display();
}
// ฟังก์ชันอ่านแรงดันแบตเตอรี่ (ตัวอย่าง)
float getBatteryVoltage() {
// สำหรับ ESP32-C6 ที่มี ADC บน pin ขาด
// ต้องต่อ voltage divider เพื่อวัด 0-5V
// นี่คือตัวอย่างง่ายๆ ควรปรับแต่งตาม hardware จริง
return 3.7; // ค่าจำลอง
}
// ฟังก์ชันส่งแจ้งเตือนไปยัง CynoIoT
void sendAlert(String message) {
// เชื่อมต่อ WiFi และส่งข้อมูลไปยัง CynoIoT API
// (ดูรายละเอียดในหัวข้อถัดไป)
Serial.print("Alert: ");
Serial.println(message);
}
void setup() {
Serial.begin(115200);
while (!Serial);
Serial.println("\n=== Rainwater Harvesting System ===");
// ตั้งค่า pins
pinMode(PUMP_RELAY_PIN, OUTPUT);
digitalWrite(PUMP_RELAY_PIN, LOW); // เริ่มต้นปิดปั๊ม
// เริ่มต้น OLED
Wire.begin(6, 7); // SDA=GPIO6, SCL=GPIO7
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("Failed to start OLED");
while (1);
}
display.display();
delay(2000);
// แสดงข้อความเริ่มต้น
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 20);
display.println("Starting...");
display.display();
// เริ่มต้น LoRaWAN
LoRaWAN.begin(
LORA_WAKE_FREQ,
LORA_WAKE_TX_POWER,
LORA_WAKE_SPREADING,
LORA_WAKE_BANDWIDTH
);
// เข้าร่วม LoRaWAN network
if (LoRaWAN.join(DEV_EUI, APP_EUI, APP_KEY)) {
Serial.println("Joined LoRaWAN network successfully");
} else {
Serial.println("Failed to join LoRaWAN network");
}
// เชื่อมต่อ WiFi (สำหรับ CynoIoT)
WiFi.begin("YOUR_WIFI_SSID", "YOUR_WIFI_PASSWORD");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
delay(2000);
}
void loop() {
// วัดระดับน้ำ
measureWaterLevel();
// ควบคุมปั๊ม
controlPump();
// อัปเดตหน้าจอ
updateDisplay();
// ส่งข้อมูลผ่าน LoRaWAN (ทุก 5 นาที)
static unsigned long lastSend = 0;
if (millis() - lastSend > 300000) { // 5 นาที
sendLoRaMessage();
lastSend = millis();
}
delay(5000); // วัดทุก 5 วินาที
}
หมายเหตุ: นี่คือโค้ดพื้นฐาน คุณต้องแก้ไข DEV_EUI, APP_EUI, APP_KEY ตามที่ได้จาก LoRaWAN Network Server ของคุณ (เช่น The Things Network หรือ ChirpStack)
การตั้งค่า LoRaWAN
LoRaWAN เป็นเทคโนโลยี wireless ที่เหมาะสำหรับ IoT ที่ต้องการระยะทางไกลและใช้พลังงานต่ำ นี่คือขั้นตอนการตั้งค่า:
1. สมัครบัญชี LoRaWAN Network Server
มีหลาย platform ให้เลือก แนะนำสำหรับผู้เริ่มต้น:
- The Things Network (TTN) - ฟรี ใช้งานง่าย มี community ที่ดี (thethingsnetwork.org)
- ChirpStack - Open-source สามารถ self-host ได้ (chirpstack.io)
- Helium - Decentralized network ที่มี coverage ทั่วโลก (helium.com)
2. สร้าง Application และ Device
ใน TTN Console:
- สร้าง Application ใหม่ (เลือก name และ description)
- เพิ่ม Device ใหม่ใน Application
- เลือก "LoRaWAN 1.0.3" และ "ABP" หรือ "OTAA" activation mode
- บันทึก DEV_EUI, APP_EUI และ APP_KEY ที่ได้
3. ตั้งค่า Gateway (ถ้าจำเป็น)
ถ้าพื้นที่ของคุณไม่มี LoRaWAN Gateway cover คุณอาจต้อง:
- ซื้อ LoRaWAN Gateway (เช่น RAK831, Mikrotik)
- สร้าง DIY Gateway ด้วย Raspberry Pi + LoRa HAT
- เช่าบริการ LoRaWAN network จากผู้ให้บริการในไทย
💡 เคล็ดลับ:
ใช้ OTAA (Over-The-Air Activation) สำหรับ production เพราะมีความปลอดภัยกว่า แต่ใช้ ABP (Activation By Personalization) สำหรับการทดสอบเพราะตั้งค่าง่ายกว่า
เชื่อมต่อ CynoIoT Platform
CynoIoT เป็นแพลตฟอร์มที่ช่วยให้คุณเก็บข้อมูล วิเคราะห์ และแสดงผลข้อมูล IoT ได้อย่างง่าย:
การเชื่อมต่อพื้นฐาน
// เพิ่มฟังก์ชันนี้ในโค้ดของคุณ:
#include <WiFi.h>
#include <HTTPClient.h>
const char* cynoiotApiKey = "YOUR_CYNOIOT_API_KEY";
const char* cynoiotDeviceId = "YOUR_DEVICE_ID";
// ฟังก์ชันส่งข้อมูลไปยัง CynoIoT
void sendToCynoIoT(float level, float volume, bool pump) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi not connected");
return;
}
HTTPClient http;
http.begin("https://api.cynoiot.com/v1/data");
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", cynoiotApiKey);
// สร้าง JSON payload
String payload = "{";
payload += "\"device_id\":\"" + String(cynoiotDeviceId) + "\",";
payload += "\"data\":{";
payload += "\"water_level\":" + String(level) + ",";
payload += "\"water_volume\":" + String(volume) + ",";
payload += "\"pump_status\":" + String(pump ? "true" : "false");
payload += "}}";
int httpResponseCode = http.POST(payload);
if (httpResponseCode > 0) {
Serial.print("CynoIoT Response: ");
Serial.println(httpResponseCode);
String response = http.getString();
Serial.println(response);
} else {
Serial.print("Error sending to CynoIoT: ");
Serial.println(httpResponseCode);
}
http.end();
}
// เรียกใช้ใน loop():
if (millis() - lastCynoIoTSend > 60000) { // ทุก 1 นาที
sendToCynoIoT(waterLevel, waterVolume, pumpStatus);
lastCynoIoTSend = millis();
}
การตั้งค่า Dashboard ใน CynoIoT
- สมัครบัญชีที่ cynoiot.com
- สร้าง Device ใหม่และบันทึก Device ID และ API Key
- สร้าง Dashboard และเพิ่ม widgets:
- Gauge Chart สำหรับระดับน้ำ (%)
- Line Chart แสดงประวัติระดับน้ำ
- Status Indicator สำหรับสถานะปั๊ม
- Text Widget แสดงปริมาณน้ำ (ลิตร)
- ตั้งค่า Alert rules (เช่น แจ้งเตือนเมื่อระดับน้ำ < 20%)
การทดสอบระบบ
1. ทดสอบ Ultrasonic Sensor
- ใช้ Serial Monitor ตรวจสอบระยะทางที่วัดได้
- ทดสอบโดยวาง object ที่ระยะต่างๆ (10cm, 50cm, 100cm)
- ตรวจสอบค่าที่แสดงบน OLED
2. ทดสอบ Relay และ Pump
- เชื่อมต่อ relay กับมัลติมิเตอร์เพื่อตรวจสอบการทำงาน
- ทดสอบด้วยการใส่น้ำในถังจริง หรือจำลองด้วยการเคลื่อนย้าย sensor
- ตรวจสอบว่าปั๊มเปิดเมื่อน้ำต่ำและปิดเมื่อน้ำเต็ม
3. ทดสอบ LoRaWAN
- ตรวจสอบใน TTN Console ว่ามีข้อมูลเข้ามาหรือไม่
- ตรวจสอบ Signal Strength (RSSI) และ Signal-to-Noise Ratio (SNR)
- ทดสอบระยะทางจริงโดยย้าย device ไปไกลๆ
4. ทดสอบ CynoIoT Integration
- ตรวจสอบว่าข้อมูลปรากฏใน Dashboard หรือไม่
- ทดสอบการแจ้งเตือน (Alerts) โดยจงใจสร้างสถานการณ์ผิดปกติ
- ตรวจสอบ Historical Data ว่าบันทึกถูกต้องหรือไม่
⚠️ ปัญหาที่พบบ่อยและวิธีแก้ไข:
- Sensor วัดระยะไม่ได้: ตรวจสอบการต่อสาย VCC/GND และลองเปลี่ยนตำแหน่งตั้งค่า sensor
- LoRaWAN เชื่อมต่อไม่ได้: ตรวจสอบ DEV_EUI, APP_EUI, APP_KEY และ frequency (923.2 MHz สำหรับไทย)
- Relay ทำงานไม่ถูกต้อง: ตรวจสอบว่าใช้ 5V relay หรือ 3.3V relay และต่อสาย GND ร่วมกัน
- OLED ไม่ติด: ตรวจสอบ I2C address (โดยปกติ 0x3C หรือ 0x3D) และการต่อสาย SDA/SCL
สรุป
ในบทความนี้ คุณได้เรียนรู้วิธีสร้างระบบเก็บน้ำฝนอัจฉริยะที่:
- ✅ ตรวจสอบระดับน้ำอัตโนมัติด้วย ultrasonic sensor
- ✅ ควบคุมปั๊มน้ำอัตโนมัติ
- ✅ ส่งข้อมูลไกลผ่าน LoRaWAN ได้ถึง 10 กม.
- ✅ เชื่อมต่อกับ CynoIoT Platform สำหรับ monitoring และ analytics
- ✅ ทำงานด้วยพลังงานแสงอาทิตย์ได้
ถัดไป
- • เพิ่ม sensor วัด pH และ EC สำหรับระบบ hydroponics
- • สร้าง Mobile App สำหรับ monitoring ระยะไกล
- • เพิ่ม AI/ML สำหรับทำนายปริมาณน้ำฝน
- • เชื่อมต่อกับ Home Assistant สำหรับ automation ภายในบ้าน
หากคุณชอบบทความนี้ อย่าลืมแชร์ให้เพื่อนๆ และติดตามบทความเกี่ยวกับ ESP32, IoT และ electronics เพิ่มเติม: