บทความ: ESP32 Deep Sleep กับ MQTT - สร้างเซนเซอร์โหนดประหยัดแบตเตอรี่

เรียนรู้วิธีสร้าง IoT Sensor Node ที่ทำงานด้วยแบตเตอรี่ได้นานเป็นเดือน ด้วยการประยุกต์ใช้ Deep Sleep Mode และ MQTT Protocol เพื่อส่งข้อมูลไปยัง Server

📅 13 มีนาคม 2026⏱️ 20 นาที🎯 ระดับปานกลาง

📖 ภาพรวมโปรเจกต์

บทความนี้จะแนะนำวิธีสร้าง IoT Sensor Node ที่ทำงานด้วยแบตเตอรี่ได้นานหลายเดือน โดยใช้ ESP32 Deep Sleep Mode ร่วมกับ MQTT Protocol เพื่อส่งข้อมูลเซนเซอร์ไปยัง Server อย่างมีประสิทธิภาพ

🌟 จุดเด่นของโปรเจกต์นี้

  • • ประหยัดพลังงานด้วย Deep Sleep Mode (10μA)
  • • ตื่นจากการนอนเพื่อวัดค่าและส่งข้อมูลผ่าน MQTT
  • • คำนวณอายุการใช้งานแบตเตอรี่ได้แม่นยำ
  • • เข้ากันได้กับ Home Assistant, Node-RED และ CynoIoT Platform
  • • ปรับแต่งระยะเวลาการส่งข้อมูลได้ตามต้องการ

สิ่งที่คุณจะได้เรียนรู้

  • ✅ การทำความเข้าใจ Deep Sleep Mode ของ ESP32
  • ✅ การเชื่อมต่อ ESP32 กับ MQTT Broker
  • ✅ การตั้งค่า Timer Wake-up และ External Wake-up
  • ✅ การคำนวณพลังงานและอายุการใช้งานแบตเตอรี่
  • ✅ การเลือกเซนเซอร์ที่เหมาะสมสำหรับ Low Power
  • ✅ เทคนิคการปรับแต่งให้ใช้พลังงานน้อยที่สุด

⚡ ทำไมต้อง Deep Sleep?

เมื่อสร้าง IoT Sensor Node ที่ทำงานด้วยแบตเตอรี่ การจัดการพลังงานเป็นสิ่งสำคัญที่สุด Deep Sleep Mode ของ ESP32 ช่วยลดการใช้พลังงานลงอย่างมหาศาล

เปรียบเทียบโหมดการทำงาน

โหมดกระแสไฟคำอธิบาย
Active Mode160-260 mAWiFi เปิด, CPU ทำงานเต็มสูบ
Light Sleep0.8 - 15 mACPU หยุดทำงาน แต่ WiFi ยังเชื่อมต่อ
Deep Sleep~10 μACPU หยุด, RAM สูญหาย (RTC memory เหลือ)
Hibernation~2.5 μAปิดทุกอย่าง ยกเว้น RTC

⚠️ ข้อควรระวัง

  • • Deep Sleep จะรีเซ็ต ESP32 เมื่อตื่นขึ้นมา (เหมือนกดรีเซ็ต)
  • • ข้อมูลใน RAM จะหายไป ใช้ RTC memory ในการเก็บข้อมูลสำคัญ
  • • การเชื่อมต่อ WiFi ใหม่ทุกครั้งใช้เวลา ~2-3 วินาที
  • • ต้องเขียนโค้ดให้รองรับการรีเซ็ตทุกครั้งที่ตื่น

📡 พื้นฐาน MQTT Protocol

MQTT (Message Queuing Telemetry Transport) เป็นโปรโตคอลการสื่อสารแบบ Lightweight ที่เหมาะสำหรับ IoT Devices ที่มีทรัพยากรจำกัด

ทำไม MQTT เหมาะกับ Deep Sleep?

✅ ข้อดี

  • • ขนาด packet เล็ก (Header เพียง 2 bytes)
  • • ใช้ bandwidth น้อยมาก
  • • เชื่อมต่อและส่งข้อมูลเร็ว
  • • รองรับ QoS (Quality of Service)
  • • สามารถรักษา connection ได้ (Keep-alive)

📊 MQTT Architecture

  • Broker: ฝ่ายกลางที่รับส่งข้อมูล
  • Publisher: ผู้ส่งข้อมูล (ESP32)
  • Subscriber: ผู้รับข้อมูล
  • Topic: ช่องทางของข้อมูล
  • Message: ข้อมูลที่ส่ง

💡 เคล็ดลับสำหรับ Deep Sleep + MQTT

