2015年3月12日 星期四

Raspberry Pi安裝MQTT之IoT應用 -- Arduino示範


Machine-to-Machine (M2M) 協定目前常見的包括有 CoAP、XMPP、RESTful HTTP及MQTT 。
● CoAP (Constrained Application Protocol)受限應用協定,是採用UDP方式傳送用在受限制的資源上的一個類似HTML觀念的應用層協定。其協定最小資料為4 byte header
也就是說當你下一個類似coap://example.com:5683/~sensors./temp1.xml這樣的CoAP URI你就可以得到該感測器的資訊。
● XMPP (Extensible Messaging and Presence Protocol )大家應該就比較熟悉了,這是一個採用TCP連接並且可以透過XML進行雙向溝通的協定。經常用在即時通訊之類的軟體上。
● RESTful 符合REST(Representational State Transfer)原則的系統統稱為RESTful,REST同樣架構在HTTP over TCP上的一個協定,比較適合在雲端運算之類的環境。
● MQTT前一篇文章已經介紹過了這裡就不重複說明,下圖是Cisco原廠所做的比較表:

上一篇的MQTT推播訊息到Android文章後,接著本篇文章來驗證看看是不是真的可以從Arduino上來進行訊息的推播。

實作:
環境說明:
Arduino UNO
Arduino Ethernet Shield 

Raspberry Pi
EDIMAX 訊舟 EW-7822Uan 300M USB無線網路
SanDisk 16G microSDHC card

作業系統:
RASPBIAN (NOOBS 1.4.0 2015-02-18 )
mosquitto 1.4

開發環境:
Win 8.1 X64專業版
Arduino IDE 1.6.1

事前準備:
1. 礙於篇幅,本文主題並不是Arduino的基礎教學,如果不清楚Arduino基礎操作者,請至網路搜尋一下相關入門教學。
2. 使用Ethernet Shield 或者是 WiFi Shield 皆可,只要確認Arduino能夠連上網路就行,由於WiFi Shield太貴了加上沒有Sponsors所以本文採用Ethernet Shield。詳細網路連線部分同樣屬於入門基礎,本文不會有太多說明。
3. 本文使用的Arduino程式碼是透過別人所寫好的函式庫(library)及範例,相關函式庫安裝同樣屬於入門基礎,本文不會有太多說明。
4. 當執行程式出問題時,請先用Ping指令確認Arduino、樹梅派、手機是否有相互連線以及其相關參數是否正確(尤其是Topic要確認正確)。

步驟:
1. 下載Arduino函式庫 MQTT Client Library  
函式庫的官網:http://knolleary.net/arduino-client-for-mqtt/
目前為止最新版本為 1.9.1
我們要下載的檔案選擇 zip 其下載後的檔名為 pubsubclient-1.9.1.zip

2. 將 pubsubclient-1.9.1.zip 解壓縮後,把 PubSubClient 目錄拷貝到 Arduino IDE 的 libraries 目錄下。

3. 開啟Arduino IDE,接著用滑鼠點選上方的檔案-->範例-->PubSubClient--> mqtt_basic 此時會出現程式碼。

4. 接著我們只要改程式碼第15、16兩行的IP,改成樹梅派的IP及與樹梅派相同網段的IP,然後把程式燒錄至Arduino。
如果燒寫過程中出現錯誤,請先拔掉Ethernet Shield後再進行燒寫即可。
這裡說明一下程式碼中
第23行 把Arduino定義為發佈者(Publish)
第29行 其動作就是把"hello world"這串字傳送到名為outTopic的Topic。
第30行 把Arduino監聽inTopic的Topic訊息。

5. 此時連線到RPi上執行 mosquitto_sub -d -t outTopic
然後按下Arduino的Reset鍵,你將會看到下列訊息
Client mosqsub/3461-raspberryp received PUBLISH (d0, q0, r0, m0, 'outTopic', ... (11 bytes))
hello world
至此,我們確認Arduino已經將hello world傳送給Subscribe了。

6. 此時,我們再將Arduino的程式第29行的outTopic,改成上一篇所講的手機Topic (我測試手機的Topic為tokudu/34b2b406165a8b0d,請參考上一篇),這時候你就可以把Arduino上的"hello world"這串字傳送到你的手機上了。
7. 接著我們將Arduino的程式改成下面內容,然後燒錄到Arduino上。
/*
 Basic MQTT example

  - connects to an MQTT server
  - publishes "hello world" to the topic "outTopic"
  - subscribes to the topic "inTopic"
*/

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>

// Update these with values suitable for your network.
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
byte server[] = { 192, 168, 0, 135 };  //MQTT服務IP位址
byte ip[]     = { 192, 168, 0, 10 };   // Arduino 設備IP位址

EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);

char message_buff[100];
void setup()
{
  Ethernet.begin(mac, ip);
  if (client.connect("arduinoClient")) {
    client.publish("outTopic","hello world");
    client.subscribe("inTopic");
  Serial.begin(9600);
  Serial.println("Running......");
  }
}

