วันอาทิตย์ที่ 20 กันยายน พ.ศ. 2558

Node-RED : ใช้งาน MQTT ด้วย Arduino

 

บทความที่แล้วกล่าวถึงการสมัครใช้งาน MQTT Broker กับ CloudMQTT ตอนนี้หลายคนคงมี user และ password แล้วก็ใช้งานกันบ้างแล้ว

MQTT จะกล่าวถึง Publish เป็นการฝากข้อมูลไว้ด้วยการตั้งชื่อ topic และ Subscribe คือการสมัครเพื่อรับข้อมูลกับ broker โดยที่ broker จะจัดส่ง topic ที่สมัครไว้ ที่มีข้อมูลใหม่ๆ ให้กับผู้ที่ได้ทำการสมัครรับข้อมูล topic นั้นๆไว้ ด้านผู้ที่สมัครต้องเตรียมการในการรับข้อมูลที่ broker จัดส่งให้ โดยเรียกการเตรียมการว่าเป็นการรอรับ callback การทำงานจะใช้หลักการของ Event driven

สิ่งที่เกริ่นมาจะเป็นหลักการในการเขียนโปรแกรมเพื่อรองรับการทำงาน แต่โชคดีจริงๆที่มีคนที่ไม่นิ่งดูดาย ได้จัดทำไลบรารี่สำหรับการนี้มาให้เราใช้เรียบร้อยแล้วในชื่อ Arduino Client for MQTT

บทความนี้จะนำสิ่งที่ต้องปรับแก้ในตัวอย่างที่ให้มาในไลบรารี่ เพื่อให้ทำงานได้ถูกต้อง

ก่อนอื่นเราต้องนำเอาไลบรารี่มาวางในโฟลเดอร์ libraries ของ Arduino 1.6.5r2 เสียก่อน

https://github.com/knolleary/pubsubclient

เข้าไปรับไฟล์ zip มาติดตั้งเสียให้เรียบร้อย

image

ขอนำเอาหน้าตาคนเขียนไลบรารี่มาให้ดูกัน งานนี้ไม่ได้ขออนุญาตโดยตรงกับเจ้าของผลงาน เพราะอยู่ในเงื่อนไขของ MIT License. อยู่แล้ว สามารถนำผลงานไปเผยแพร่ได้

วางไลบรารี่เรียบร้อย ดำเนินการเปิด Arduino 1.6.2r5 จากนั้นเรียกตัวอย่างมาทดลองกันเลย ให้เลือก mqtt_esp8266 ซึ่งอยู่ใน PubSubClient

เริ่มการตั้งค่ากันก่อน

const char* ssid = "........";
const char* password = "........";
const char* mqtt_server = "broker.mqtt-dashboard.com";

ssid กับ password คงคุ้นกันอยู่แล้ว ส่วน mqtt_server ก็นำมาจากที่เราสมัครไว้กับ CloudMQTT ตัวอย่างของผมคือ m11.cloudmqtt.com ย้อนไปอ่านในบล๊อกที่แล้วครับ

void setup() {
  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

ตัวเลข 1883 เป็นหมายเลข port ดูจากที่สมัครไว้ ตัวอย่างที่ผมได้รับจาก CloudMQTT เป็น 15749

สำหรับ BUILTIN_LED เป็น pin ของ ESP8266 โดยถูกกำหนดค่าไว้ที่ 16 ที่ pin ของ ESP8266 ให้ต่อ LED ไว้ดวงหนึ่ง เพื่อทดสอบการรับ callback จาก broker

ส่วนบรรทัดสุดท้ายจะบอกตำแหน่งรูทีนที่จะให้ทำงานเมื่อได้รับ callback จาก broker ในที่นี้กำหนดให้ไปทำที่ รูทีน callback ตามที่แสดงด้านล่าง

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  // Switch on the LED if an 1 was received as first character
  if ((char)payload[0] == '1') {
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is acive low on the ESP-01)
  } else {
    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
  }

}
รูทีน callback จะมีตัวแปร topic, payload และ length มารอรับข้อมูลที่ broker ส่งมา ในรูทีนจะแสดง topic ที่รับมา โดยที่ข้อมูลหรือ message จะอยู่ใน payload โดยนำมาแสดงบน serial monitor

