สร้างสถานีตรวจวัดอากาศ ESP32 แบบครบวงจร: วัดอุณหภูมิ ความชื้น ความดัน ฝน และความเร็วลม

เรียนรู้วิธีสร้างสถานีตรวจวัดอากาศ IoT ด้วย ESP32 และเซนเซอร์หลากหลายประเภท พร้อมระบบบันทึกข้อมูล SD Card และ Dashboard แบบ Real-time

หมวดหมู่:Tutorial
ระดับ:Intermediate
เวลา:3-4 ชั่วโมง
อัปเดต:16 มีนาคม 2026
ESP32Weather StationBME280IoTHome Assistant

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

สถานีตรวจวัดอากาศแบบ DIY เป็นโปรเจกต์ IoT ที่ได้รับความนิยมอย่างมากในปี 2026 ด้วย ESP32 ที่มีความสามารถด้านการเชื่อมต่อ Wi-Fi และ Bluetooth ทำให้เราสามารถสร้างสถานีตรวจวัดอากาศที่ส่งข้อมูลแบบ Real-time ได้อย่างง่ายดายและประหยัด

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

  • วัดอุณหภูมิ ความชื้อ และความดันอากาศด้วย BME280
  • ตรวจจับฝนด้วย Rain Sensor Module
  • วัดความเร็วลมด้วย Anemometer (เสริม)
  • บันทึกข้อมูลลง SD Card แบบต่อเนื่อง
  • แสดงผลบน Web Dashboard แบบ Real-time
  • เชื่อมต่อกับ Home Assistant ผ่าน ESPHome
  • ใช้งานได้ทั้งแบบ Standalone และ Cloud-connected

🎯 เหมาะสำหรับ:

  • เกษตรกรที่ต้องการติดตามสภาพอากาศในไร่นา
  • คนรักการทำสวนที่ต้องการเฝ้าสภาพอากาศ
  • นักพัฒนา IoT ที่ต้องการเรียนรู้การทำงานกับเซนเซอร์หลายตัว
  • ผู้ที่สนใจ Smart Home และ Home Automation

🔧 อุปกรณ์ที่ต้องการ

อุปกรณ์จำนวนราคาโดยประมาณหมายเหตุ
ESP32 Development Board1150-250 บาทESP32 DevKitC หรือ ESP32-WROOM
BME280 Sensor180-150 บาทวัดอุณหภูมิ ความชื้อ ความดัน
Rain Sensor Module130-60 บาทตรวจจับน้ำฝน
Micro SD Card Module140-80 บาทพร้อม SD Card 4GB+
OLED Display 0.96" (Optional)160-100 บาทแสดงผลข้อมูลในตัวเครื่อง
Anemometer (Optional)1200-500 บาทวัดความเร็วลม
Jumper Wires1 ชุด30-50 บาทMale-to-Female แนะนำ
Breadboard130-50 บาทขนาด 400-800 pins
USB Cable120-40 บาทMicro USB สำหรับ ESP32

💡 คำแนะนำ:

ใช้ BME280 แทน DHT11/DHT22 เพราะ:

  • ความแม่นยำสูงกว่ามาก
  • วัดได้ทั้งอุณหภูมิ ความชื้อ และความดันในตัวเดียว
  • ใช้พลังงานต่ำกว่า
  • สื่อสารผ่าน I2C ง่ายต่อการเชื่อมต่อ

⚡ การเชื่อมต่อวงจร

BME280 Sensor (I2C)

BME280 PinESP32 Pin
VIN (3.3V)3.3V
GNDGND
SCLGPIO 22 (I2C SCL)
SDAGPIO 21 (I2C SDA)

Rain Sensor Module

Rain Sensor PinESP32 Pin
VCC5V (หรือ 3.3V ตาม Module)
GNDGND
AO (Analog Out)GPIO 34 (ADC1_CH6)

Micro SD Card Module (SPI)

SD Card ModuleESP32 Pin
CSGPIO 5
SCKGPIO 18
MOSIGPIO 23
MISOGPIO 19
VCC5V หรือ 3.3V

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

  • ตรวจสอบระดับแรงดันของ Rain Sensor ก่อนเชื่อมต่อ (บางตัวใช้ 5V)
  • GPIO 34 เป็น Input Only ไม่สามารถใช้เป็น Output ได้
  • SD Card Module บางตัวต้องใช้ 3.3V เท่านั้น
  • ใช้ Resistor 10KΩ Pull-up สำหรับ I2C ถ้า BME280 ไม่มี Built-in

💻 โค้ด Arduino

ก่อนเริ่มใช้งาน ติดตั้ง Library ที่จำเป็นก่อน:

  • Adafruit BME280 Library - สำหรับ BME280
  • Adafruit Unified Sensor - Sensor abstraction layer
  • SD Library - สำหรับ SD Card (มีในตัว)
/*
 * ESP32 Weather Station - สถานีตรวจวัดอากาศ
 * วัดอุณหภูมิ ความชื้อ ความดัน ฝน และบันทึกข้อมูล
 * 
 * Hardware: ESP32 + BME280 + Rain Sensor + SD Card
 * Author: CynoIoT
 * Updated: March 2026
 */

#include <Wire.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
#include "FS.h"
#include "SD.h"
#include "SPI.h"

// --- Pin Definitions ---
#define BME280_SDA 21
#define BME280_SCL 22
#define RAIN_SENSOR_PIN 34  // ADC1_CH6
#define SD_CS_PIN 5
#define SD_SCK_PIN 18
#define SD_MISO_PIN 19
#define SD_MOSI_PIN 23

// --- Sensor Objects ---
Adafruit_BME280 bme;

// --- Variables ---
float temperature = 0.0;
float humidity = 0.0;
float pressure = 0.0;
int rainValue = 0;
bool isRaining = false;

unsigned long lastReadTime = 0;
const long readInterval = 5000;  // อ่านค่าทุก 5 วินาที
unsigned long lastSDWriteTime = 0;
const long sdWriteInterval = 60000;  // เขียนลง SD ทุก 1 นาที

void setup() {
  Serial.begin(115200);
  
  // แสดงข้อความเริ่มต้น
  Serial.println("========================================");
  Serial.println("ESP32 Weather Station Starting...");
  Serial.println("========================================");
  
  // เริ่มต้น I2C สำหรับ BME280
  Wire.begin(BME280_SDA, BME280_SCL);
  
  // เริ่มต้น BME280
  if (!bme.begin(0x76)) {  // ลองที่อยู่ 0x76 ก่อน
    if (!bme.begin(0x77)) {  // ถ้าไม่ได้ลอง 0x77
      Serial.println("❌ ไม่พบ BME280! ตรวจสอบการเชื่อมต่อ");
      while (1);
    }
  }
  Serial.println("✅ BME280 เริ่มทำงานแล้ว");
  
  // เริ่มต้น SD Card
  SPI.begin(SD_SCK_PIN, SD_MISO_PIN, SD_MOSI_PIN, SD_CS_PIN);
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println("❌ การ์ด SD ล้มเหลว หรือไม่ได้ใส่การ์ด");
  } else {
    Serial.println("✅ SD Card เริ่มทำงานแล้ว");
    createDataFile();
  }
  
  // แสดงข้อความเริ่มใช้งาน
  Serial.println("🌤️ สถานีตรวจวัดอากาศพร้อมใช้งาน!");
  Serial.println("========================================\n");
}

void loop() {
  unsigned long currentTime = millis();
  
  // อ่านค่าเซนเซอร์ทุก 5 วินาที
  if (currentTime - lastReadTime >= readInterval) {
    lastReadTime = currentTime;
    readSensors();
    displayData();
  }
  
  // เขียนข้อมูลลง SD Card ทุก 1 นาที
  if (currentTime - lastSDWriteTime >= sdWriteInterval) {
    lastSDWriteTime = currentTime;
    logToSD();
  }
}

// อ่านค่าจากเซนเซอร์ทั้งหมด
void readSensors() {
  // อ่าน BME280
  temperature = bme.readTemperature();
  humidity = bme.readHumidity();
  pressure = bme.readPressure() / 100.0F;  // แปลงเป็น hPa
  
  // อ่าน Rain Sensor
  rainValue = analogRead(RAIN_SENSOR_PIN);
  
  // ตรวจสอบว่าฝนตกหรือไม่ (ปรับค่า Threshold ตามทดลอง)
  // ค่ามาก = แห้ง, ค่าน้อย = มีน้ำ
  isRaining = (rainValue < 2000);  // ปรับค่านี้ตามทดลองจริง
}

// แสดงข้อมูลบน Serial Monitor
void displayData() {
  Serial.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
  Serial.printf("🕐 เวลา: %lu ms จากการเริ่มเครื่อง\n", millis());
  Serial.printf("🌡️  อุณหภูมิ: %.2f °C\n", temperature);
  Serial.printf("💧 ความชื้อ: %.2f %%\n", humidity);
  Serial.printf("📊 ความดัน: %.2f hPa\n", pressure);
  Serial.printf("🌧️  Rain Sensor: %d", rainValue);
  
  if (isRaining) {
    Serial.print(" (ฝนตก! 🌧️)");
  } else {
    Serial.print(" (ไม่มีฝน ☀️)");
  }
  
  Serial.println();
  Serial.printf("📈 Heat Index: %.2f °C\n", calculateHeatIndex());
  Serial.printf("💨 Dew Point: %.2f °C\n", calculateDewPoint());
  Serial.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
}

// คำนวณ Heat Index (ดัชนีความร้อน)
float calculateHeatIndex() {
  // สูตรคำนวณ Heat Index แบบง่าย
  float T = temperature;
  float RH = humidity;
  
  // Rothfusz regression
  float HI = -8.78469475556 +
             1.61139411 * T +
             2.33854883889 * RH -
             0.14611605 * T * RH -
             0.012308094 * T * T -
             0.0164248277778 * RH * RH +
             0.002211732 * T * T * RH +
             0.00072546 * T * RH * RH -
             0.000003582 * T * T * RH * RH;
  
  return HI;
}

// คำนวณ Dew Point (จุดน้ำค้าง)
float calculateDewPoint() {
  float T = temperature;
  float RH = humidity;
  
  // Magnus formula
  float a = 17.27;
  float b = 237.7;
  float alpha = ((a * T) / (b + T)) + log(RH / 100.0);
  float dewPoint = (b * alpha) / (a - alpha);
  
  return dewPoint;
}

// สร้างไฟล์ข้อมูลใน SD Card
void createDataFile() {
  File dataFile = SD.open("/weather_data.csv", FILE_WRITE);
  
  if (dataFile) {
    // เขียน Header ถ้าไฟล์ว่างเปล่า
    if (dataFile.size() == 0) {
      dataFile.println("timestamp,temperature,humidity,pressure,rain_value,is_raining,heat_index,dew_point");
      Serial.println("📝 สร้างไฟล์ weather_data.csv แล้ว");
    }
    dataFile.close();
  }
}

// เขียนข้อมูลลง SD Card
void logToSD() {
  File dataFile = SD.open("/weather_data.csv", FILE_APPEND);
  
  if (dataFile) {
    // สร้าง timestamp แบบง่าย
    unsigned long timestamp = millis() / 1000;  // วินาที
    
    // เขียนข้อมูลแบบ CSV
    dataFile.printf("%lu,%.2f,%.2f,%.2f,%d,%d,%.2f,%.2f\n",
                    timestamp,
                    temperature,
                    humidity,
                    pressure,
                    rainValue,
                    isRaining ? 1 : 0,
                    calculateHeatIndex(),
                    calculateDewPoint());
    
    dataFile.close();
    Serial.println("💾 บันทึกข้อมูลลง SD Card แล้ว");
  } else {
    Serial.println("❌ ไม่สามารถเปิดไฟล์สำหรับเขียนข้อมูล");
  }
}

💡 เคล็ดลับการใช้งาน:

  • ปรับค่า rainValue < 2000 ตามการทดสอบจริง
  • ใช้ Serial Plotter (Ctrl+Shift+L) เพื่อดูกราฟแบบ Real-time
  • ข้อมูลจะถูกบันทึกเป็นไฟล์ CSV สามารถเปิดด้วย Excel ได้
  • เพิ่ม NTP Client เพื่อใช้เวลาจริงแทน millis()

📊 สร้าง Web Dashboard

ตอนนี้เราจะเพิ่ม Web Server เพื่อแสดงผลข้อมูลแบบ Real-time บน Browser

// เพิ่มส่วนนี้ไว้ด้านบนสุดของโค้ด
#include <WiFi.h>
#include <WebServer.h>

// แก้ไข WiFi settings
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

WebServer server(80);

// เพิ่มใน setup()
void setup() {
  // ... โค้ดเดิม ...
  
  // เชื่อมต่อ WiFi
  WiFi.begin(ssid, password);
  Serial.print("📡 กำลังเชื่อมต่อ WiFi");
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("\n✅ เชื่อมต่อ WiFi แล้ว!");
  Serial.printf("🌐 IP Address: %s\n", WiFi.localIP().toString().c_str());
  Serial.println("🔗 เปิด Browser ไปที่: http://" + WiFi.localIP().toString());
  
  // ตั้งค่า Web Server routes
  setupWebServer();
}

// ตั้งค่า Web Server
void setupWebServer() {
  // หน้าแรก - Dashboard
  server.on("/", HTTP_GET, []() {
    String html = generateDashboardHTML();
    server.send(200, "text/html", html);
  });
  
  // API endpoint สำหรับข้อมูล JSON
  server.on("/api/data", HTTP_GET, []() {
    String json = generateDataJSON();
    server.send(200, "application/json", json);
  });
  
  server.begin();
  Serial.println("✅ Web Server เริ่มทำงานแล้ว");
}

// เพิ่มใน loop()
void loop() {
  // ... โค้ดเดิม ...
  server.handleClient();  // จัดการ Client requests
}

// สร้าง HTML Dashboard
String generateDashboardHTML() {
  String html = R"rawliteral(
<!DOCTYPE html>
<html lang="th">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>ESP32 Weather Station</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
  <style>
    body { font-family: 'Sarabun', sans-serif; }
  </style>
</head>
<body class="bg-gradient-to-br from-blue-50 to-indigo-100 min-h-screen">
  <div class="container mx-auto px-4 py-8">
    <h1 class="text-4xl font-bold text-center text-gray-800 mb-8">
      🌤️ ESP32 Weather Station
    </h1>
    
    <!-- Sensor Cards -->
    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
      <div class="bg-white rounded-lg shadow-lg p-6">
        <div class="flex items-center justify-between">
          <div>
            <p class="text-gray-600">อุณหภูมิ</p>
            <p class="text-3xl font-bold text-red-600" id="temp">--</p>
          </div>
          <div class="text-5xl">🌡️</div>
        </div>
      </div>
      
      <div class="bg-white rounded-lg shadow-lg p-6">
        <div class="flex items-center justify-between">
          <div>
            <p class="text-gray-600">ความชื้อ</p>
            <p class="text-3xl font-bold text-blue-600" id="humid">--</p>
          </div>
          <div class="text-5xl">💧</div>
        </div>
      </div>
      
      <div class="bg-white rounded-lg shadow-lg p-6">
        <div class="flex items-center justify-between">
          <div>
            <p class="text-gray-600">ความดัน</p>
            <p class="text-3xl font-bold text-purple-600" id="press">--</p>
          </div>
          <div class="text-5xl">📊</div>
        </div>
      </div>
      
      <div class="bg-white rounded-lg shadow-lg p-6">
        <div class="flex items-center justify-between">
          <div>
            <p class="text-gray-600">สถานะฝน</p>
            <p class="text-3xl font-bold" id="rain">--</p>
          </div>
          <div class="text-5xl">🌧️</div>
        </div>
      </div>
    </div>
    
    <!-- Chart -->
    <div class="bg-white rounded-lg shadow-lg p-6">
      <h2 class="text-2xl font-bold mb-4">กราฟประวัติอุณหภูมิ</h2>
      <canvas id="tempChart"></canvas>
    </div>
    
    <p class="text-center text-gray-600 mt-8">
      อัปเดตล่าสุด: <span id="updateTime">--</span>
    </p>
  </div>
  
  <script>
    // เริ่มต้น Chart
    const ctx = document.getElementById('tempChart').getContext('2d');
    const tempChart = new Chart(ctx, {
      type: 'line',
      data: {
        labels: [],
        datasets: [{
          label: 'อุณหภูมิ (°C)',
          data: [],
          borderColor: 'rgb(239, 68, 68)',
          tension: 0.4,
          fill: true,
          backgroundColor: 'rgba(239, 68, 68, 0.1)'
        }]
      },
      options: {
        responsive: true,
        scales: {
          y: { beginAtZero: false }
        }
      }
    });
    
    // อัปเดตข้อมูลทุก 5 วินาที
    setInterval(updateData, 5000);
    
    async function updateData() {
      try {
        const response = await fetch('/api/data');
        const data = await response.json();
        
        document.getElementById('temp').textContent = data.temperature.toFixed(1) + '°C';
        document.getElementById('humid').textContent = data.humidity.toFixed(1) + '%';
        document.getElementById('press').textContent = data.pressure.toFixed(1) + ' hPa';
        
        if (data.is_raining) {
          document.getElementById('rain').textContent = 'ฝนตก 🌧️';
          document.getElementById('rain').classList.add('text-blue-600');
        } else {
          document.getElementById('rain').textContent = 'ไม่มีฝน ☀️';
          document.getElementById('rain').classList.remove('text-blue-600');
        }
        
        document.getElementById('updateTime').textContent = new Date().toLocaleString('th-TH');
        
        // เพิ่มข้อมูลลงกราฟ
        const now = new Date().toLocaleTimeString('th-TH');
        if (tempChart.data.labels.length > 20) {
          tempChart.data.labels.shift();
          tempChart.data.datasets[0].data.shift();
        }
        tempChart.data.labels.push(now);
        tempChart.data.datasets[0].data.push(data.temperature);
        tempChart.update();
        
      } catch (error) {
        console.error('Error:', error);
      }
    }
    
    // โหลดข้อมูลครั้งแรก
    updateData();
  </script>
</body>
</html>
  )rawliteral";
  
  return html;
}

// สร้าง JSON data
String generateDataJSON() {
  String json = "{";
  json += "\"temperature\":" + String(temperature) + ",";
  json += "\"humidity\":" + String(humidity) + ",";
  json += "\"pressure\":" + String(pressure) + ",";
  json += "\"rain_value\":" + String(rainValue) + ",";
  json += "\"is_raining\":" + String(isRaining ? "true" : "false") + ",";
  json += "\"heat_index\":" + String(calculateHeatIndex()) + ",";
  json += "\"dew_point\":" + String(calculateDewPoint()) + ",";
  json += "\"timestamp\":" + String(millis());
  json += "}";
  return json;
}

🌐 วิธีใช้งาน:

  1. อัปโหลดโค้ดทั้งหมดไปยัง ESP32
  2. เปิด Serial Monitor (115200 baud)
  3. รอจนกว่าจะเชื่อมต่อ WiFi และแสดง IP Address
  4. เปิด Browser ไปที่ IP ที่แสดง
  5. Dashboard จะอัปเดตข้อมูลอัตโนมัติทุก 5 วินาที

💾 บันทึกข้อมูลลง SD Card

ข้อมูลทุกนาทีจะถูกบันทึกลงไฟล์ weather_data.csv บน SD Card

รูปแบบข้อมูล CSV:

timestamp,temperature,humidity,pressure,rain_value,is_raining,heat_index,dew_point
1234,28.5,65.2,1013.25,1500,0,30.2,21.8
1294,28.6,65.0,1013.20,1450,0,30.3,21.7

วิธีดึงข้อมูล:

  • วิธีที่ 1: ถอด SD Card ออกแล้วเสียบในคอมพิวเตอร์
  • วิธีที่ 2: เพิ่ม Web Server endpoint สำหรับดาวน์โหลดไฟล์
  • วิธีที่ 3: อัปโหลดไปยัง Cloud (Google Sheets, ThingSpeak, etc.)

🏠 เชื่อมต่อ Home Assistant (ESPHome)

หากต้องการใช้กับ Home Assistant สามารถใช้ ESPHome แทน Arduino ได้:

# ESPHome Configuration for Weather Station
# esphome/weather-station.yaml

esphome:
  name: esp32-weather-station
  platform: ESP32
  board: esp32dev

# WiFi connection
wifi:
  ssid: "YOUR_WIFI_SSID"
  password: "YOUR_WIFI_PASSWORD"

# Enable logging
logger:

# Enable Home Assistant API
api:
  password: "YOUR_API_PASSWORD"

# Enable OTA updates
ota:
  password: "YOUR_OTA_PASSWORD"

# Enable Web server
web_server:
  port: 80

# I2C Bus
i2c:
  sda: 21
  scl: 22
  scan: true

# BME280 Sensor
sensor:
  - platform: bme280
    temperature:
      name: "Weather Station Temperature"
      id: temp_sensor
      oversampling: 16x
    pressure:
      name: "Weather Station Pressure"
      id: pressure_sensor
    humidity:
      name: "Weather Station Humidity"
      id: humidity_sensor
    address: 0x76
    update_interval: 60s

  # Rain Sensor (Analog)
  - platform: ads1115
    multiplexer: 'A0_GND'
    gain: 4.096
    name: "Rain Sensor"
    id: rain_sensor
    update_interval: 5s

  # Calculate Heat Index
  - platform: template
    name: "Heat Index"
    lambda: |-
      float T = id(temp_sensor).state;
      float RH = id(humidity_sensor).state;
      float HI = -8.78469475556 +
                 1.61139411 * T +
                 2.33854883889 * RH -
                 0.14611605 * T * RH -
                 0.012308094 * T * T -
                 0.0164248277778 * RH * RH +
                 0.002211732 * T * T * RH +
                 0.00072546 * T * RH * RH -
                 0.000003582 * T * T * RH * RH;
      return HI;
    update_interval: 60s