สำหรับ Sensor Node ที่ใช้ Deep Sleep ควรใช้ MQTT QoS 1 (At least once) เพื่อให้มั่นใจว่าข้อมูลถูกส่งถึง Broker แม้ว่าจะมีการเชื่อมต่อที่ไม่เสถียร แต่อย่าใช้ QoS 2 เพราะจะใช้พลังงานและเวลามากขึ้น

🛠️ อุปกรณ์ที่ต้องใช้

Hardware

🔌

ESP32 Board (DevKitC, NodeMCU, ฯลฯ)

บอร์ดหลักสำหรับโปรเจกต์ (~฿80-150)

🌡️

DHT11/DHT22 หรือ DS18B20 Temperature Sensor

เซนเซอร์วัดอุณหภูมิ (~฿20-60)

🔋

Battery (Li-Ion 18650 หรือ Li-Po)

แหล่งจ่ายพลังงาน (~฿80-150)

TP4056 USB Charging Module หรือ DC-DC Boost Converter

ชาร์จและจัดการแบตเตอรี่ (~฿15-40)

🔗

Jumper Wires (Male-to-Female)

สายเชื่อมต่อ (~฿40-60)

Software

  • Arduino IDE 2.x - ดาวน์โหลดจาก arduino.cc
  • ESP32 Board Package - ติดตั้งผ่าน Board Manager
  • MQTT Broker - ใช้ฟรีจาก HiveMQ, EMQX หรือติดตั้งเอง
  • MQTT Client - MQTT Explorer สำหรับทดสอบ

📦 Libraries ที่ต้องติดตั้ง

• WiFi.h (built-in)

• PubSubClient (by Nick O'Leary)

• DHT sensor library (by Adafruit)

• OneWire (ใช้กับ DS18B20)

🔌 การต่อวงจร Hardware

ในตัวอย่างนี้เราจะใช้ DHT22 Temperature & Humidity Sensor เพราะใช้งานง่ายและให้ข้อมูลที่แม่นยำ

Pinout การต่อสาย

DHT22 PinESP32 Pinหมายเหตุ
VCC (Pin 1)3.3Vจ่ายไฟ 3.3V
DATA (Pin 2)GPIO 4เชื่อมต่อพร้อม Pull-up 10KΩ
NC (Pin 3)-ไม่ต้องต่อ
GND (Pin 4)GNDกราวด์

⚠️ ข้อควรระวังเรื่อง Pin

  • • หลีกเลี่ยงการใช้ GPIO 0, 2, 12, 15 เพราะอาจมีผลต่อการ Boot
  • • GPIO 34-39 เป็น Input-only และไม่มี Pull-up/Pull-down ภายใน
  • • ใช้ GPIO 4 หรือ GPIO 5 สำหรับ DHT22 เพื่อความปลอดภัย
  • • DHT22 ต้องการ Pull-up resistor 10KΩ บนขา DATA

วงจรแบตเตอรี่

สำหรับโปรเจกต์นี้ สามารถใช้แบตเตอรี่ในรูปแบบต่างๆ ได้:

  • Li-Ion 18650 - ความจุ 2000-3500mAh, ถูกและหาง่าย
  • Li-Po ธรรมดา - ความจุ 500-2000mAh, เบาและบาง
  • Battery Pack 4x AA - 6V, ใช้งานง่ายแต่อายุสั้น

💡 เคล็ดลับ

ใช้ TP4056 Module สำหรับชาร์จ Li-Ion/Li-Po และต่อเข้ากับ DC-DC Boost Converter เพื่อแปลง 3.7V เป็น 5V หรือ 3.3V สำหรับ ESP32 อย่าลืมใส่ Diode ป้องกันการไหลย้อนของกระแสไฟ

💻 โค้ดโปรแกรม

โค้ดต่อไปนี้จะทำให้ ESP32 ตื่นขึ้นมาเชื่อมต่อ WiFi, อ่านค่าเซนเซอร์, ส่งข้อมูลผ่าน MQTT, แล้วกลับเข้า Deep Sleep อีกครั้ง

/*
 * ESP32 Deep Sleep + MQTT Temperature Sensor
 * 
 * โค้ดนี้ทำให้ ESP32 ทำงานแบบ Battery-powered Sensor Node
 * โดยจะตื่นขึ้นมาทุกๆ ช่วงเวลาที่กำหนด เพื่อส่งข้อมูลผ่าน MQTT
 * 
 * Hardware: ESP32 + DHT22
 * Author: CynoIoT Team
 * Date: March 2026
 */

#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>

// ========== WiFi Settings ==========
const char* ssid = "YOUR_WIFI_SSID";        // ชื่อ WiFi
const char* password = "YOUR_WIFI_PASSWORD"; // รหัสผ่าน WiFi

// ========== MQTT Settings ==========
const char* mqtt_server = "broker.hivemq.com";  // MQTT Broker
const int mqtt_port = 1883;                      // MQTT Port
const char* mqtt_user = "";                      // Username (ถ้ามี)
const char* mqtt_password = "";                  // Password (ถ้ามี)

// ========== Topics ==========
const char* temp_topic = "cynoiot/sensor/temperature";
const char* hum_topic = "cynoiot/sensor/humidity";
const char* status_topic = "cynoiot/sensor/status";

// ========== Sensor Settings ==========
#define DHTPIN 4         // GPIO 4 สำหรับ DHT22
#define DHTTYPE DHT22    // รุ่น DHT22
DHT dht(DHTPIN, DHTTYPE);

// ========== Deep Sleep Settings ==========
#define uS_TO_S_FACTOR 1000000  /* แปลง microseconds เป็น seconds */
#define TIME_TO_SLEEP  300      /* เวลานอน 300 วินาที (5 นาที) */

// ========== Global Variables ==========
WiFiClient espClient;
PubSubClient client(espClient);
RTC_DATA_ATTR int bootCount = 0;  // เก็บจำนวนครั้งที่บูตใน RTC memory

// ========== Function Prototypes ==========
void setupWiFi();
void reconnectMQTT();
void readAndSendSensorData();
void goToDeepSleep();

void setup() {
  Serial.begin(115200);
  
  // นับจำนวนครั้งที่ตื่นจาก Deep Sleep
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));
  
  // แสดงสาเหตุที่ตื่น
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();
  
  switch(wakeup_reason) {
    case ESP_SLEEP_WAKEUP_TIMER:
      Serial.println("Wakeup caused by timer");
      break;
    case ESP_SLEEP_WAKEUP_EXT0:
      Serial.println("Wakeup caused by external signal using RTC_IO");
      break;
    case ESP_SLEEP_WAKEUP_EXT1:
      Serial.println("Wakeup caused by external signal using RTC_CNTL");
      break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD:
      Serial.println("Wakeup caused by touchpad");
      break;
    default:
      Serial.println("Wakeup was not caused by deep sleep");
      break;
  }
  
  // เริ่มต้นเซนเซอร์
  dht.begin();
  
  // เชื่อมต่อ WiFi
  setupWiFi();
  
  // เชื่อมต่อ MQTT
  client.setServer(mqtt_server, mqtt_port);
  reconnectMQTT();
  
  // อ่านและส่งข้อมูลเซนเซอร์
  readAndSendSensorData();
  
  // ส่งสถานะและเข้า Deep Sleep
  client.publish(status_topic, "Going to sleep...", true);
  delay(100);  // รอให้ส่งข้อมูลเสร็จ
  
  goToDeepSleep();
}

