เนื้อหาในบทความ
📊 ภาพรวมโปรเจกต์
โปรเจกต์นี้จะสอนวิธีสร้าง ระบบบันทึกข้อมูลหลาย Sensor (Multi-Sensor Data Logger) โดยใช้ ESP32 เพื่ออ่านค่าจาก:
- DHT22 - วัดอุณหภูมิและความชื้น
- BMP280 - วัดความดันบรรยากาศและอุณหภูมิ
และบันทึกข้อมูลลง SD Card ในรูปแบบ CSV พร้อมส่งข้อมูลไปยัง CynoIoT Platform ผ่าน WiFi
✨ จุดเด่นของโปรเจกต์นี้:
- บันทึกข้อมูลได้ต่อเนื่องแม้ไม่มี Internet
- นำข้อมูลไปวิเคราะห์ด้วย Excel ได้ทันที
- เชื่อมต่อ CynoIoT เพื่อ monitoring ผ่านเว็บ
- ใช้งานได้จริงกับสถานการณ์ต่างๆ
สถานการณ์ที่ใช้งานได้:
- 🏠 ติดตามสภาพอากาศในบ้าน
- 🏭 ตรวจสอบสภาพแวดล้อมในโกดัง
- 🌾 ติดตามสภาพอากาศในฟาร์ม
- 📦 ตรวจสอบอุณหภูมิในคอนเทนเนอร์ขนส่งสินค้า
- 🔬 บันทึกข้อมูลการทดลองในห้อง lab
🔧 อุปกรณ์ที่ต้องใช้
Hardware Components:
ESP32 Development Board
หรือ NodeMCU ESP32
~฿150-250
DHT22 Sensor Module
อุณหภูมิและความชื้น
~฿60-100
BMP280 Sensor
ความดันบรรยากาศ
~฿80-150
MicroSD Card Module
พร้อม SD Card 4GB+
~฿50-80
Jumper Wires
สายเชื่อมต่อ Male-to-Female
~฿30-50
Breadboard
ขนาด 400 หรือ 830 points
~฿40-80
💡 รวมค่าใช้จ่ายโดยประมาณ: ฿410-710 (ไม่รวม SD Card)
Software & Tools:
- Arduino IDE - สำหรับเขียนและอัปโหลดโค้ด
- CynoIoT Account - ฟรี! สมัครที่
cynoiot.com - Libraries: DHT, Adafruit BMP280, SD (ติดตั้งผ่าน Library Manager)
🔌 การต่อสาย
| Component | Pin | ESP32 Pin |
|---|---|---|
| DHT22 Sensor | ||
| VCC | - | 3.3V |
| Data | - | GPIO 4 |
| GND | - | GND |
| BMP280 Sensor (I2C) | ||
| VCC | - | 3.3V |
| GND | - | GND |
| SCL | - | GPIO 22 |
| SDA | - | GPIO 21 |
| SD Card Module (SPI) | ||
| VCC | - | 5V |
| GND | - | GND |
| CS | - | GPIO 5 |
| MOSI | - | GPIO 23 |
| MISO | - | GPIO 19 |
| SCK | - | GPIO 18 |
⚠️ ข้อควรระวัง:
- SD Card Module ต้องใช้ 5V ไม่ใช่ 3.3V
- ต่อสาย DHT22 อย่าลืมใส่ Resistor 10kΩ ระหว่าง VCC และ Data
- ตรวจสอบขา SCL/SDA ของ BMP280 ให้ถูกต้อง
💻 การเขียนโปรแกรม
ติดตั้ง Libraries:
- เปิด Arduino IDE
- ไปที่ Sketch → Include Library → Manage Libraries
- ค้นหาและติดตั้ง:
- "DHT sensor library" โดย Adafruit
- "Adafruit BMP280 Library"
- "Adafruit Unified Sensor"
- "SD" (มีมากับ Arduino IDE อยู่แล้ว)
โค้ดสมบูรณ์ (Complete Code):
/**
* ESP32 Multi-Sensor Data Logger
* บันทึกข้อมูลอุณหภูมิ ความชื้น และความดันลง SD Card
* และส่งข้อมูลไป CynoIoT Platform
*
* Hardware:
* - ESP32 Board
* - DHT22 Sensor (GPIO 4)
* - BMP280 Sensor (I2C: SCL=GPIO 22, SDA=GPIO 21)
* - SD Card Module (SPI: CS=5, MOSI=23, MISO=19, SCK=18)
*/
#include <DHT.h>
#include <Adafruit_BMP280.h>
#include <SD.h>
#include <WiFi.h>
#include <HTTPClient.h>
// === ตั้งค่า Sensor ===
#define DHTPIN 4 // DHT22 Data pin
#define DHTTYPE DHT22 // DHT 22
DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP280 bmp; // I2C
// === ตั้งค่า SD Card ===
#define SD_CS 5 // CS pin สำหรับ SD Card
// === ตั้งค่า WiFi ===
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
// === ตั้งค่า CynoIoT ===
const char* cynoiot_server = "api.cynoiot.com";
const char* device_id = "YOUR_DEVICE_ID";
const char* api_key = "YOUR_API_KEY";
// === ตั้งค่าการบันทึก ===
#define LOG_INTERVAL 60000 // บันทึกทุกๆ 60 วินาที
unsigned long lastLogTime = 0;
void setup() {
Serial.begin(115200);
Serial.println("\n=== ESP32 Multi-Sensor Data Logger ===");
// เริ่มต้น DHT22
dht.begin();
Serial.println("✓ DHT22 started");
// เริ่มต้น BMP280
if (!bmp.begin(0x76)) {
Serial.println("✗ BMP280 not found!");
while (1);
}
Serial.println("✓ BMP280 started");
// เริ่มต้น SD Card
if (!SD.begin(SD_CS)) {
Serial.println("✗ SD Card initialization failed!");
while (1);
}
Serial.println("✓ SD Card initialized");
// สร้างไฟล์ CSV ถ้ายังไม่มี
if (!SD.exists("/datalog.csv")) {
File dataFile = SD.open("/datalog.csv", FILE_WRITE);
if (dataFile) {
dataFile.println("Timestamp,Temperature_DHT,Temperature_BMP,Humidity,Pressure");
dataFile.close();
Serial.println("✓ Created datalog.csv");
}
}
// เชื่อมต่อ WiFi
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\n✓ WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("\n=== System Ready ===\n");
}
void loop() {
unsigned long currentTime = millis();
// บันทึกข้อมูลทุกๆ ที่กำหนด
if (currentTime - lastLogTime >= LOG_INTERVAL) {
lastLogTime = currentTime;
// อ่านค่าจาก DHT22
float tempDHT = dht.readTemperature();
float humidity = dht.readHumidity();
// ตรวจสอบการอ่านค่า DHT22
if (isnan(tempDHT) || isnan(humidity)) {
Serial.println("✗ Failed to read from DHT sensor!");
return;
}
// อ่านค่าจาก BMP280
float tempBMP = bmp.readTemperature();
float pressure = bmp.readPressure() / 100.0; // แปลงเป็น hPa
// สร้าง timestamp
String timestamp = getTimestamp();
// แสดงผลบน Serial Monitor
Serial.println("=== Sensor Readings ===");
Serial.print("Timestamp: ");
Serial.println(timestamp);
Serial.print("Temperature (DHT): ");
Serial.print(tempDHT);
Serial.println(" °C");
Serial.print("Temperature (BMP): ");
Serial.print(tempBMP);
Serial.println(" °C");
Serial.print("Humidity: ");
Serial.print(humidity);
Serial.println(" %");
Serial.print("Pressure: ");
Serial.print(pressure);
Serial.println(" hPa");
// บันทึกลง SD Card
if (logToSD(timestamp, tempDHT, tempBMP, humidity, pressure)) {
Serial.println("✓ Data saved to SD Card");
} else {
Serial.println("✗ Failed to save to SD Card");
}
// ส่งข้อมูลไป CynoIoT
if (sendToCynoIoT(tempDHT, humidity, pressure)) {
Serial.println("✓ Data sent to CynoIoT");
} else {
Serial.println("✗ Failed to send to CynoIoT");
}
Serial.println();
}
}
// ฟังก์ชันสร้าง timestamp
String getTimestamp() {
char timestamp[20];
sprintf(timestamp, "%04d-%02d-%02d %02d:%02d:%02d",
year(), month(), day(), hour(), minute(), second());
return String(timestamp);
}
// ฟังก์ชันบันทึกลง SD Card
bool logToSD(String timestamp, float tempDHT, float tempBMP, float humidity, float pressure) {
File dataFile = SD.open("/datalog.csv", FILE_APPEND);
if (!dataFile) {
return false;
}
// เขียนข้อมูลในรูปแบบ CSV
dataFile.print(timestamp);
dataFile.print(",");
dataFile.print(tempDHT);
dataFile.print(",");
dataFile.print(tempBMP);
dataFile.print(",");
dataFile.print(humidity);
dataFile.print(",");
dataFile.println(pressure);
dataFile.close();
return true;
}
// ฟังก์ชันส่งข้อมูลไป CynoIoT
bool sendToCynoIoT(float temperature, float humidity, float pressure) {
if (WiFi.status() != WL_CONNECTED) {
return false;
}
HTTPClient http;
http.begin(cynoiot_server);
http.addHeader("Content-Type", "application/json");
http.addHeader("X-API-Key", api_key);
// สร้าง JSON payload
String payload = "{\"device_id\":\"" + String(device_id) + "\",";
payload += "\"data\":{";
payload += "\"temperature\":" + String(temperature) + ",";
payload += "\"humidity\":" + String(humidity) + ",";
payload += "\"pressure\":" + String(pressure);
payload += "}}";
int httpResponseCode = http.POST(payload);
http.end();
return (httpResponseCode == 200);
}คำอธิบายโค้ดสำคัญ:
- Libraries - ใช้ DHT, BMP280, SD สำหรับ sensor และ SD Card
- PIN Definitions - กำหนดขาที่ใช้งานที่ต้นไฟล์
- setup() - เริ่มต้น sensor, SD Card, WiFi และสร้างไฟล์ CSV
- loop() - อ่านค่า sensor ทุกๆ 60 วินาที
- logToSD() - บันทึกข้อมูลลง SD Card ในรูปแบบ CSV
- sendToCynoIoT() - ส่งข้อมูลไป CynoIoT Platform
💡 เคล็ดลับ:
- เปลี่ยน
LOG_INTERVALเพื่อปรับความถี่ในการบันทึก - ไฟล์ datalog.csv สามารถเปิดด้วย Excel ได้ทันที
- ใช้ Serial Plotter (Tools → Serial Plotter) เพื่อดูกราฟแบบ real-time
🧪 การทดสอบ
ขั้นตอนการทดสอบ:
- อัปโหลดโค้ดไปยัง ESP32
- เปิด Serial Monitor (115200 baud)
- ดูข้อความ "=== System Ready ===" แสดงว่าโปรแกรมทำงานได้
- นำ SD Card มาเสียบในคอมพิวเตอร์
- เปิดไฟล์
datalog.csvด้วย Excel - ตรวจสอบว่ามีข้อมูลบันทึกถูกต้อง
ตัวอย่างข้อมูลใน CSV:
Timestamp,Temperature_DHT,Temperature_BMP,Humidity,Pressure
2026-03-29 18:12:00,28.50,28.30,65.20,1013.25
2026-03-29 18:13:00,28.60,28.40,65.10,1013.20
2026-03-29 18:14:00,28.70,28.50,65.00,1013.18การตรวจสอบข้อมูลใน CynoIoT:
- ล็อกอินเข้าสู่ cynoiot.com
- ไปที่หน้า Devices
- คลิกที่ device ของคุณ
- ดูกราฟข้อมูล sensor แบบ real-time
🔧 การแก้ปัญหา
ปัญหา: SD Card initialization failed
อาการ: แสดง "✗ SD Card initialization failed!"
สาเหตุ: SD Card ไม่ได้ฟอร์แมต หรือต่อสายไม่ถูกต้อง
วิธีแก้: ฟอร์แมต SD Card เป็น FAT32 และตรวจสอบการต่อสาย SPI
ปัญหา: BMP280 not found
อาการ: แสดง "✗ BMP280 not found!"
สาเหตุ: ต่อสาย I2C ผิด หรือใช้ address ไม่ถูกต้อง
วิธีแก้: ตรวจสอบว่า BMP280 ใช้ address 0x76 หรือ 0x77 และแก้ในโค้ด
ปัญหา: Failed to read from DHT sensor
อาการ: แสดง "✗ Failed to read from DHT sensor!"
สาเหตุ: ไม่ได้ต่อ Resistor หรือต่อสายผิดขา
วิธีแก้: ใส่ Resistor 10kΩ ระหว่าง VCC และ Data pin
ปัญหา: WiFi connection failed
อาการ: เชื่อมต่อ WiFi ไม่ได้
สาเหตุ: ชื่อ WiFi หรือรหัสผ่านผิด
วิธีแก้: ตรวจสอบ ssid และ password ในโค้ด
ปัญหา: ข้อมูลใน CSV ไม่ถูกต้อง
อาการ: ข้อมูลกระจายตัวไม่เป็นคอลัมน์
สาเหตุ: Excel ไม่รู้จักการแยก comma
วิธีแก้: ใช้ Data → Text to Columns และเลือก Delimited → Comma
📝 สรุป
ในบทความนี้คุณได้เรียนรู้:
- ✅ วิธีต่อ DHT22, BMP280 และ SD Card กับ ESP32
- ✅ การอ่านค่าจากหลาย sensor พร้อมกัน
- ✅ การบันทึกข้อมูลลง SD Card ในรูปแบบ CSV
- ✅ การส่งข้อมูลไป CynoIoT Platform ผ่าน WiFi
- ✅ การแก้ปัญหาที่พบบ่อย
🎯 สิ่งที่คุณสามารถทำต่อได้:
- เพิ่ม sensor อื่นๆ เช่น วัดแสง (BH1750) หรือวัดฝุ่น (PMS5003)
- ต่อหน้าจอ OLED เพื่อแสดงผลแบบ real-time
- ใช้ Deep Sleep Mode เพื่อประหยัดแบตเตอรี่
- สร้าง Web Server บน ESP32 เพื่อดูข้อมูลผ่าน browser
- ต่อ IoT Relay เพื่อควบคุมอุปกรณ์ไฟฟ้าอัตโนมัติ