MQTT State Machine — 橋เชื่อมระหว่างอุปกรณ์กับโลก IoT
ถ้า WiFi คือถนนที่พาข้อมูลวิ่งได้ MQTT ก็คือระบบไปรษณีย์บนถนนนั้นครับ — มีที่อยู่ มีผู้ส่ง มีผู้รับ และมีกฎชัดเจนว่าใครส่งอะไรให้ใคร
โค้ด handleMQTT() ข้างต้นเป็นหัวใจของการสื่อสารในระบบ IoT ที่สมบูรณ์ครับ มาทำความเข้าใจทีละส่วนกันครับ

MQTT คืออะไร?
MQTT ย่อมาจาก Message Queuing Telemetry Transport เป็น protocol ที่ออกแบบมาเพื่อ IoT โดยเฉพาะ มีจุดเด่นคือ:

เบามาก — ใช้ bandwidth น้อยมาก เหมาะกับบอร์ดที่มี RAM จำกัดอย่าง ESP32
Publish/Subscribe — อุปกรณ์ไม่คุยกันตรงๆ แต่ส่งข้อความผ่าน broker กลาง
QoS — กำหนดระดับความมั่นใจในการส่งข้อมูลได้ถึง 3 ระดับ
Retain & Will — ข้อความสุดท้ายก่อนตายสามารถบอกระบบได้ว่าอุปกรณ์ออฟไลน์


วิเคราะห์โค้ดทีละส่วน
ตรวจสอบก่อนเสมอ
cppif (mqtt.connected()) {
setLedMode(LED_ON);
return;
}
ทุกครั้งที่ loop() เรียกฟังก์ชันนี้ จะเช็คก่อนว่ายังเชื่อมต่ออยู่ไหม ถ้าใช่ก็จบแค่นั้น ไม่เปลือง CPU ครับ
Non-blocking Retry
cppif (millis() - lastMqttRetryMs < MQTT_RECONNECT_MS) return;
lastMqttRetryMs = millis();
ไม่มี delay() ไม่มีการค้าง ถ้ายังไม่ถึงเวลา retry ก็ออกจากฟังก์ชันทันที บอร์ดทำงานอื่นต่อได้เลยครับ
Client ID ที่ไม่ซ้ำกันเลย
cppString cid = "kitdee_" + WiFi.macAddress();
cid.replace(":", "");
ใช้ MAC address ของบอร์ดสร้าง Client ID ทำให้มั่นใจได้ว่าถ้ามีบอร์ด 100 ตัวในระบบ แต่ละตัวจะมี ID ไม่ซ้ำกันเลยครับ
Last Will Testament — พินัยกรรมของอุปกรณ์
cppbool ok = mqtt.connect(
cid.c_str(),
MQTT_USER, MQTT_PASS,
topicStatus.c_str(), 1, true, "offline"
);
ส่วนที่น่าสนใจที่สุดคือ "offline" ตรงท้ายครับ นี่คือ Last Will — ข้อความที่ broker จะส่งอัตโนมัติให้ทุกคนที่ subscribe topic นี้อยู่ ถ้าบอร์ดหลุดการเชื่อมต่อโดยไม่ได้แจ้งลา ทำให้ระบบ monitoring รู้ทันทีว่าอุปกรณ์ออฟไลน์โดยไม่ต้องรอ timeout ครับ
เมื่อเชื่อมต่อสำเร็จ
cppif (ok) {
mqtt.subscribe(topicCmd.c_str(), 1);
mqtt.publish(topicStatus.c_str(), "online", true);
setLedMode(LED_ON);
readAndSendSensor();
}
```
ทำ 4 อย่างทันทีครับ — subscribe รับคำสั่ง, ประกาศ online, เปิด LED, และส่งค่าเซ็นเซอร์ครั้งแรกเลย ไม่รอครับ

---

## Topic คืออะไร?

ใน MQTT ข้อมูลถูกจัดระเบียบด้วย **Topic** ซึ่งเหมือน path ของไฟล์ครับ เช่น:
```
kitdee/device/abc123/status → สถานะออนไลน์/ออฟไลน์
kitdee/device/abc123/sensor → ค่าเซ็นเซอร์
kitdee/device/abc123/cmd → รับคำสั่งจาก server
dashboard หรือ server จะ subscribe topic เหล่านี้ไว้ พอบอร์ดส่งข้อมูลมา broker ก็กระจายให้ทุกคนที่รอรับอยู่ทันทีครับ

ภาพรวมระบบ IoT ที่สมบูรณ์
ตอนนี้เราเห็นภาพชัดขึ้นแล้วครับว่าระบบ IoT ที่แข็งแกร่งต้องประกอบด้วยอะไรบ้าง:
ชิ้นส่วนหน้าที่WiFi State Machineเชื่อมต่อเครือข่ายและ retry อัตโนมัติMQTT Handlerส่งและรับข้อมูลผ่าน brokerSensor Managerอ่านค่าเซ็นเซอร์ตามจังหวะที่กำหนดLED Indicatorแสดงสถานะให้เห็นด้วยตาเปล่าWatchdog Timerรีสตาร์ทอัตโนมัติเมื่อระบบค้างOTA Updateอัปเดต firmware ผ่าน WiFi
ทุกชิ้นส่วนทำงานใน loop() เดียวกัน ไม่มีใคร block ใคร — นั่นคือปรัชญาของ Non-blocking IoT firmware ครับ

ตัวอย่างโปรแกรมทั้งหมด
// ════════════════════════════════════════════════════
// HANDLE MQTT — Non-blocking
// ════════════════════════════════════════════════════
void handleMQTT() {
if (mqtt.connected()) {
setLedMode(LED_ON);
return;
}

if (millis() - lastMqttRetryMs < MQTT_RECONNECT_MS) return;
lastMqttRetryMs = millis();

setLedMode(LED_BLINK);
Serial.printf("🔌 MQTT %s:%d ...", MQTT_HOST, MQTT_PORT);

String cid = "kitdee_" + WiFi.macAddress();
cid.replace(":", "");

bool ok = mqtt.connect(
cid.c_str(),
MQTT_USER, MQTT_PASS,
topicStatus.c_str(), 1, true, "offline"
);

if (ok) {
Serial.println(" ✅");
mqtt.subscribe(topicCmd.c_str(), 1);
mqtt.publish(topicStatus.c_str(), "online", true);
setLedMode(LED_ON);
readAndSendSensor();
} else {
Serial.printf(" ❌ rc=%d — รอ %ds\n",
mqtt.state(), MQTT_RECONNECT_MS / 1000);
}
}
สรุป
handleMQTT() ไม่ใช่แค่โค้ดเชื่อมต่อธรรมดา แต่มันรวมแนวคิดสำคัญหลายอย่างไว้ในฟังก์ชันเดียว ทั้ง non-blocking retry, unique client ID, last will testament และ retain message ถ้าเข้าใจโค้ดนี้ได้ครับ ก็เข้าใจหลักการสำคัญของ IoT communication ไปได้มากกว่าครึ่งแล้วครับ
บทความถัดไปเราจะมาดู Sensor Manager — วิธีอ่านค่าเซ็นเซอร์อย่างถูกต้องโดยไม่ให้กระทบการทำงานของระบบครับ