void loop() {
  // ไม่ต้องใช้ loop เพราะจะเข้า Deep Sleep ใน setup
}

// ========== WiFi Setup ==========
void setupWiFi() {
  Serial.print("Connecting to WiFi");
  
  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("\nWiFi connected!");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("\nWiFi connection failed!");
    Serial.println("Going to deep sleep anyway...");
  }
}

// ========== MQTT Reconnect ==========
void reconnectMQTT() {
  int attempts = 0;
  while (!client.connected() && attempts < 3) {
    Serial.print("Attempting MQTT connection...");
    
    // สร้าง Client ID แบบสุ่ม
    String clientId = "ESP32Client-";
    clientId += String(random(0xffff), HEX);
    
    if (client.connect(clientId.c_str(), mqtt_user, mqtt_password)) {
      Serial.println("connected");
      return;
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" retrying...");
      delay(500);
      attempts++;
    }
  }
}

// ========== Read and Send Sensor Data ==========
void readAndSendSensorData() {
  // อ่านค่าอุณหภูมิและความชื้น
  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature();  // ค่า Celsius
  
  // ตรวจสอบว่าอ่านค่าได้หรือไม่
  if (isnan(humidity) || isnan(temperature)) {
    Serial.println("Failed to read from DHT sensor!");
    client.publish(status_topic, "Sensor reading failed!", true);
    return;
  }
  
  // แสดงค่าที่ได้ใน Serial Monitor
  Serial.println("Temperature: " + String(temperature) + " °C");
  Serial.println("Humidity: " + String(humidity) + " %");
  
  // แปลงค่าเป็น String
  char tempStr[10];
  char humStr[10];
  dtostrf(temperature, 2, 2, tempStr);
  dtostrf(humidity, 2, 2, humStr);
  
  // ส่งข้อมูลผ่าน MQTT
  if (client.publish(temp_topic, tempStr, true)) {
    Serial.println("Temperature data sent!");
  } else {
    Serial.println("Failed to send temperature data");
  }
  
  if (client.publish(hum_topic, humStr, true)) {
    Serial.println("Humidity data sent!");
  } else {
    Serial.println("Failed to send humidity data");
  }
}