อีกส่วนคือการนำ message ที่ส่งมา นำมาเปิด ปิด LED โดยจะดูว่าตัวอักษรตัวแรกเป็น 0 ก็จะให้ LED ติด และถ้าเป็น 1 ก็จะดับหลอด LED

อีกส่วนที่สำคัญคือ รูทีน reconnect() ส่วนที่เป็นสีแดง ต้องทำการแก้ไข เนื่องจากจำเป็นต้องระบุ user และ password ให้กับ CloudMQTT

if(client.connect(“ESP8266Client”,”user”,”password”)) {

user และ password กำหนดให้โดย CloudMQTT เช่นกัน

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
   if (client.connect("ESP8266Client")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "hello world");
      // ... and resubscribe
      client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

สำหรับการ publish ได้ตั้งชื่อ topic ว่า outTopic และส่งค่า hello world ออกไป

client.publish(“outTopic”,”hello world”);

ส่วนการ subscribe จะรอรับ callback จาก topic ชื่อ inTopic

client.subscribe(“inTopic”);

โค๊ดส่วนอื่นๆก็เป็นการเตรียมเรื่อง WiFi และการคงการเชื่อมต่อให้ได้ตลอดเวลา

ส่วนการทำงานวนลูป จะทำการ publish topic ชื่อ outTopic ออกไปเป็นจังหวะห่างกันครั้งละประมาณ 2 วินาที

ทำการคอมไพล์และอัพโหลด ถ้าทุกสิ่งทำงานจะเห็นข้อมูลใน Serial monitor ลักษณะนี้ ต่อจากการเชื่อมต่อกับ WiFi โดยตัวเลขต่อท้าย hello world จะเพิ่มขึ้นเรื่อยๆ

Attempting MQTT connection...connected
Publish message: hello world #1
Publish message: hello world #2
Publish message: hello world #3
Publish message: hello world #4
Publish message: hello world #5
Publish message: hello world #6

การทดสอบการทำงาน

ให้เปิด Websocket UI ของ CloudMQTT (ดูวิธีในบล๊อกล่าสุด)

image

ทันทีที่เปิดก็จะเห็น Received message ตามภาพ ซึ่งก็คือการ publish โดย ESP8266 ด้วย topic outTopic

ทดลอง Send message (เป็นการ publish topic ชื่อ inTopic) ป้อน message เป็นตัวอักษรหรือข้อความก็ได้ สังเกตุผลที่ Serial monitor

ได้ทดลองส่งคำว่า Hi ออกไป ที่ Serial monitor ก็แสดงคำดังกล่าวทันที

Publish message: hello world #1281
Publish message: hello world #1282
Publish message: hello world #1283
Publish message: hello world #1284
Message arrived [inTopic] Hi

ทดลองส่ง message 0 หรือ 1 ซึ่งจะเห็น LED ติดและดับ ตามลำดับ

จะเห็นว่าการทำ publish และ subscribe เป็นแบบตรงไปตรงมา ไม่มีความยุ่งยาก ตัวอย่างที่ได้เห็นน่าจะทำให้เข้าใจการทำงานของ MQTT Broker ได้ชัดเจนยิ่งขึ้น

ผู้อ่านอาจประยุกต์ให้ publish ข้อมูลอุณหภูมิ และ subscribe เพื่อรับ callback มาเปิด ปิด หลอดไฟ หรือ subscribe ค่า analog มาทำการหรี่ไฟ

ผมแนะนำให้นำผลที่ได้จากบทความไปทดลองเขียน flow ใน NodeRED เพื่อขยายผลการประยุกต์การใช้งาน

ในส่วนของการทดสอบ MQTT มี app ใน Playstore ชื่อ MyMQTT สามารถใช้ทดสอบการทำงานแทน Websocket ของ CloudMQTT ได้เป็นอย่างดี ลองโหลดมาทดลองใช้ดูครับ

2 ความคิดเห็น: