📑 เนื้อหาในบทความ
ภาพรวมโปรเจกต์
ระบบติดตามสุขภาพพืช (Plant Monitoring System) เป็นโปรเจกต์ IoT ที่น่าสนใจและมีประโยชน์จริง ช่วยให้คุณติดตามความต้องการน้ำของพืช อุณหภูมิ และความชื้นในอากาศได้ตลอดเวลา ไม่ว่าจะอยู่ที่ไหนก็ตาม ผ่านแอปบนมือถือ
ในบทความนี้ เราจะใช้ ESP32 เป็นไมโครคอนโทรลเลอร์หลัก เพราะมี WiFi และ Bluetooth ในตัว ราคาถูก และประหยัดไฟ ประกอบกับเซ็นเซอร์ 3 ตัว:
- Soil Moisture Sensor - วัดความชื้นในดิน
- DHT22 Sensor - วัดอุณหภูมิและความชื้นในอากาศ
- Light Sensor (LDR) - วัดความเข้มแสง (ถ้าต้องการ)
💡 เคล็ดลับ: พืชแต่ละชนิดต้องการความชื้นและแสงที่ต่างกัน คุณสามารถปรับแต่งค่า threshold ในโค้ดให้เหมาะกับพืชของคุณได้
🛠️ อุปกรณ์ที่ต้องใช้
Hardware Components
| อุปกรณ์ | จำนวน | ราคาโดยประมาณ |
|---|---|---|
| ESP32 DevKitC | 1 | ฿120-150 |
| Soil Moisture Sensor | 1 | ฿40-60 |
| DHT22 Sensor (AM2302) | 1 | ฿60-80 |
| Resistor 10kΩ | 1 | ฿1-2 |
| Jumper Wires | 1 ชุด | ฿30-50 |
| Breadboard | 1 | ฿30-50 |
| USB Cable (Micro USB) | 1 | ฿20-40 |
| Power Bank (Optional) | 1 | ฿100-200 |
📱 Software & Tools
- ✅ Arduino IDE (หรือ PlatformIO)
- ✅ CynoIoT Account (สมัครฟรี)
- ✅ USB Driver สำหรับ ESP32
- ✅ DHT Sensor Library
🔌 การต่อวงจร
ตารางการต่อสาย (Pinout)
| เซ็นเซอร์ | ขาเซ็นเซอร์ | ESP32 Pin |
|---|---|---|
| Soil Moisture | Signal | GPIO 34 (ADC1_CH6) |
| VCC | 3.3V | |
| GND | GND | |
| DHT22 | Signal | GPIO 4 |
| VCC | 3.3V | |
| GND | GND |
⚠️ คำเตือน: Soil Moisture Sensor เป็นเซ็นเซอร์แบบ analog ต้องต่อเข้ากับขา ADC เท่านั้น และหลีกเลี่ยงการใช้ขา ADC2 (GPIO 0, 2, 4, 12-15, 25-27) เพราะจะใช้งานไม่ได้เมื่อเปิด WiFi
📐 แผนผังการต่อวงจร
[รูปภาพ Fritzing Diagram จะแสดงที่นี่]
ESP32 DevKit | Soil Moisture Sensor | DHT22 Sensor
💻 การเขียนโปรแกรม
ขั้นตอนที่ 1: ติดตั้ง Library
เปิด Arduino IDE และไปที่ Sketch → Include Library → Manage Libraries ค้นหาและติดตั้ง:
- "DHT sensor library" โดย Adafruit
- "Adafruit Unified Sensor"
ขั้นตอนที่ 2: โค้ดทั้งหมด
/*
* DIY Plant Monitoring System with ESP32
* วัดความชื้นในดิน, อุณหภูมิ, และความชื้นในอากาศ
* เชื่อมต่อกับ CynoIoT Platform
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <DHT.h>
// ===== WiFi Credentials =====
const char* ssid = "YOUR_WIFI_SSID"; // แทนที่ด้วยชื่อ WiFi ของคุณ
const char* password = "YOUR_WIFI_PASSWORD"; // แทนที่ด้วยรหัส WiFi ของคุณ
// ===== CynoIoT Configuration =====
const char* cynoiot_server = "api.cynoiot.com"; // เปลี่ยนเป็น server จริง
const char* device_id = "YOUR_DEVICE_ID"; // แทนที่ด้วย Device ID ของคุณ
const char* api_key = "YOUR_API_KEY"; // แทนที่ด้วย API Key ของคุณ
// ===== Sensor Pin Definitions =====
#define SOIL_MOISTURE_PIN 34 // GPIO 34 (ADC1_CH6) - สำหรับ Soil Moisture Sensor
#define DHT_PIN 4 // GPIO 4 - สำหรับ DHT22
#define DHT_TYPE DHT22 // ชนิดของ DHT Sensor
// ===== Threshold Values =====
const int SOIL_DRY_THRESHOLD = 2000; // ค่าที่ถือว่าดินแห้ง (0-4095)
const int SOIL_WET_THRESHOLD = 1000; // ค่าที่ถือว่าดินชื้น (0-4095)
// ===== Sensor Objects =====
DHT dht(DHT_PIN, DHT_TYPE);
// ===== Variables =====
float temperature = 0;
float humidity = 0;
int soilMoisture = 0;
unsigned long lastTime = 0;
const long interval = 5000; // ส่งข้อมูลทุก 5 วินาที
void setup() {
// เริ่มต้น Serial Monitor สำหรับ Debug
Serial.begin(115200);
delay(1000);
Serial.println("\n=== Plant Monitoring System ===");
Serial.println("กำลังเริ่มต้นระบบ...");
// เริ่มต้น DHT Sensor
dht.begin();
Serial.println("✓ DHT Sensor เริ่มทำงานแล้ว");
// ตั้งค่า Pin Mode
pinMode(SOIL_MOISTURE_PIN, INPUT);
// เชื่อมต่อ WiFi
connectWiFi();
}
void loop() {
unsigned long currentTime = millis();
// อ่านค่าเซ็นเซอร์ทุก 5 วินาที
if (currentTime - lastTime >= interval) {
lastTime = currentTime;
// อ่านค่าจากเซ็นเซอร์ทั้งหมด
readSensors();
// แสดงผลใน Serial Monitor
displaySensorData();
// ส่งข้อมูลไปยัง CynoIoT
sendToCynoIoT();
// ตรวจสอบสถานะพืช
checkPlantStatus();
}
}
// ===== WiFi Connection =====
void connectWiFi() {
Serial.print("กำลังเชื่อมต่อ WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n✓ เชื่อมต่อ WiFi สำเร็จ!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("\n✗ ไม่สามารถเชื่อมต่อ WiFi ได้");
Serial.println("จะลองเชื่อมต่อใหม่ใน 1 นาที...");
}
}
// ===== Read Sensors =====
void readSensors() {
// อ่านค่าอุณหภูมิและความชื้นจาก DHT22
temperature = dht.readTemperature();
humidity = dht.readHumidity();
// ตรวจสอบว่าอ่านค่าสำเร็จหรือไม่
if (isnan(temperature) || isnan(humidity)) {
Serial.println("✗ ไม่สามารถอ่านค่าจาก DHT22 ได้!");
temperature = 0;
humidity = 0;
}
// อ่านค่าความชื้นในดิน (0-4095)
soilMoisture = analogRead(SOIL_MOISTURE_PIN);
// แปลงค่าเป็นเปอร์เซ็นต์ (ยิ่งต่วย่างแห้ง)
int soilPercent = map(soilMoisture, 0, 4095, 100, 0);
soilMoisture = soilPercent;
}
// ===== Display Sensor Data =====
void displaySensorData() {
Serial.println("\n--- ข้อมูลเซ็นเซอร์ ---");
Serial.printf("อุณหภูมิ: %.2f °C\n", temperature);
Serial.printf("ความชื้นอากาศ: %.2f %%\n", humidity);
Serial.printf("ความชื้นในดิน: %d %%\n", soilMoisture);
}
// ===== Send Data to CynoIoT =====
void sendToCynoIoT() {
// ตรวจสอบสถานะ WiFi
if (WiFi.status() != WL_CONNECTED) {
Serial.println("✗ WiFi ไม่ได้เชื่อมต่ออยู่ กำลังเชื่อมต่อใหม่...");
connectWiFi();
return;
}
// สร้าง JSON Payload
String payload = "{";
payload += "\"temperature\":" + String(temperature) + ",";
payload += "\"humidity\":" + String(humidity) + ",";
payload += "\"soil_moisture\":" + String(soilMoisture);
payload += "}";
// ส่ง HTTP Request
HTTPClient http;
String url = "http://" + String(cynoiot_server) + "/api/v1/devices/" + String(device_id) + "/data";
http.begin(url);
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", "Bearer " + String(api_key));
int httpResponseCode = http.POST(payload);
if (httpResponseCode > 0) {
Serial.print("✓ ส่งข้อมูลไปยัง CynoIoT สำเร็จ! Response: ");
Serial.println(httpResponseCode);
} else {
Serial.print("✗ ไม่สามารถส่งข้อมูลได้ Error: ");
Serial.println(httpResponseCode);
}
http.end();
}
// ===== Check Plant Status =====
void checkPlantStatus() {
Serial.println("\n--- สถานะพืช ---");
// ตรวจสอบความชื้นในดิน
if (soilMoisture < 30) {
Serial.println("⚠️ ดินแห้งมาก! ควรรดน้ำพืชทันที");
} else if (soilMoisture < 50) {
Serial.println("ℹ️ ดินเริ่มแห้ง ควรรดน้ำเร็วๆ นี้");
} else if (soilMoisture > 80) {
Serial.println("⚠️ ดินชื้นเกินไป อาจทำให้รากเน่าได้");
} else {
Serial.println("✓ ความชื้นในดินปกติ");
}
// ตรวจสอบอุณหภูมิ
if (temperature > 35) {
Serial.println("⚠️ อุณหภูมิสูงเกินไป พืชอาจเครียดได้");
} else if (temperature < 15) {
Serial.println("ℹ️ อุณหภูมิต่ำ พืชอาจเจริญเติบโตช้าลง");
}
// ตรวจสอบความชื้นในอากาศ
if (humidity < 30) {
Serial.println("ℹ️ อากาศแห้ง ควรพ่นหมอกให้พืช");
} else if (humidity > 80) {
Serial.println("⚠️ อากาศชื้นเกินไป อาจเกิดเชื้อราได้");
}
}🌐 เชื่อมต่อกับ CynoIoT Platform
ขั้นตอนการตั้งค่า CynoIoT
- สมัครบัญชี CynoIoT:
- ไปที่ cynoiot.com
- คลิก "Sign Up" และกรอกข้อมูล
- ยืนยันอีเมล
- สร้างอุปกรณ์ใหม่:
- ไปที่ Dashboard → Devices → Add Device
- เลือก "ESP32" เป็นประเภทอุปกรณ์
- ตั้งชื่ออุปกรณ์ เช่น "Plant Monitor"
- รับ Device ID และ API Key:
- คลิกที่อุปกรณ์ที่สร้าง
- คัดลอก Device ID
- ไปที่ Settings → API Keys
- สร้าง API Key ใหม่และคัดลอก
- อัปโหลดโค้ด:
- ใส่ WiFi credentials ของคุณ
- ใส่ Device ID และ API Key
- อัปโหลดโค้ดไปยัง ESP32
✅ เคล็ดลับ: คุณสามารถตั้งค่า Alert ใน CynoIoT เพื่อให้แจ้งเตือนผ่าน Line, Email หรือแอปเมื่อความชื้นในดินต่ำกว่าค่าที่กำหนด
🧪 การทดสอบระบบ
ขั้นตอนการทดสอบ
- ทดสอบ Soil Moisture Sensor:
- แช่เซ็นเซอร์ในน้ำ - ค่าควรอยู่ที่ 80-100%
- ปล่อยให้แห้งในอากาศ - ค่าควรอยู่ที่ 0-20%
- ตรวจสอบใน Serial Monitor
- ทดสอบ DHT22:
- เป่าลมเข้าไป - อุณหภูมิควรเพิ่มขึ้น
- ตรวจสอบค่าความชื้นที่สมเหตุสมผล (30-70%)
- ทดสอบการเชื่อมต่อ CynoIoT:
- ตรวจสอบ Serial Monitor ว่าแสดง "ส่งข้อมูลสำเร็จ"
- ไปที่ CynoIoT Dashboard
- ดูว่าข้อมูลมาถึงหรือไม่
- ทดสอบในกระถางพืชจริง:
- แท่งเซ็นเซอร์ลงในดิน
- รอสักครู่ให้ค่าเสถียร
- รดน้ำและสังเกตการเปลี่ยนแปลง
💡 ข้อแนะนำ: ให้เซ็นเซอร์แช่ในดินลึกประมาณ 2-3 ซม. เพื่อให้ได้ค่าที่แม่นยำ และหลีกเลี่ยงการใส่เซ็นเซอร์ส่วนที่เป็นวงจร (head) ลงในน้ำ
🔧 การแก้ปัญหา
ปัญหาที่ 1: DHT22 อ่านค่าไม่ได้ หรือค่าเป็น NaN
อาการ: Serial Monitor แสดง "✗ ไม่สามารถอ่านค่าจาก DHT22 ได้!"
สาเหตุ:
- ต่อสายผิดขา
- ใช้เซ็นเซอร์ของเกิด (DHT11 แต่ตั้งเป็น DHT22)
- ไม่ได้ต่อ Resistor 10kΩ ระหว่าง VCC และ Signal
วิธีแก้ไข:
- ตรวจสอบการต่อสายใหม่
- ตรวจสอบว่าตั้งค่า DHT_TYPE ถูกต้อง
- เพิ่ม Resistor 10kΩ
ปัญหาที่ 2: Soil Moisture Sensor ค่าไม่เปลี่ยน
อาการ: ค่าความชื้นในดินอยู่ที่ 0% หรือ 100% ตลอดเวลา
สาเหตุ:
- เซ็นเซอร์เสีย
- ต่อขา ADC2 ซึ่งไม่ทำงานเมื่อเปิด WiFi
- เซ็นเซอร์ไม่ได้แช่ในดินจริง
วิธีแก้ไข:
- ลองเปลี่ยนเซ็นเซอร์ตัวใหม่
- ย้ายไปใช้ขา ADC1 (เช่น GPIO 34, 35, 36, 39)
- แช่เซ็นเซอร์ในน้ำเพื่อทดสอบ
ปัญหาที่ 3: เชื่อมต่อ CynoIoT ไม่ได้
อาการ: Serial Monitor แสดง "✗ ไม่สามารถส่งข้อมูลได้ Error: -1"
สาเหตุ:
- WiFi เชื่อมต่อไม่ได้
- Device ID หรือ API Key ผิด
- Server URL ผิด
วิธีแก้ไข:
- ตรวจสอบ WiFi credentials
- คัดลอก Device ID และ API Key ใหม่
- ตรวจสอบ Server URL ว่าถูกต้อง
- ลองส่ง HTTP request ด้วย Postman เพื่อทดสอบ
ปัญหาที่ 4: ESP32 รีบูตเอง
อาการ: ESP32 รีสตาร์ทเองบ่อยๆ
สาเหตุ:
- ไฟไม่เพียงพอ
- Short circuit
- โค้ดมีปัญหา
วิธีแก้ไข:
- ใช้แหล่งจ่ายไฟที่เสถียร (2A ขึ้นไป)
- ตรวจสอบการต่อสายว่า short หรือไม่
- ตรวจสอบ Serial Monitor ดูว่ารีบูตตอนไหน
🚀 ขั้นตอนถัดไป
ยินดีด้วย! คุณได้สร้างระบบติดตามสุขภาพพืชเบื้องต้นเรียบร้อยแล้ว ต่อไปนี้คือไอเดียในการพัฒนาต่อ:
- เพิ่ม Water Pump: ต่อรีเลย์และปั้มน้ำอัตโนมัติ เพื่อรดน้ำอัตโนมัติเมื่อดินแห้ง
- เพิ่ม Light Sensor: วัดความเข้มแสงเพื่อควบคุม grow light
- ประหยัดไฟ: ใช้ Deep Sleep Mode เพื่อให้แบตอยู่นานขึ้น (ดูบทความ ESP32 Deep Sleep)
- Dashboard: สร้างกราฟและ Analytics ใน CynoIoT Dashboard
- Notifications: ตั้งค่าแจ้งเตือนผ่าน Line หรือ Telegram