หลักสูตรประกาศนียบัตรวิชาชีพชั้นสูง (ปวส.) สาขาวิชาเทคโนโลยีสารสนเทศ / อิเล็กทรอนิกส์ สำนักงานคณะกรรมการการอาชีวศึกษา (สอศ.) รหัสวิชา 31910-2012 จำนวน 3.0 หน่วยกิต ปูพื้นฐานสถาปัตยกรรมระบบสมองกลฝังตัว Arduino & ESP32, การประมวลผลสัญญาณเซนเซอร์, ระบบขับเร้า, โปรโตคอล MQTT / LINE Notify / Web Server และคลาวด์ไอโอที พร้อมเอกสารวิชาการส่งงาน ว.PA ครบวงจร
เจาะลึกฮาร์ดแวร์ไมโครคอนโทรลเลอร์ ATmega328P และ ESP32, โครงสร้างโค้ด C/C++, ระบบเวลา Multitasking, การจัดการสัญญาณ Digital/Analog
delay(ms) จะทำให้ CPU ถูกกักขังอยู่ในวงรอบว่าง (Busy-wait loop) ไม่สามารถตอบสนองต่อเซนเซอร์หรือเครือข่ายได้ ในระบบงานจริงระดับ ปวส. จึงต้องเปลี่ยนมาใช้แนวคิด State Machine และฟังก์ชัน millis() ซึ่งคืนค่าจำนวนมิลลิวินาทีที่เปิดเครื่องขึ้นมา ทำให้สามารถจัดการงานหลายอย่างพร้อมกัน (Non-blocking Co-operative Multitasking)
setup() ทำงานเพียงรอบเดียวเพื่อกำหนดโหมดขาพอร์ต และ loop() ทำงานวนรอบซ้ำอย่างต่อเนื่องunsigned long (32-bit) เพื่อรองรับเวลาสะสมต่อเนื่องได้นานถึง ~49.7 วันก่อนที่ค่าจะวนกลับมาเป็น 0if (currentMillis - previousMillis >= interval) ป้องกันปัญหา Rollover ได้อย่างสมบูรณ์// โค้ดตัวอย่างที่ 1: ควบคุมไฟกระพริบโดยไม่บล็อกซีพียู (Non-blocking Blink)
const int LED_PIN = 2; // ขา LED บนบอร์ด (ESP32 คือ GPIO2, Uno คือขา 13)
const unsigned long INTERVAL = 1000; // รอบเวลา 1,000 มิลลิวินาที (1 วินาที)
unsigned long previousMillis = 0; // ตัวแปรจำเวลาครั้งล่าสุด
int ledState = LOW; // สถานะหลอดไฟ
void setup() {
pinMode(LED_PIN, OUTPUT);
Serial.begin(115200);
Serial.println("System Ready: Non-blocking LED Blinker");
}
void loop() {
unsigned long currentMillis = millis();
// ตรวจสอบว่าเวลาผ่านไปครบช่วงที่กำหนดหรือยัง
if (currentMillis - previousMillis >= INTERVAL) {
previousMillis = currentMillis;
// สลับสถานะหลอดไฟ (Toggle)
ledState = (ledState == LOW) ? HIGH : LOW;
digitalWrite(LED_PIN, ledState);
Serial.print("Timestamp: ");
Serial.print(currentMillis);
Serial.print(" ms | LED State: ");
Serial.println(ledState == HIGH ? "ON" : "OFF");
}
// ซีพียูสามารถประมวลผลงานอื่น เช่น อ่านค่าเซนเซอร์ หรือรับข้อมูลเครือข่าย ในลูปนี้ได้ทันที
}
long (Signed) ในการเก็บเวลา เพราะเมื่อค่าเวลาเกิน 2,147,483,647 ms (~24.8 วัน) จะเกิดเครื่องหมายลบ ส่งผลให้เงื่อนไข if เกิดข้อผิดพลาดและอุปกรณ์หยุดทำงานทันที!
loop() เดียวกันโดยไม่ใช้ delay()
unsigned long prevRed = 0, prevGreen = 0;
const unsigned long INT_RED = 1000, INT_GREEN = 350;
int stateRed = LOW, stateGreen = LOW;
void loop() {
unsigned long now = millis();
if (now - prevRed >= INT_RED) {
prevRed = now;
stateRed = !stateRed;
digitalWrite(2, stateRed);
}
if (now - prevGreen >= INT_GREEN) {
prevGreen = now;
stateGreen = !stateGreen;
digitalWrite(4, stateGreen);
}
}
\n หรือ \r) และตัดอักขระส่วนเกินด้วย trim() ก่อนส่งเข้าสู่ฟังก์ชันตรวจสอบเงื่อนไข
const int RELAY_PIN = 4;
void setup() {
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
Serial.begin(115200);
while (!Serial) { ; }
Serial.println("=========================================");
Serial.println(" IoT Serial Command Parser System Ready ");
Serial.println(" Commands: LED:ON | LED:OFF | STATUS ");
Serial.println("=========================================");
}
void loop() {
if (Serial.available() > 0) {
String cmd = Serial.readStringUntil('\n');
cmd.trim(); // กำจัด \r หรือช่องว่างหัวท้าย
if (cmd.equalsIgnoreCase("LED:ON")) {
digitalWrite(RELAY_PIN, HIGH);
Serial.println("[ACK] Relay Output is now ACTIVATED (ON)");
}
else if (cmd.equalsIgnoreCase("LED:OFF")) {
digitalWrite(RELAY_PIN, LOW);
Serial.println("[ACK] Relay Output is now DEACTIVATED (OFF)");
}
else if (cmd.equalsIgnoreCase("STATUS")) {
int st = digitalRead(RELAY_PIN);
Serial.print("[INFO] Current Relay State is: ");
Serial.println(st == HIGH ? "ON" : "OFF");
Serial.print("[INFO] System Uptime: ");
Serial.print(millis() / 1000);
Serial.println(" seconds");
}
else {
Serial.print("[ERR] Unknown Command: ");
Serial.println(cmd);
}
}
}
SET:INTERVAL:500 หรือ SET:PWM:180 โดยใช้ฟังก์ชัน cmd.indexOf(':') และ cmd.substring() เพื่อแยกตัวเลขพารามิเตอร์ไปใช้งานจริง
if (cmd.startsWith("SET:PWM:")) {
int val = cmd.substring(8).toInt();
val = constrain(val, 0, 255);
ledcWrite(0, val);
Serial.printf("[ACK] PWM set to %d\n", val);
}
const int BUTTON_PIN = 14; // สวิตช์ต่อกับขา GPIO14 และอีกขาลง GND
const int LED_PIN = 2;
int ledState = LOW;
int lastButtonReading = HIGH;
int buttonState = HIGH;
unsigned long lastDebounceTime = 0;
const unsigned long DEBOUNCE_DELAY = 50; // หน่วงเวลาตรวจสอบ 50ms
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP); // ใช้งานตัวต้านทานพูลอัปภายในชิป
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, ledState);
Serial.begin(115200);
Serial.println("Debounce Push Button System Ready");
}
void loop() {
int reading = digitalRead(BUTTON_PIN);
// เมื่อตรวจพบการเปลี่ยนแปลงของระดับสัญญาณ
if (reading != lastButtonReading) {
lastDebounceTime = millis();
}
// หากสัญญาณคงที่นานเกินค่า DEBOUNCE_DELAY ให้ยอมรับค่านั้น
if ((millis() - lastDebounceTime) > DEBOUNCE_DELAY) {
if (reading != buttonState) {
buttonState = reading;
// เมื่อปุ่มถูกกดลงจริง (Active LOW)
if (buttonState == LOW) {
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
Serial.print("Valid Press Detected! Toggle State: ");
Serial.println(ledState ? "HIGH" : "LOW");
}
}
}
lastButtonReading = reading;
}
const int POT_PIN = 34; // ขาต่อตัวต้านทานปรับค่าได้ (ADC1_CH6)
const int PWM_PIN = 18; // ขาขับสัญญาณ PWM ไปยัง LED
// การตั้งค่าฮาร์ดแวร์ PWM บน ESP32
const int PWM_FREQ = 5000; // ความถี่ 5 kHz
const int PWM_CHANNEL = 0; // ช่องสัญญาณหมายเลข 0
const int PWM_RESOLUTION = 8; // ความละเอียด 8-bit (ค่า 0-255)
void setup() {
Serial.begin(115200);
ledcSetup(PWM_CHANNEL, PWM_FREQ, PWM_RESOLUTION);
ledcAttachPin(PWM_PIN, PWM_CHANNEL);
Serial.println("Analog ADC & PWM Dimmer System Initialized");
}
void loop() {
int rawADC = analogRead(POT_PIN); // อ่านค่า ADC (0 - 4095)
float voltage = (rawADC / 4095.0) * 3.3; // คำนวณเป็นแรงดันโวลต์
// แปลงช่วงข้อมูล 0-4095 ให้เป็น 0-255 สำหรับ PWM Duty Cycle
int dutyCycle = map(rawADC, 0, 4095, 0, 255);
ledcWrite(PWM_CHANNEL, dutyCycle);
Serial.print("Raw ADC: ");
Serial.print(rawADC);
Serial.print(" | Voltage: ");
Serial.print(voltage, 2);
Serial.print(" V | PWM Duty: ");
Serial.println(dutyCycle);
delay(100);
}
การเชื่อมต่อทรานสดิวเซอร์ตรวจวัดสภาพแวดล้อมจริง การขับโหลดไฟฟ้ากำลัง และการสื่อสารผ่านบัส I2C แสดงผลผ่านกราฟิก OLED
#include "DHT.h"
#define DHTPIN 4 // ขาสัญญาณ Data ต่อกับ GPIO4
#define DHTTYPE DHT22 // ชนิดเซนเซอร์ DHT22 (AM2302)
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(115200);
Serial.println("DHT22 Temperature & Humidity Sensor Test");
dht.begin();
}
void loop() {
delay(2000); // DHT22 ต้องการช่วงเวลาอ่านค่าอย่างน้อย 2 วินาที
float humidity = dht.readHumidity();
float temperature = dht.readTemperature(); // องศาเซลเซียส
// ตรวจสอบความถูกต้องของข้อมูล (ป้องกันค่าว่างหรือ NaN)
if (isnan(humidity) || isnan(temperature)) {
Serial.println("[ERROR] Failed to read from DHT sensor! Check wiring.");
return;
}
// คำนวณ Heat Index (ดัชนีความร้อนที่ร่างกายสัมผัสได้จริง)
float hic = dht.computeHeatIndex(temperature, humidity, false);
Serial.print("ความชื้น: ");
Serial.print(humidity, 1);
Serial.print(" %RH | อุณหภูมิ: ");
Serial.print(temperature, 1);
Serial.print(" *C | ดัชนีความร้อน: ");
Serial.print(hic, 1);
Serial.println(" *C");
}
const int TRIG_PIN = 5;
const int ECHO_PIN = 18;
const int BUZZER_PIN = 19;
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
Serial.println("Ultrasonic Radar & Proximity Alarm Ready");
}
void loop() {
// ยิงพัลส์ Trigger กว้าง 10 ไมโครวินาที
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// วัดความกว้างพัลส์สะท้อนกลับ Echo (หน่วยไมโครวินาที)
long duration = pulseIn(ECHO_PIN, HIGH);
float distanceCm = (duration * 0.034) / 2.0;
Serial.print("ระยะห่างของวัตถุ: ");
Serial.print(distanceCm, 1);
Serial.println(" cm");
// ระบบแจ้งเตือนเมื่อวัตถุเข้ามาใกล้ต่ำกว่า 15 ซม.
if (distanceCm > 0 && distanceCm < 15.0) {
digitalWrite(BUZZER_PIN, HIGH);
} else {
digitalWrite(BUZZER_PIN, LOW);
}
delay(200);
}
const int RELAY_PIN = 23;
// โมดูลรีเลย์ส่วนใหญ่เป็นวงจร Active LOW
#define RELAY_ON LOW
#define RELAY_OFF HIGH
void setup() {
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, RELAY_OFF); // สถานะเริ่มต้น ปิดรีเลย์เสมอเพื่อความปลอดภัย
Serial.begin(115200);
Serial.println("Optocoupler Relay Controller Online");
}
void loop() {
Serial.println("[ACTION] สั่งเปิดโหลดไฟฟ้า (Relay ON)");
digitalWrite(RELAY_PIN, RELAY_ON);
delay(5000);
Serial.println("[ACTION] สั่งปิดโหลดไฟฟ้า (Relay OFF)");
digitalWrite(RELAY_PIN, RELAY_OFF);
delay(5000);
}
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setup() {
Serial.begin(115200);
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("OLED SSD1306 allocation failed"));
for(;;);
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
}
void loop() {
float fakeTemp = 28.5 + (random(0, 50) / 10.0);
float fakeHum = 65.0 + (random(0, 100) / 10.0);
display.clearDisplay();
// วาดหัวข้อ Dashboard
display.setTextSize(1);
display.setCursor(10, 0);
display.println(F("--- KRUBAS IoT NODE ---"));
display.drawLine(0, 10, 128, 10, SSD1306_WHITE);
// อุณหภูมิ
display.setCursor(0, 20);
display.print(F("TEMP: "));
display.setTextSize(2);
display.setCursor(42, 16);
display.print(fakeTemp, 1);
display.setTextSize(1);
display.print(F(" C"));
// ความชื้น
display.setCursor(0, 42);
display.print(F("HUM : "));
display.setTextSize(2);
display.setCursor(42, 38);
display.print(fakeHum, 1);
display.setTextSize(1);
display.print(F(" %"));
display.drawLine(0, 55, 128, 55, SSD1306_WHITE);
display.setCursor(15, 57);
display.print(F("STATUS: ONLINE [OK]"));
display.display();
delay(1000);
}
โครงข่าย Wi-Fi 802.11 b/g/n, สถาปัตยกรรม RESTful API, การแจ้งเตือน LINE Notify, โปรโตคอล MQTT และ Web Server ฝังในชิป
#include <WiFi.h>
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
void connectToWiFi() {
Serial.print("Connecting to Wi-Fi: ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 25) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n>>> Wi-Fi Connected Successfully! <<<");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
Serial.print("Subnet Mask: ");
Serial.println(WiFi.subnetMask());
Serial.print("Gateway IP: ");
Serial.println(WiFi.gatewayIP());
Serial.print("Signal (RSSI): ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
} else {
Serial.println("\n[ERROR] Connection Timeout!");
}
}
void setup() {
Serial.begin(115200);
connectToWiFi();
}
void loop() {
// ตรวจจับการหลุดเชื่อมต่อเพื่อต่อใหม่โดยอัตโนมัติ
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Wi-Fi connection lost. Attempting reconnect...");
WiFi.disconnect();
WiFi.reconnect();
delay(5000);
}
delay(1000);
}
POST โดยใช้มาตรฐาน Bearer Token สำหรับการยืนยันตัวตน บน ESP32 เราใช้คลาส HTTPClient ร่วมกับ WiFiClientSecure เพื่อเข้ารหัสความปลอดภัย SSL/TLS
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* LINE_TOKEN = "YOUR_LINE_NOTIFY_TOKEN";
void sendLineAlert(String message) {
if (WiFi.status() == WL_CONNECTED) {
WiFiClientSecure client;
client.setInsecure(); // ละเว้นการตรวจสอบ Root CA ในการทดลอง
HTTPClient https;
if (https.begin(client, "https://notify-api.line.me/api/notify")) {
https.addHeader("Content-Type", "application/x-www-form-urlencoded");
https.addHeader("Authorization", String("Bearer ") + LINE_TOKEN);
String postData = "message=" + message;
int httpCode = https.POST(postData);
if (httpCode > 0) {
Serial.print("[LINE] Response HTTP Code: ");
Serial.println(httpCode);
} else {
Serial.print("[LINE] Error: ");
Serial.println(https.errorToString(httpCode).c_str());
}
https.end();
}
}
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi Connected!");
sendLineAlert("🔥 ระบบเตือนภัย IoT ปวส.: ตรวจพบอุณหภูมิห้องเซิร์ฟเวอร์สูงผิดปกติ 43.5 *C!");
}
void loop() {
delay(60000);
}
#include <WiFi.h>
#include <PubSubClient.h>
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* mqtt_server = "broker.hivemq.com";
const int mqtt_port = 1883;
const char* TOPIC_DATA = "krubas/iot/sensor/data";
const char* TOPIC_CONTROL = "krubas/iot/control/relay";
WiFiClient espClient;
PubSubClient client(espClient);
void callback(char* topic, byte* payload, unsigned int length) {
String msg = "";
for (int i = 0; i < length; i++) { msg += (char)payload[i]; }
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("]: ");
Serial.println(msg);
if (String(topic) == TOPIC_CONTROL) {
if (msg == "ON") {
digitalWrite(2, HIGH);
Serial.println("[MQTT ACTUATOR] Turned ON");
} else if (msg == "OFF") {
digitalWrite(2, LOW);
Serial.println("[MQTT ACTUATOR] Turned OFF");
}
}
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
String clientId = "ESP32Client-" + String(random(0xffff), HEX);
if (client.connect(clientId.c_str())) {
Serial.println("connected!");
client.subscribe(TOPIC_CONTROL);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
delay(5000);
}
}
}
void setup() {
pinMode(2, OUTPUT);
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) { reconnect(); }
client.loop();
static unsigned long lastMsg = 0;
if (millis() - lastMsg > 5000) {
lastMsg = millis();
float temp = 29.2;
String payload = "{\"temp\":" + String(temp) + ",\"status\":\"ONLINE\"}";
client.publish(TOPIC_DATA, payload.c_str());
Serial.println("Published to MQTT: " + payload);
}
}
ESPAsyncWebServer รองรับการเชื่อมต่อแบบมัลติคอนเนกชัน (Multi-connections) โดยไม่ทำให้ระบบสะดุด เหมาะสำหรับการส่งหน้าเว็บ HTML/CSS/JavaScript ให้แก่เบราว์เซอร์ และรับคำสั่งสลับการทำงานของพอร์ตแบบ Real-time โดยไม่ต้องรีเฟรชหน้าจอ
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const int RELAY_PIN = 4;
bool relayState = false;
AsyncWebServer server(80);
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ESP32 IoT Dashboard</title>
<style>
body { font-family: Arial; text-align: center; margin-top: 50px; background: #0f172a; color: #fff; }
.btn { display: inline-block; padding: 15px 30px; font-size: 20px; border-radius: 8px; cursor: pointer; text-decoration: none; font-weight: bold; }
.btn-on { background-color: #22c55e; color: white; }
.btn-off { background-color: #ef4444; color: white; }
</style>
</head>
<body>
<h2>ESP32 Web Server Relay Controller</h2>
<p>Status: %STATE%</p>
<a href="/toggle" class="btn %BTN_CLASS%">TOGGLE POWER</a>
</body>
</html>
)rawliteral";
String processor(const String& var){
if(var == "STATE"){ return relayState ? "ACTIVATED (ON)" : "DEACTIVATED (OFF)"; }
if(var == "BTN_CLASS"){ return relayState ? "btn-off" : "btn-on"; }
return String();
}
void setup() {
Serial.begin(115200);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nServer IP: " + WiFi.localIP().toString());
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
server.on("/toggle", HTTP_GET, [](AsyncWebServerRequest *request){
relayState = !relayState;
digitalWrite(RELAY_PIN, relayState ? HIGH : LOW);
request->redirect("/");
});
server.begin();
}
void loop() { }
การบูรณาการระบบกับคลาวด์ชั้นนำ (Blynk, NETPIE, ThingSpeak) และโครงงานพัฒนาระบบฟาร์มอัจฉริยะอัตโนมัติเต็มรูปแบบ
#define BLYNK_TEMPLATE_ID "TMPLxxxxxx"
#define BLYNK_TEMPLATE_NAME "Smart Farm"
#define BLYNK_AUTH_TOKEN "YOUR_BLYNK_TOKEN"
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
char ssid[] = "YOUR_WIFI_SSID";
char pass[] = "YOUR_WIFI_PASSWORD";
const int PUMP_PIN = 5;
BlynkTimer timer;
// รับค่าจากปุ่มสวิตช์บนแอป Blynk (Virtual Pin V1)
BLYNK_WRITE(V1) {
int value = param.asInt();
digitalWrite(PUMP_PIN, value == 1 ? HIGH : LOW);
Serial.println(value == 1 ? "[BLYNK] Pump ON" : "[BLYNK] Pump OFF");
}
// ฟังก์ชันส่งค่าเซนเซอร์ขึ้นคลาวด์ทุก 2 วินาที
void sendSensorData() {
float soilMoisture = 68.5; // ตัวอย่างค่าเซนเซอร์
Blynk.virtualWrite(V2, soilMoisture);
}
void setup() {
pinMode(PUMP_PIN, OUTPUT);
Serial.begin(115200);
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
timer.setInterval(2000L, sendSensorData);
}
void loop() {
Blynk.run();
timer.run();
}
#include <WiFi.h>
#include <PubSubClient.h>
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* mqtt_server = "broker.netpie.io";
const int mqtt_port = 1883;
const char* client_id = "YOUR_DEVICE_ID";
const char* token = "YOUR_DEVICE_TOKEN";
const char* secret = "YOUR_DEVICE_SECRET";
WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
client.setServer(mqtt_server, mqtt_port);
}
void loop() {
if (!client.connected()) {
while (!client.connected()) {
Serial.print("Connecting to NETPIE 2020...");
if (client.connect(client_id, token, secret)) {
Serial.println("connected!");
} else {
delay(3000);
}
}
}
client.loop();
// อัปเดตข้อมูลสถานะเข้าสู่ Shadow
static unsigned long lastTime = 0;
if (millis() - lastTime > 10000) {
lastTime = millis();
String payload = "{\"data\":{\"temp\":31.4,\"humidity\":72.0}}";
client.publish("@shadow/data/update", payload.c_str());
Serial.println("Sent telemetry to NETPIE Shadow");
}
}
#include <WiFi.h>
#include <HTTPClient.h>
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* thingspeak_api_key = "YOUR_WRITE_API_KEY";
const char* server = "http://api.thingspeak.com/update";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("WiFi Connected for ThingSpeak Logger");
}
void loop() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
float temp = 27.8;
float lightLux = 850;
String url = String(server) + "?api_key=" + thingspeak_api_key +
"&field1=" + String(temp) + "&field2=" + String(lightLux);
http.begin(url);
int httpResponseCode = http.GET();
if (httpResponseCode > 0) {
Serial.print("ThingSpeak Update HTTP Code: ");
Serial.println(httpResponseCode);
} else {
Serial.print("HTTP Error: ");
Serial.println(httpResponseCode);
}
http.end();
}
delay(20000); // ส่งข้อมูลทุก 20 วินาทีตามข้อกำหนด ThingSpeak
}
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const int RELAY_WATER_PUMP = 16;
const int RELAY_MIST_FAN = 17;
const int SOIL_SENSOR_PIN = 35;
void setup() {
Serial.begin(115200);
pinMode(RELAY_WATER_PUMP, OUTPUT);
pinMode(RELAY_MIST_FAN, OUTPUT);
digitalWrite(RELAY_WATER_PUMP, HIGH); // ปิดปั๊มน้ำ
digitalWrite(RELAY_MIST_FAN, HIGH); // ปิดพัดลมหมอก
WiFi.begin(ssid, password);
Serial.println("Smart Greenhouse System Starting...");
}
void loop() {
// อ่านค่าความชื้นในดินและแปลงเป็นเปอร์เซ็นต์
int soilRaw = analogRead(SOIL_SENSOR_PIN);
int soilPercent = map(soilRaw, 4095, 1500, 0, 100);
soilPercent = constrain(soilPercent, 0, 100);
Serial.print("Soil Moisture: ");
Serial.print(soilPercent);
Serial.println("%");
// ตรรกะควบคุมอัตโนมัติ (Automated Closed-loop Control)
if (soilPercent < 40) {
digitalWrite(RELAY_WATER_PUMP, LOW); // รดน้ำอัตโนมัติ
Serial.println("[AUTO ACTION] Soil dry: Water Pump ACTIVATED");
} else {
digitalWrite(RELAY_WATER_PUMP, HIGH);
}
delay(2000);
}