// ========== Go to Deep Sleep ==========
void goToDeepSleep() {
  Serial.println("Going to deep sleep for " + String(TIME_TO_SLEEP) + " seconds");
  
  // ตั้งค่าเวลานอน
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  
  // เข้าสู่โหมด Deep Sleep
  Serial.println("Entering deep sleep mode...");
  Serial.flush();
  esp_deep_sleep_start();
}

✨ จุดสำคัญในโค้ด

  • RTC_DATA_ATTR: เก็บตัวแปรใน RTC memory จะไม่หายเมื่อ Deep Sleep
  • esp_sleep_enable_timer_wakeup(): ตั้งเวลาตื่นด้วย Timer
  • esp_deep_sleep_start(): เข้าสู่ Deep Sleep ทันที
  • MQTT QoS 1 (true): รับประกันว่าข้อมูลจะถูกส่งถึง

วิธีอัปโหลดโค้ด

  1. 1. เปิด Arduino IDE และสร้าง Sketch ใหม่
  2. 2. Copy โค้ดด้านบนและวางลงไป
  3. 3. แก้ไข WiFi credentials และ MQTT settings
  4. 4. เลือกบอร์ดและ port ที่ถูกต้อง
  5. 5. กด Upload ไปยัง ESP32
  6. 6. เปิด Serial Monitor (115200 baud) เพื่อดูผล

🔋 คำนวณอายุการใช้งานแบตเตอรี่

การคำนวณอายุการใช้งานแบตเตอรี่ช่วยให้เราวางแผนการบำรุงรักษาและทำนายว่าเซนเซอร์โหนดจะทำงานได้นานแค่ไหน

สูตรการคำนวณ

อายุแบต (วัน) = ความจุแบต (mAh) / (กระแสเฉลี่ยรายวัน (mAh/วัน))

กระแสเฉลี่ยรายวัน = กระแส Active × เวลา Active + กระแส Deep Sleep × เวลา Deep Sleep

ตัวอย่างการคำนวณ

📊 สมมติสถานการณ์

  • • แบตเตอรี่: 2000 mAh (Li-Ion 18650)
  • • เวลา Active: ~10 วินาทีต่อครั้ง
  • • เวลา Deep Sleep: 290 วินาที (5 นาทีรวม)
  • • กระแส Active: ~150 mA (เฉลี่ย)
  • • กระแส Deep Sleep: ~10 μA = 0.01 mA

🧮 การคำนวณ

รอบต่อวัน: 86400 วินาที / 300 วินาที = 288 รอบ/วัน

กระแส Active ต่อวัน: 150 mA × 10 วินาที × 288 รอบ / 3600 = 120 mAh/วัน

กระแส Deep Sleep ต่อวัน: 0.01 mA × 290 วินาที × 288 รอบ / 3600 = 0.008 mAh/วัน

กระแสรวมต่อวัน: 120.008 ≈ 120 mAh/วัน

🎯 อายุแบต: 2000 / 120 = 16.67 วัน

เคล็ดลับการยืดอายุแบตเตอรี่

✅ ทำให้ใช้พลังน้อยลง

  • • เพิ่มระยะเวลา Deep Sleep (เช่น 10-15 นาที)
  • • ลดเวลาเชื่อมต่อ WiFi
  • • ปิด Serial หลังจาก Debug เสร็จ
  • • ใช้เซนเซอร์ที่ประหยัดพลังงาน
  • • ปิด LED บนบอร์ด (ถ้ามี)

❌ สิ่งที่ควรหลีกเลี่ยง

  • • ใช้ delay() มากเกินไปใน Active mode
  • • ไม่ปิด WiFi หลังจากใช้งาน
  • • ใช้ Power Bank ที่มี Auto-off
  • • เซนเซอร์ที่ใช้พลังมากเกินไป
  • • ส่งข้อมูลถี่เกินไป

⚠️ ข้อควรระวัง

การคำนวณเป็นเพียงค่าประมาณ อายุแบตจริงอาจต่างออกไปขึ้นอยู่กับอุณหภูมิ, คุณภาพแบต, และสภาพแวดล้อม แนะนำให้ทดสอบจริงและเพิ่ม Safety Margin 20-30%