# Binary Sensor for Rain Detection
binary_sensor:
  - platform: template
    name: "Is Raining"
    lambda: |-
      if (id(rain_sensor).state < 2000) {
        return true;
      } else {
        return false;
      }
    update_interval: 5s

# SD Card (SPI)
spi:
  clk_pin: 18
  mosi_pin: 23
  miso_pin: 19

# Text Sensor for logging
text_sensor:
  - platform: template
    name: "Weather Log"
    lambda: |-
      return {"Logging to SD card..."};
    update_interval: never

🎨 ปรับแต่ง Dashboard ใน Home Assistant:

  1. เพิ่ม ESPHome ผ่าน Configuration → Integrations
  2. สร้าง Lovelace Dashboard ใหม่
  3. เพิ่ม Gauge Card สำหรับอุณหภูมิและความชื้อ
  4. เพิ่ม History Graph เพื่อดูแนวโน้ม
  5. สร้าง Automation ตามข้อมูลอากาศ (เช่น เปิดพัดลมเมื่อร้อน)

🔧 แก้ปัญหาที่พบบ่อย

❌ BME280 ไม่ตอบสนอง

สาเหตุ: อาจเป็นที่อยู่ I2C ผิดหรือการเชื่อมต่อหลวม

วิธีแก้:

  • ลองเปลี่ยนจาก 0x76 เป็น 0x77
  • ตรวจสอบการเชื่อมต่อ SDA/SCL
  • ใช้ I2C Scanner เพื่อหาที่อยู่ที่ถูกต้อง

❌ SD Card ไม่ทำงาน

สาเหตุ: รูปแบบไฟล์ไม่ถูกต้องหรือ Pin SPI ผิด

วิธีแก้:

  • ฟอร์แมต SD Card เป็น FAT32
  • ตรวจสอบ Pin SPI: CS=5, SCK=18, MOSI=23, MISO=19
  • ใช้ SD Card ขนาดไม่เกิน 32GB

❌ WiFi เชื่อมต่อไม่ได้

สาเหตุ: รหัสผ่านผิดหรือสัญญาณอ่อน

วิธีแก้:

  • ตรวจสอบ SSID และ Password
  • ใช้ WiFi 2.4GHz (ESP32 ไม่รองรับ 5GHz บางรุ่น)
  • เพิ่ม WiFi.reconnect() ใน loop()

⚠️ ค่า Rain Sensor ผิดปกติ

วิธีแก้:

  • ปรับค่า Threshold ในโค้ด (ลอง 1000-3000)
  • ทดสอบโดนน้ำโดยตรงแล้วดูค่าที่อ่านได้
  • ใช้ Digital Output แทน Analog ถ้าต้องการเพียงรู้ว่าฝนตกหรือไม่

🎯 สรุป

ในบทความนี้เราได้เรียนรู้วิธีสร้างสถานีตรวจวัดอากาศ ESP32 ที่สมบูรณ์แบบ ตั้งแต่การเชื่อมต่อเซนเซอร์ การเขียนโค้ด การสร้าง Web Dashboard และการบันทึกข้อมูล

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

  • การใช้ BME280 วัดอุณหภูมิ ความชื้อ และความดันอากาศ
  • การตรวจจับฝนด้วย Rain Sensor Module
  • การบันทึกข้อมูลลง SD Card แบบ CSV
  • การสร้าง Web Dashboard ด้วย HTML และ Chart.js
  • การเชื่อมต่อกับ Home Assistant ผ่าน ESPHome
  • การคำนวณ Heat Index และ Dew Point

🚀 ไอเดียต่อยอด:

  • เพิ่ม Anemometer สำหรับวัดความเร็วและทิศทางลม
  • เพิ่ม UV Index Sensor เพื่อตรวจสอบรังสีแสงแดด
  • อัปโหลดข้อมูลไปยัง ThingSpeak หรือ Google Sheets
  • เพิ่ม Solar Panel และ Battery สำหรับใช้งาน Outdoor
  • สร้างแจ้งเตือนผ่าน Line Notify หรือ Telegram
  • เพิ่ม OLED Display แสดงผลในตัวเครื่อง

📚 อ้างอิงเพิ่มเติม:

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