void loop()
{
   // MQTT client loop processing
  client.loop();
}

void callback(char* topic, byte* payload, unsigned int length) {

  int i = 0;
  Serial.println("Message arrived:  topic: " + String(topic));
  Serial.println("Length: " + String(length,DEC));

  // create character buffer with ending null terminator (string)
  for (i = 0; i < length; i++) {
    message_buff[i] = payload[i];
  }
  message_buff[i] = '\0';
  String msgString = String(message_buff);
  Serial.println("Payload: " + msgString);
}

上述程式,我們只在callback加入了顯示接收訊息。

8. 此時,在RPi上執行 mosquitto_pub -d -t inTopic -m "on"

你將會在Arduino IDE中的序列埠監控視窗看到下面的訊息。

由上面的資訊,你可以確認由發佈者發布了一個"on"的字串到inTopic的Topic,此時Android會收到"on"這個字串,由此,我們只要在Arduino程式中加一個字串的判斷就可以控制GPIO輕鬆達到遠端開關的功能。

至此,我們即透過Arduino完成了一個簡單的MQTT之IoT應用。
最後,Raspberry Pi安裝MQTT之推播應用,我就用這兩篇文章來說明,日後還有看到其他應用在寫文章進行補充說明。

後記:
1. MQTT協定的訊息不像XML一樣,它沒有訊息標識,所以不容易理解;另外必須熟悉其訊息格式才能通訊。
但一般MCU在運算部分能力並不是很好,如果接收到的是XML訊息還要解析將會造成CPU的負擔,這時候MQTT的協定就有些優勢了。

2. 本文所提供的方式並非標準的IoT通用的通訊框架,如果考慮到未來IoT的相容性,建議參考「開放互連聯盟」(The Open Interconnect Consortium, OIC)標準組織所訂定的IoTivity
不過值得注意的是由於國際上IoT的聯盟太多了,將來誰是主流還未勝負。所以IoTivity僅建議參考是需要觀察及審慎評估的,待時機成熟再擇一標準。

3. 這兩天寒流來了先不要管IoT通用的通訊框架了,下圖的結果是我把DHT11所收到的值,透過Arduino定時推播到我的手機上的結果,這樣就簡單地完成了一個行動氣象台了。


參考:
1.Beyond MQTT: A Cisco View on IoT Protocols
http://blogs.cisco.com/ioe/beyond-mqtt-a-cisco-view-on-iot-protocols

2.Arduino Client for MQTT
http://knolleary.net/arduino-client-for-mqtt/
https://github.com/knolleary/pubsubclient

3.Constrained Application Protocol(CoAP)
http://en.wikipedia.org/wiki/Constrained_Application_Protocol

4.Performance Evaluation of MQTT and CoAP via a Common Middleware
http://www.alvinvalera.net/wp-content/uploads/2014/10/issnip2014.pdf

5.什麼是REST跟RESTful?
https://ihower.tw/blog/archives/1542

6.IoTivity
https://www.iotivity.org/

7.台灣物聯網聯盟TIOTA
http://www.tiota.org.tw/
http://goo.gl/Mu66vS

==============延伸閱讀=====================
1. Raspberry Pi 第一次接觸
http://cheng-min-i-taiwan.blogspot.tw/2013/02/raspberry-pi.html

2.Raspberry Pi 網路設定
http://cheng-min-i-taiwan.blogspot.tw/2013/02/raspberry-pi_23.html

3.Raspberry Pi 應用之Windows檔案伺服器
http://cheng-min-i-taiwan.blogspot.tw/2013/02/raspberry-pi-windows.html

4.Raspberry Pi 應用之DLNA影音伺服器
http://cheng-min-i-taiwan.blogspot.tw/2013/02/raspberry-pi-dlna.html

5.Raspberry Pi 硬體控制-- Python 語言篇
http://cheng-min-i-taiwan.blogspot.tw/2013/04/raspberry-pi-python.html

6.Raspberry Pi 硬體控制-- C 語言篇
http://cheng-min-i-taiwan.blogspot.tw/2013/04/raspberry-pi-c.html

7.Raspberry Pi 2 Model B 使用心得
http://www.cheng-min-i-taiwan.blogspot.tw/2015/02/raspberry-pi-2-model-b.html

8.Raspberry Pi 藍牙4.0應用之iBeacon 發射器
http://www.cheng-min-i-taiwan.blogspot.tw/2015/03/raspberry-pi-40ibeacon.html

9.Raspberry Pi安裝MQTT之應用 -- Android訊息推播
http://www.cheng-min-i-taiwan.blogspot.tw/2015/03/raspberry-pimqtt-android.html

3 則留言:

  1. 不好意思請問一下,是用任何wifi板的都可嗎?只要有網路功能即可。

    回覆刪除
    回覆
    1. 只要arduino可以ping得到Raspberry Pi就可

      刪除
  2. 請問一下我是Arduino uno + Esp8266,是去libraries>mqtt_esp8266燒錄到Arduino uno就可以了嗎 ?

    回覆刪除