🧪 การทดสอบ

ทดสอบด้วย MQTT Explorer

  1. 1

    ดาวน์โหลดและติดตั้ง MQTT Explorer

    ได้ที่ mqtt-explorer.com

  2. 2

    สร้าง Connection ใหม่

    Host: broker.hivemq.com, Port: 1883

  3. 3

    Subscribe Topics

    cynoiot/sensor/#

  4. 4

    รอดูข้อมูล

    ESP32 จะส่งข้อมูลทุกๆ 5 นาที (ตามที่ตั้งค่า)

ตรวจสอบ Serial Monitor

Boot number: 1
Wakeup caused by timer
Connecting to WiFi.....
WiFi connected!
IP address: 192.168.1.100
Attempting MQTT connection...connected
Temperature: 28.50 °C
Humidity: 65.20 %
Temperature data sent!
Humidity data sent!
Going to deep sleep for 300 seconds
Entering deep sleep mode...

ทดสอบอายุแบตเตอรี่

หากต้องการทดสอบอายุแบตจริง สามารถใช้โค้ดนี้ในการ Track การใช้พลังงาน:

// เพิ่มใน setup() หลังจากตื่น
Serial.print("Boot count: ");
Serial.println(bootCount);

// คำนวณเวลาที่ผ่านไป (ถ้าต้องการ)
// ใช้ RTC memory ในการเก็บ timestamp ก่อนนอน

🔧 การแก้ปัญหา

ESP32 ตื่นแล้วไม่ทำงาน

อาการ: ตื่นจาก Deep Sleep แต่ไม่เชื่อมต่อ WiFi หรือไม่ส่งข้อมูล

วิธีแก้: เพิ่ม delay() หลังจาก dht.begin() ให้เซนเซอร์พร้อมทำงาน, ตรวจสอบว่าตัวแปรทุกตัวถูกกำหนดค่าใหม่ใน setup()

MQTT เชื่อมต่อไม่ได้

อาการ: แสดง "failed, rc=-2" ใน Serial Monitor

วิธีแก้: ตรวจสอบว่า WiFi เชื่อมต่อสำเร็จ, ลองเปลี่ยน MQTT Broker, เพิ่มเวลา Timeout ในการเชื่อมต่อ

อ่านค่า DHT ไม่ได้

อาการ: แสดง "Failed to read from DHT sensor!"

วิธีแก้: ตรวจสอบการต่อสาย (VCC, GND, DATA), เพิ่ม delay() 2-3 วินาทีหลังจากเริ่มเซนเซอร์, ลองใช้ Pull-up resistor ภายนอก

แบตเตอรี่หมดเร็วเกินไป

อาการ: แบตหมดภายใน 2-3 วัน

วิธีแก้: เพิ่มเวลา Deep Sleep, ลดเวลา Active, ตรวจสอบว่าปิด WiFi หลังใช้งาน, ใช้เซนเซอร์ที่ประหยัดพลังงานกว่า

อัปโหลดโค้ดไม่ได้ขณะ Deep Sleep

อาการ: ไม่สามารถอัปโหลดโค้ดใหม่ได้

วิธีแก้: กดปุ่ม BOOT ค้างระหว่างอัปโหลด, หรือรีเซ็ต ESP32 ก่อนอัปโหลด, หรือต่อสาย GPIO 0 เข้ากับ GND ระหว่างอัปโหลด

🚀 ขั้นตอนถัดไป

ยินดีด้วย! ตอนนี้คุณมี IoT Sensor Node ที่ประหยัดพลังงานแล้ว ต่อไปนี้คือสิ่งที่คุณสามารถพัฒนาต่อได้:

📊 เชื่อมต่อกับ CynoIoT Platform

นำข้อมูลเซนเซอร์ไปแสดงบน Dashboard ของ CynoIoT พร้อมกราฟและแจ้งเตือน

🏠 ใช้กับ Home Assistant

เพิ่ม MQTT Sensor ใน Home Assistant เพื่อสร้าง Automation อัจฉริยะ

📡 เพิ่มเซนเซอร์หลายตัว

เพิ่ม Soil Moisture, Light Sensor หรือ Motion Sensor ลงในโหนดเดียว

🔋 OTA Updates

เพิ่มความสามารถอัปเดตฟาร์มแวร์ผ่าน WiFi โดยไม่ต้องถอดแบต

บทความที่เกี่ยวข้อง

© 2026 CynoIoT Platform. สร้างสรรค์ด้วย ❤️ สำหรับชุมชน IoT ไทย