#include <Wire.h> // เรียกใช้งาน Library ควบคุมเส้นทางการสื่อสารแบบ I2C
#include <Adafruit_GFX.h> // เรียกใช้งาน Library จัดการกราฟิก เช่น ขนาดอักษร วาดเส้น
#include <Adafruit_SSD1306.h> // เรียกใช้งาน Library สำหรับสั่งการหน้าจอ OLED โดยเฉพาะ
#include <DHT.h> // เรียกใช้งาน Library สำหรับคุยกับเซนเซอร์อุณหภูมิและความชื้น
// ตั้งค่าจอ OLED
#define SCREEN_WIDTH 128 // กำหนดความกว้างของหน้าจอ OLED เป็น 128 พิกเซล
#define SCREEN_HEIGHT 64 // กำหนดความสูงของหน้าจอ OLED เป็น 64 พิกเซล
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // สร้างตัวแปรชื่อ display ควบคุมจอ (ไม่มีขารีเซ็ต = -1)
// ตั้งค่า DHT22
#define DHTPIN 4 // กำหนดให้สายข้อมูลเซนเซอร์ (Data) ต่อกับบอร์ดที่ขา 4
#define DHTTYPE DHT22 // ระบุว่าเราใช้เซนเซอร์รุ่น DHT22
DHT dht(DHTPIN, DHTTYPE); // สร้างตัวแปรชื่อ dht เตรียมไว้สำหรับดึงค่าเซนเซอร์
void setup() { // ฟังก์ชัน setup() ทำงานแค่ "ครั้งเดียว" ตอนเปิดบอร์ด
Serial.begin(115200); // เปิดการเชื่อมต่อส่งข้อมูลเข้าคอมพิวเตอร์ที่ความเร็ว 115200
dht.begin(); // สั่งให้ตัวเซนเซอร์ DHT เริ่มทำงาน
// เริ่มต้นหน้าจอ OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // ตรวจสอบว่าบอร์ดมองเห็นจอ OLED ที่ Address 0x3C หรือไม่
Serial.println(F("SSD1306 allocation failed")); // ถ้าไม่เจอจอ ให้พิมพ์แจ้ง Error บนคอมพิวเตอร์
for(;;); // สั่งให้บอร์ดหยุดทำงานค้างไว้ตรงนี้ ไม่ต้องทำอย่างอื่นต่อ
}
display.clearDisplay(); // ล้างหน้าจอให้สะอาดก่อน
// 1. พิมพ์ข้อความชื่อโปรเจกต์
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(15, 20); // กะระยะให้อยู่กึ่งกลางจอ
display.print("SPTC GREENHOUSE");
// 2. วาด "กรอบเปล่า" ของหลอดโหลดข้อมูล
// รูปแบบ drawRect(แกน X, แกน Y, ความกว้าง, ความสูง, สี)
display.drawRect(14, 40, 100, 10, WHITE);
display.display(); // สั่งแสดงผลกรอบเปล่าขึ้นจอก่อน
// 3. วาด "แถบสีทึบ" ให้ค่อยๆ วิ่งจนเต็มกรอบ
// ใช้ลูป for ให้นับเลข 0 ถึง 100 เก็บไว้ในตัวแปร i
for (int i = 0; i <= 100; i++) {
// ให้ความกว้างของสี่เหลี่ยมทึบ เพิ่มขึ้นตามค่า i
display.fillRect(14, 40, i, 10, WHITE);
display.display(); // อัปเดตหน้าจอทุกครั้งที่ขยับ 1 พิกเซล
delay(20); // หน่วงเวลา 20 มิลลิวินาที (ยิ่งค่าน้อย หลอดยิ่งวิ่งเร็ว)
}
// 4. โหลดเสร็จแล้ว ค้างหน้าจอไว้ 1 วินาทีให้คนดูทัน แล้วเคลียร์ทิ้ง
delay(1000);
display.clearDisplay();
// ---------------------------------------------------
}
void loop() { // ฟังก์ชัน loop() ทำงานวนซ้ำไปเรื่อยๆตลอดเวลาที่เปิดเครื่อง
float h = dht.readHumidity(); // อ่านค่าความชื้นมาเก็บในตัวแปร h (ใช้ float เพราะมีทศนิยม)
float t = dht.readTemperature(); // อ่านค่าอุณหภูมิมาเก็บในตัวแปร t (ใช้ float เพราะมีทศนิยม)
if (isnan(h) || isnan(t)) { // ตรวจสอบว่าค่า h หรือ t ออกมาสำเร็จไหม
Serial.println("Failed to read from DHT sensor!"); // ถ้าไม่สำเร็จ ให้พิมพ์แจ้งเตือนบนคอมพิวเตอร์
return; // สั่งให้จบการทำงานรอบนี้ทันที เพื่อกลับไปเริ่มบรรทัดบนสุดของ loop ใหม่
}
// ส่วนของการจัดรูปแบบแสดงผลบนหน้าจอ OLED
display.clearDisplay(); // ล้างกระดานหน้าจอให้ว่างเปล่าก่อนเริ่มเขียนรอบใหม่
display.setCursor(0, 0); // เอาเคอเซอร์ไปจ่อที่พิกัด X:0, Y:0 (มุมซ้ายบนสุดของจอ)
display.setTextSize(1); // กำหนดขนาดตัวอักษรเป็นไซส์ 1 (ขนาดเล็ก)
display.println("SMART FARM MONITOR"); // แสดงข้อความ SMART FARM MONITOR
display.setTextSize(2); // เปลี่ยนขนาดตัวอักษรเป็นไซส์ 2 (ใหญ่ขึ้นมาหน่อย)
display.setCursor(0, 20); // ย้ายเคอเซอร์ลงมาที่พิกัด X:0, Y:20
display.print("T "); display.print(t); display.println(" C"); // แสดงตัว T ตามด้วยค่าอุณหภูมิ และตัว C
display.setCursor(0, 45); // ย้ายเคอเซอร์ลงมาอีกที่พิกัด X:0, Y:45
display.print("H "); display.print(h); display.println(" %"); // แสดงตัว H ตามด้วยค่าความชื้น และ %
// Challenge ถ้าอุณหภูมิเกิน 35C ให้แจ้งเตือน
if(t > 35.0) { // ตรวจสอบเงื่อนไข ถ้าอุณหภูมิ (t) มีค่ามากกว่า 35.0 องศา
display.setTextSize(1); // ปรับขนาดอักษรกลับมาไซส์ 1
display.setCursor(85, 10); // ย้ายเคอเซอร์ไปพิกัด X:85, Y:10 แถวมุมขวาบน
display.print("HOT!"); // แสดงคำเตือนว่า HOT!
}
display.display(); // สำคัญมาก นำสิ่งที่เราจัดเตรียมไว้ทั้งหมดข้างต้น ส่งไปแสดงบนจอภาพจริงๆ
delay(2000); // สั่งให้บอร์ดหยุดรอ 2 วินาที เพื่อให้พอดีกับที่เซนเซอร์ DHT22 อัปเดตค่ารอบใหม่
}