ESP32 วัดความชื้นแบบไร้สาย — ใช้แบต 18650 อยู่ได้ 14 เดือน!
ไม่มีระบบรดน้ำอัตโนมัติ ก็ใช้ได้ — แค่เสียบ Capacitive Sensor ลงกระถาง แล้ว ESP32 จะส่งค่าความชื้นเข้าเว็บให้ดูผ่านมือถือ พร้อมแจ้งเตือนเมื่อดินแหง
💡 แนวคิด: ไม่อยากติดตั้งระบบรดน้ำทั้งระบบ แต่อยากรู้ว่าต้นไม้ต้องการน้ำเมื่อไหร่ — ESP32 ก้อนเดียวใช้ 18650 วัดความชื้นทุก 1 ชม. ส่งค่า HTTP GET เข้าเว็บ แค่นี้ก็รู้แล้วว่าควรรดน้ำตอนไหน
แผนผังระบบ 3.7V (18650)
🔋 18650 Li-ion 2,600 mAh
|
[TP4056 Charger + Protection]
| (USB-C ชารจ์ได ใช Powerbank ก็ได)
|
ESP32 Dev Board (VIN → 5V)
|
+-- 3.3V -- Capacitive Sensor v1.2 (VCC)
+-- GND -- Capacitive Sensor v1.2 (GND)
+-- GPIO34 -- Capacitive Sensor v1.2 (SIG/AOUT)
|
[Deep Sleep 1 ชม.] → ตื่น 8 วิ → WiFi → HTTP GET → เขา Deep Sleep
✅ ใชแค 3 สายตอ Sensor: VCC→3.3V, GND→GND, SIG→GPIO34 — ไมตอง Step Down ไมตองสายไฟยาว!
3 โหมดการใชงาน
| โหมด | กระแส | เวลาตอรอบ (1 ชม.) |
|---|---|---|
| 😴 Deep Sleep | ~60µA (ESP32 + TP4056) | 59 นาที 52 วิ |
| 📡 ตื่น + WiFi + อาน Sensor + HTTP GET | ~85mA | ~8 วินาที |
| ⚡ เฉลี่ยตอชั่วโมง | ~0.25 mAh | — |
อายุแบตตามความจุ
| แบต | ความจุ | อายุการใชงาน |
|---|---|---|
| 🔋 18650 ทั่วไป | 2,600 mAh | ~14 เดือน |
| 🔋 18650 จอใหญ (Samsung 35E, LG MJ1) | 3,500 mAh | ~19 เดือน |
| 🔋 14500 (AA size) | 800 mAh | ~4.4 เดือน |
| 🔋 18650 Protected (UF, NCR) | 3,400 mAh | ~18 เดือน |
🏆 18650 กอนเดียว > 1 ป — วัดทุก 1 ชม. โดยไมตองชารจ ถาใช 3,500 mAh อยูไดเกือบ 2 ป!
ราคาตอชุด (ไมตอง 12V)
| อุปกรณ | ราคาประมาณ |
|---|---|
| ESP32 Dev Board (ESP32-WROOM-32) | ~120-200 บาท |
| Capacitive Soil Sensor v1.2 | ~50-80 บาท |
| TP4056 Charger Module + Protection | ~10-20 บาท |
| 18650 Holder (รวมสาย) | ~5-15 บาท |
| 🔋 18650 2,600 mAh | ~80-150 บาท |
| Resistor 10kΩ + Capacitor 100µF | ~7 บาท |
| กลอง ABS กันน้ำ (4x3x2 cm) | ~20-50 บาท |
| สายไฟ + Header + ขั้วตอ | ~10-20 บาท |
| รวม (พรอมแบต 18650) | ~302-542 บาท |
| รวม (เฉพาะกลอง ไมรวมแบต) | ~222-392 บาท |
เทียบราคากับระบบ 12V
| หัวขอ | 12V + Step Down | 3.7V 18650 |
|---|---|---|
| ราคารวม | ~237-407 บ. | ~222-392 บ. 🏆 |
| ราคารวม + แบต | + แบตมอไซค 12V 7Ah ~250 บ. = ~487-657 บ. | + 18650 2.6Ah ~80-150 บ. = ~302-542 บ. 🏆 |
| ขนาดกลอง | ตอง Step Down + แบตใหญ | เล็กกวา ไซซกระปุกออมสิน 🏆 |
| อายุแบต | 12V 7Ah อยูไดหลายเดือน | 18650 2.6Ah อยูได ~14 เดือน 🏆 |
| การชารจ | ตองถอดแบตไปชารจ หรือติด Solar | TP4056 — เสียบ USB Micro ไดเลย 🏆 |
| วางกระถางไหน | ตองพึ่งระบบรดน้ำ 12V | วางที่ไหนก็ได ไมตองพึ่งระบบอะไร 🏆 |
| กันน้ำ | กลองกลาง + กลองยอย | กลองเดียวจบ |
Arduino Code — ESP32 + 18650 + Deep Sleep ทุก 1 ชม.
/*
* ESP32 Soil Moisture Sensor — 3.7V 18650
* วัดทุก 1 ชม. สง HTTP GET ไปเว็บ
* Deep Sleep ระหวางรอบ — แบตอยู 14 เดือน
*
* 🧠 เนื้อหาคนควาและเรียบเรียงโดย AI — ตรวจสอบกอนนำไปใช
*/
#include <WiFi.h>
#include <HTTPClient.h>
// ==== WiFi ====
const char* ssid = "your_wifi";
const char* password = "your_password";
// ==== Server ====
const char* serverUrl = "https://YOUR_DOMAIN/api/moisture.php";
// ==== Device Config ====
const char* device_id = "sensor01"; // เปลี่ยนตามกลอง
const char* port_id = "A0";
// ==== Sensor ====
#define SENSOR_PIN 34 // GPIO34 (ADC)
#define DRY_LEVEL 3000 // ปรับตาม Sensor
#define WET_LEVEL 1200 // ปรับตาม Sensor
// ==== Deep Sleep Timer (ไมโครวินาที) ====
#define SLEEP_uS 3600000000ULL // 1 ชม. = 60*60*1,000,000
void setup() {
Serial.begin(115200);
analogReadResolution(12); // 0-4095
// อานคา Sensor
int raw = analogRead(SENSOR_PIN);
Serial.print("Moisture: ");
Serial.println(raw);
// เชื่อมตอ WiFi
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 30) {
delay(200);
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
// สงคา HTTP GET
sendMoisture(raw);
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
} else {
Serial.println("❌ WiFi fail — skip this round");
}
// เขา Deep Sleep
Serial.println("😴 Deep Sleep 1 ชม.");
esp_sleep_enable_timer_wakeup(SLEEP_uS);
esp_deep_sleep_start();
}
void loop() {
// ไมมี — ESP32 ตื่นมา setup() ทุกครั้ง
}
void sendMoisture(int value) {
HTTPClient http;
String url = String(serverUrl) +
"?moisture=" + String(value) +
"&device_id=" + String(device_id) +
"&port_id=" + String(port_id) +
"&time=" + getTimeStr();
http.begin(url);
http.setTimeout(5000); // 5 วิ
int httpCode = http.GET();
if (httpCode > 0) {
Serial.print("✅ HTTP ");
Serial.println(httpCode);
} else {
Serial.print("❌ Error: ");
Serial.println(http.errorToString(httpCode));
}
http.end();
}
String getTimeStr() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) return "unknown";
char buf[25];
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &timeinfo);
return String(buf);
}
💡 สำคัญ: ในโหมด Deep Sleep ESP32 เริ่มตัน code จากsetup()ทุกครั้งที่ตื่น —loop()ไมมีวันถูกรัน! ดังนั้น code ทั้งหมด (รวม WiFi) อยูในsetup()เทานั้น
วิธีเพิ่ม NTP — ลองหลาย Server ก่อนส่งข้อมูล
ปัญหาที่พบบ่อย: configTime() สั่งครั้งเดียว แต่ NTP อาจยังไม่ได้ Sync — ส่งผลให้ getTimeStr() คืน "unknown"
วิธีที่ดีกว่า: ลอง NTP หลาย Server (pool.ntp.org, time.nist.gov, time.google.com, th.pool.ntp.org) และ วนรอจนกว่าได้เวลาจริง ก่อนส่งข้อมูล:
// ==== NTP Config — ลองหลาย Server ====
const char* ntpServers[4] = {
"pool.ntp.org",
"th.pool.ntp.org", // NTP ไทย
"time.nist.gov",
"time.google.com"
};
const int NTP_TIMEOUT = 10; // รอ NTP สูงสุด 10 วิ
bool syncNTP() {
// ลอง NTP ทีละ Server จนกว่าจะได้เวลา
for (int i = 0; i < 4; i++) {
configTime(7 * 3600, 0, ntpServers[i]);
// รอ NTP Sync สูงสุด NTP_TIMEOUT วินาที
for (int wait = 0; wait < NTP_TIMEOUT; wait++) {
time_t now = time(nullptr);
if (now > 100000) { // ปี 1970+ = ได้เวลาแล้ว
struct tm ti;
getLocalTime(&ti);
char buf[30];
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &ti);
Serial.print("✅ NTP (");
Serial.print(ntpServers[i]);
Serial.print("): ");
Serial.println(buf);
return true;
}
delay(1000);
}
Serial.print("⚠️ NTP fail (");
Serial.print(ntpServers[i]);
Serial.println("), trying next...");
}
return false; // ทุก Server ล้ม — ส่ง unknown แทน
}
เรียกใน setup() หลังจาก WiFi พร้อม แล้วก่อน sendMoisture():
void setup() {
Serial.begin(115200);
analogReadResolution(12);
int raw = analogRead(SENSOR_PIN);
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 30) {
delay(200);
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
// NTP — ลองหลาย Server ก่อนส่ง
bool timeOk = syncNTP();
if (!timeOk) {
Serial.println("⚠️ NTP all fail — ส่ง unknown time");
}
sendMoisture(raw);
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
}
esp_sleep_enable_timer_wakeup(SLEEP_uS);
esp_deep_sleep_start();
}
และอัปเดต getTimeStr() ให้จัดการเวลาที่ได้จริง:
String getTimeStr() {
time_t now = time(nullptr);
if (now < 100000) return "unknown"; // NTP ยังไม่ Sync
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) return "unknown";
char buf[25];
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &timeinfo);
return String(buf);
}
ทำไมต้อง NTP?
- ESP32 ไม่มี RTC จริง — เวลาจะหายทุกครั้งที่ Deep Sleep
- Deep Sleep ใช้ RTC clock ภายใน (~150ppm) — คลาดเคลื่อน ~5-10 วิ/ชม.
- NTP Sync ทุกครั้งที่ตื่น = เวลาถูกต้อง ±1-2 วิ
- MySQL ฝั่ง server จะได้เวลาที่แม่นยำ — ทำกราฟ trend ได้!
การชารจแบต — ไมตองถอด!
| วิธี | รายละเอียด |
|---|---|
| 📱 เสียบ Powerbank | TP4056 รองรับ Micro USB — เสียบ Powerbank ตรงๆ ได |
| 🔌 เสียบ Adapter | USB 5V 1A ธรรมดา — ชารจ 18650 ~2-4 ชม. |
| 🔋 ถอดแบตไปชารจ | ใช External Charger (Nitecore, Xtar) |
| ☀️ Solar (Optional) | เพิ่ม Solar Panel 5V 1W + TP4056 — ชารจกลางวัน |
TP4056 มี LED:
- 🔴 แดง = กำลังชารจ
- 🟢 เขียว = เต็มแลว
ฝั่ง Web Server — PHP endpoint (เหมือนเดิม)
ไฟล /api/moisture.php:
<?php
$pdo = new PDO("mysql:host=localhost;dbname=your_db;charset=utf8mb4", "user", "pass");
$time = $_GET['time'] ?? date('Y-m-d\TH:i:s');
$moisture = isset($_GET['moisture']) ? (int)$_GET['moisture'] : 0;
$device_id = $_GET['device_id'] ?? 'unknown';
$port_id = $_GET['port_id'] ?? 'unknown';
$stmt = $pdo->prepare("INSERT INTO moisture_log (time, moisture, device_id, port_id, created_at) VALUES (?, ?, ?, ?, NOW())");
$stmt->execute([$time, $moisture, $device_id, $port_id]);
echo "OK";
Dashboard ดูคาลาสุด (Serveless HTML)
<?php
// dashboard-18650.php
$pdo = new PDO("mysql:host=localhost;dbname=your_db;charset=utf8mb4", "user", "pass");
$devices = $pdo->query("
SELECT m1.*
FROM moisture_log m1
WHERE m1.id = (SELECT MAX(m2.id) FROM moisture_log m2 WHERE m2.device_id = m1.device_id)
ORDER BY m1.time DESC
")->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>🌱 Soil Moisture</title>
<style>
body{font-family:sans-serif;background:#0d1117;color:#c9d1d9;max-width:600px;margin:0 auto;padding:20px;}
.card{background:#161b22;border:1px solid #30363d;border-radius:8px;padding:16px;margin-bottom:10px;}
.badge{padding:2px 8px;border-radius:10px;font-size:0.8rem;}
.b-wet{background:#0d1a10;color:#3fb950;border:1px solid #238636;}
.b-dry{background:#1c0a08;color:#f85149;border:1px solid #da3633;}
.b-mid{background:#1c1408;color:#d29922;border:1px solid #9e6a03;}
.battery{color:#8b949e;font-size:0.8rem;}
</style>
</head>
<body>
<h1>🌱 Soil Moisture Monitor</h1>
<p style="color:#8b949e;">🔋 18650 — วัดทุก 1 ชม. อยูได ~14 เดือน</p>
<?php foreach($devices as $d):
$v = (int)$d['moisture'];
if ($v > 3000) { $status = '🔴 แหง!'; $cls = 'b-dry'; }
elseif ($v < 1200) { $status = '🟢 ชื้น'; $cls = 'b-wet'; }
else { $status = '🟡 ปานกลาง'; $cls = 'b-mid'; }
$batt = 65; // สมมุติ (หรือสงคาจริงๆจาก ESP32)
?>
<div class="card">
<div style="display:flex;justify-content:space-between;align-items:center;">
<strong>📡 <?=htmlspecialchars($d['device_id'])?></strong>
<span class="badge <?=$cls?>"><?=$status?></span>
</div>
<div style="font-size:2rem;margin:8px 0;"><?=$v?></div>
<div style="color:#8b949e;font-size:0.85rem;">🕐 <?=$d['time']?></div>
<div class="battery">🔋 ~<?=$batt?>%</div>
</div>
<?php endforeach; ?>
<p style="color:#484f58;font-size:0.8rem;">🛜 ESP32 ตื่นทุก 1 ชม. สง HTTP GET</p>
</body>
</html>
เพิ่มการแจงเตือน (ไมตองเขามาดูเว็บ)
วิธีงายๆ ให ESP32 สงคาแลว ให PHP ตรวจสอบวามอยูในเกณฑแหงหรือเปลา:
fetchAll(PDO::FETCH_ASSOC);
foreach ($devices as $d) {
if ((int)$d['moisture'] > 3000) {
// สง LINE Notify / Telegram Bot
$msg = "🌱 ".$d['device_id']." ดินแหง! (".$d['moisture'].")";
file_get_contents("https://api.telegram.org/bot".$token."/sendMessage?chat_id=".$chat_id."&text=".urlencode($msg));
}
}
?>
สรุป
| ขอดี | ขอควรระวัง |
|---|---|
| ✅ 18650 กอนเดียว อยูได 14 เดือน | ⚠️ ADC ESP32 แมนยำ ±6% — ควร Calibrate |
| ✅ ไมตองระบบรดน้ำ — เสียบ Sensor แลวจบ | ⚠️ Deep Sleep ใช RTC clock — อาจคลาดเคลือนเล็กนอย |
| ✅ TP4056 เสียบชารจ USB ได | ⚠️ ตองแนใจวา WiFi สัญญาณถึง |
| ✅ กลองเล็ก ~4x3x2 cm — วางตรงไหนก็ได | ⚠️ กันน้ำใหดี — ESP32 ไมชอบน้ำ! |
| ✅ ราคา ~302-542 บ. ครบชุด | ⚠️ Temperatura −10°C ~ +60°C — อยาวางกลางแดด |
📝 สรุป: ถาคุณมีตนไมแค 2-3 กระถาง ไมอยากลงทุนระบบรดน้ำทั้งระบบ — ESP32 + 18650 + Capacitive Sensor ราคา ~300-500 บ. ตอกระถาง ใชงานได >1 ป โดยไมตองชารจ แถมดูคาผานเว็บหรือแจงเตือนเขา LINE/Telegram แคนี้ก็รูแลววาควรรดน้ำตอนไหน!
📖 เนื้อหาคนควาและเรียบเรียงโดย Hermes AI — กรุณาตรวจสอบ datasheet และทดสอบวงจรกอนนำไปใชงานจริง
🔬 ขอมูลทางเทคนิคอาจตองปรับตามอุปกรณจริงที่ซื้อมา