2015年3月9日 星期一

Raspberry Pi安裝MQTT之應用 -- Android訊息推播

Android 常見的推播方式有GCM(Google Cloud Messaging)、XMPP、HTTP輪循方式(Web Service)以及本文所談的MQTT協定。
這四種推播的平台比較下各有優缺點,例如
GCM是Google的服務其優點簡單、無須安裝部屬。缺點則是受Google限制(上限 4kb 的輕量資料)。
XMPP優點是協定成熟、強大、可擴展性強、主要應用於聊天系統中。缺點則是協定較複雜、四種方式比較起來由於基於XML所以流量較大,需要軟硬體部署。
Web Service則是定時透過HTTP服務獲取最新訊息。優點是實現簡單、可控性強,部署硬體成本較低。缺點則是無法做到即時性的廣播。
MQTT優點協議簡潔、小巧、可擴展性強、節省頻寬。缺點不夠成熟、實現較複雜、需要軟硬體部署。

另外,下圖是MQTT與其他比較知名的大型原廠推播系統的比較,參考一下!

MQTT並不是一個新的技術,早在1999年由IBM的Andy Stanford-Clark及 Arcom (現為Eurotech)的Arlen Nipper這位所一起創造MQTT這個協定。只是這一陣子物聯網(IoT)又被炒作的變成一種熱門技術前提下,MQTT是一種很適合應用在物聯網上的一項技術,因此本篇就在樹梅派上採用MQTT協定來做Android訊息推播的平台。

MQTT是一個 machine-to-machine (M2M) 的發佈(Publish)/訂閱(Subscribe)訊息的傳輸協定,簡單來說當發佈者將訊息送至Topic平台,而Topic會將這個訊息送到所註冊的訂閱者。
一般來說發佈者可以是一個Sensors也可以是一個推播訊息的入口。訂閱者可以是個伺服器上的應用服務也可以是個手機。
其關係如下圖所示:
MQTT設計構想是採開放、簡單、輕量、易於實現同時支援離線訊息及訊息保留的功能。適用於受限制的環境,例如小頻寬、不穩定的網路或是資源有限的嵌入設備。其協定的特點如下:
1.使用發佈(Publish)/訂閱(Subscribe)訊息模式,提供一對多的訊息發佈。
2.使用 TCP/IP 提供網路連接。
3.具有多重QOS訊息傳輸,有三種用於訊息傳遞的服務品質::
4.使用網路頻寬小(2 bytes at minimum),減少通訊協定交換量。
5.使用 Last Will 和 Testament (最後留言)特性,可通知訂閱者用戶端與 MQTT 伺服器的連線異常中斷。

詳細資料請參考MQTT V3.1 Protocol Specification 說明

由上述的關係圖中,我們明白發佈者與訂閱者的中間需要一個平台,而這個平台最簡單的方式就是採用MQTT Broker
常見的MQTT Broker大致有Apache Apollo、HiveMQ、Mosca、Mosquitto、RabbitMQ、RSMB、...其比較如下表所示:
本篇文章的MQTT Broker則是採用Mosquitto,Mosquitto是一個實現了MQTT3.1協議的開源(BSD許可證)代理服務器,由MQTT協議創始人之一的Andy Stanford-Clark開發,它為我們提供了輕量級數據交換的解決方案。其官網為:http://mosquitto.org/,至目前為止他的最新版本為1.4。
實作:
環境說明:
Raspberry Pi
EDIMAX 訊舟 EW-7822Uan 300M USB無線網路
SanDisk 16G microSDHC card

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

步驟:
安裝的方式大致上有兩種,一種是下載原始碼來進行編譯,這種方式可以用到最新版的軟體;另一種則是採用apt-get方式,這種方式比較簡單本文則採取這種方式來安裝。

1.安裝相關套件及含式庫:
sudo apt-get install libssl-dev libwrap0-dev libc-ares-dev uuid-dev

2.安裝Mosquitto
a.採用下載原始碼來進行編譯

wget http://mosquitto.org/files/source/mosquitto-1.4.tar.gz
tar zxvf mosquitto-1.4.tar.gz
cd mosquitto-1.4/
make all
sudo make install
sudo ldconfig

b.採用apt-get方式 (本文所採用方式)
wget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key
sudo apt-key add mosquitto-repo.gpg.key
rm mosquitto-repo.gpg.key

cd /etc/apt/sources.list.d/
sudo wget http://repo.mosquitto.org/debian/mosquitto-repo.list

視安裝的系統版本選擇下列其一:
sudo wget  http://repo.mosquitto.org/debian/mosquitto-jessie.list
sudo wget http://repo.mosquitto.org/debian/mosquitto-stretch.list
sudo wget http://repo.mosquitto.org/debian/mosquitto-wheezy.list

例如 Pi 裝的是 RASPBIAN JESSIE 那就執行 sudo wget http://repo.mosquitto.org/debian/mosquitto-jessie.list

sudo apt-get update

sudo apt-get install mosquitto mosquitto-clients

按照上述步驟即完成Mosquitto軟體安裝。接著驗證一下Mosquitto是否可以正確執行。
3.首先開啟兩個視窗,或者使用兩個ssh連線。

4.在第一個視窗中執行:(當作訂閱者角色)
mosquitto_sub -d -t hello/world
5.在另一個視窗執行:(當作發佈者角色)
mosquitto_pub -d -t hello/world -m "Hi, This test message."
6.然後此時回到第一個視窗你可以看到剛剛傳送的訊息。
7.此時,在第二個視窗中執行下列指令,可以看到Mosquitto的一些資訊這表示Mosquitto服務是正在執行中,由此我們可以知道Mosquitto的參數檔案是/etc/mosquitto/mosquitto.conf;所使用的網路埠號是1883。
ps -ef | grep mosq && netstat -tln | grep 1883
執行下列指令可以關閉Mosquitto服務:
sudo /etc/init.d/mosquitto stop

執行下列指令可以開啟Mosquitto服務:
sudo /etc/init.d/mosquitto start

查看MQTT訂閱者執行情況:
mosquitto_sub -v -t \$SYS/#

安裝至此,已經完成安裝項目。
接著,已經安裝好Mosquitto這個MQTT Broker,接下來介紹一下MQTT的工具。

WMQTT Utility (ia92)
ia92是IBM為了它們家的WebSphere所開發的一套工具,可以到官網下載ia92.zip
下載後解壓縮,可以在J2SE目錄下找到一個wmqttSample.jar檔案,直接用java執行即可。
java -jar wmqttSample.jar

由上圖執行畫面所示,畫面分為三個區塊:
最上面是連線區塊
中間是訂閱者(Subscribe)區塊
下面是發佈者(Publish)區塊

接著我們登入剛剛所安裝好的系統驗證一下。
首先用WMQTT Utility登入到系統。此時當作一個發佈者
接著開啟一個ssh連線到RPi執行下列指令當作一個訂閱者
mosquitto_sub -d -t hello/world

此時再回到WMQTT Utility下面的區塊中在Topic項目輸入 hello/world ;然後再下面的框框中輸入測試訊息接著按下Publish按鈕,此時已透過WMQTT Utility將訊息法送到 hello/world 這個 Topic中了。

接著,回到剛剛ssh的訂閱者視窗,我們可以看到剛剛所送的訊息一字不漏的接收到了。

另外這個工具也可以當作訂閱者礙於篇幅這部分就不詳細說明有興趣的人在測試一下。不過這個工具不支援中文字訊息的發送

至此,完成了訊息的發佈與訂閱動作,接下來我們來實作在Android下的推播。
Android推播系統我們是利用網路上別人寫好的資源: How to Implement Push Notifications for Android

這個網站中提供了發佈工具(PHP程式)與訂閱工具(Android程式),這兩個程式可以到GitHub下載:
tokudu/AndroidPushNotificationsDemo  https://github.com/tokudu/AndroidPushNotificationsDemo
tokudu/PhpMQTTClient https://github.com/tokudu/PhpMQTTClient

Android程式的部分在eclipse上用匯入的方式就可以執行了。只要確認wmqtt.jar的 Java Build Path,以及更改 PushService.java 中第 38 行的 MQTT_HOST ,把這個IP改成RPi的IP即可。

接著安裝PhpMQTTClient,由於這是一個PHP的程式,因此我們必須在RPi上執行下列指令來安裝Apache+PHP :
sudo apt-get install apache2 php5

此時,我們可以在瀏覽器上輸入 http://RPi IP 即可看到下圖畫面:

然後我們將GitHub上的PhpMQTTClient下載後上傳到RPi上面。
接著將在RPi上解壓縮所上傳的檔案:
unzip PhpMQTTClient-master.zip
進入解壓所後的目錄:
cd PhpMQTTClient-master/
建立一個 etc 目錄:
mkdir etc
建立config.php檔案
vi etc/config.php
其內容如下:
define('MQTT_SERVER_HOST', '192.168.0.135');
define('MQTT_SERVER_POST', '1883');
?>

其中第2行定義了MQTT Host,這裡的IP請改成RPi的IP第3行不變,然後存檔。
此時用pwd指令確認還在PhpMQTTClient-master目錄下,接著在apache上建立一個名為mqtt的目錄:
sudo mkdir /var/www/mqtt
sudo mv ~/PhpMQTTClient-master/* /var/www/mqtt  (將PhpMQTTClient-master目錄下的所有檔案搬移到/var/www/mqtt)
此時用 ls /var/www/mqtt/ 確認檔案已經搬移過去。
接著用瀏覽器開啟剛才所安裝的PHP程式,此時你會見到如下圖所示的畫面:

此時,我們執行手機上的Push Demo程式,我們可以先將Start Push service按鈕按下,此時手機就會開始監聽伺服器是否有推播訊息。

接著我們會看到Your Device Target下的一組ID號碼(每支手機會不同),把這個號碼輸入到剛剛PHP網站中的上面那一格。
然後在下方輸入中英文測試訊息,接著按下Send Push Message。

此時,你會在手機上的通知訊息欄上看到所接收到剛才所輸入的訊息。

(註:上述手機的Topic是  tokudu/34b2b406165a8b0d )
至此,完成了Android推播的功能。不過再利用這個程式進行推播功能時務必先確認你的手機是在網路上,如果手機沒有在網路上的話在PHP上所輸入的資訊是會遺失不會重送。
當然,如果要確保訊息可以完整到手機的話就必須更改上述的程式了。


後記:
1. 如果你設計的推播系統除了手機當作發佈者外,也想要讓Arduino或其他MCU的Sensor也是發佈者,那麼MQTT是個不錯選擇。

2. Mosquitto官網提供Windows、Linux以及qnx系統的版本,所以除了RPi上可以執行也可以在Linux/Windows上執行,不過本篇主題是在樹梅派上所以其他平台我並沒有測試過。

3. mosquitto.conf (在/etc/mosquitto目錄下) 中的說明,本文所使用的是預設值沒有更改,如果需要更改的話相關參數請參考官網說明

4. Mosquitto也可以界接到其他的MQTT平台,詳見Displaying MQTT messages in a browser in real time說明

5. MQTT另一個常見的工具是mqtt-spy,可以到官方網站下載
在官方網站中的下方找到 Downloads ,並下載 0.1.8 - http://tinyurl.com/mqtt-spy-download/mqtt-spy-0.1.8-jar-with-dependencies.jar 這個檔案。
然後你要確認你的Java版本是1.8版的,因為這個工具只能用這個版本,然後執行下列指令就可以執行程式。
java -jar mqtt-spy-0.1.8-jar-with-dependencies.jar
這部分我還沒有進行測試過,詳細部分請參考官網的GettingStarted說明

6. 或許會由疑問,用樹梅派來做MQTT到底可以撐多少個用戶?
這個答案我概略測試過我的Raspberry Pi 2 Model B (二代,四核心)大致上能承受約3186個,實際上大約在1800~2000個用戶系統就滿載了,僅供參考。
所以,現今隨便的一台PC隨隨便便應該可以應付20萬個用戶吧!畢竟樹梅派是Linux嵌入式的教學工具能應付千百個用戶已經不錯了,如果要應付幾十萬或幾百萬用戶那還是買伺服器來做比較穩定。

參考:
Installing Mosquitto on a Raspberry Pi
http://jpmens.net/2013/09/01/installing-mosquitto-on-a-raspberry-pi/

Installing mosquitto on Raspberry Pi
http://www.xappsoftware.com/wordpress/2014/10/27/installing-mosquitto-on-raspberry-pi/

Running Mosquitto (MQTT broker) on Raspberry Pi
http://www.reddit.com/r/raspberry_pi/comments/2tbsj8/running_mosquitto_mqtt_broker_on_raspberry_pi/

Displaying MQTT messages in a browser in real time
http://blog.jonharrington.org/iot/2013/11/02/displaying-mqtt-messages-in-a-browser-in-real-time/

How to Implement Push Notifications for Android
http://tokudu.com/post/50024574938/how-to-implement-push-notifications-for-android

MQTT(一)簡介
http://blog.maxkit.com.tw/2014/01/mqtt.html
http://blog.maxkit.com.tw/search/label/MQTT

MQTT V3.1 Protocol Specification
http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html
http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/MQTT_V3.1_Protocol_Specific.pdf

Building Smarter Planet Solutions with MQTT and IBM WebSphere MQ Telemetry
http://www.redbooks.ibm.com/redbooks/pdfs/sg248054.pdf

Download ia92.zip
http://www-01.ibm.com/support/docview.wss?uid=swg24006006

Download mqtt-spy
https://code.google.com/p/mqtt-spy/

==============延伸閱讀=====================
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

10. Raspberry Pi安裝MQTT之IoT應用 -- Arduino示範
http://cheng-min-i-taiwan.blogspot.tw/2015/03/raspberry-pimqttiot-android.html#more

12 則留言:

  1. 請問你的Rpi是怎麼測試這麼多用戶的呢?謝謝

    回覆刪除
  2. 寫個script,用netstat去看,參考用!未必準確~
    #!/bin/bash
    c=1
    while [ $c -le 20000 ]
    do
    mosquitto_sub -d -t hello/world -k 900 &
    (( c++ ))
    done

    回覆刪除
  3. 作者已經移除這則留言。

    回覆刪除
  4. 哈囉 能和你 加個LINE嘛!? 想學習 MQTT的 相關事情!! 謝謝囉!

    回覆刪除
  5. 哈囉 能跟你 交換 LINE嘛! 想學習 MQTT 相關事件!

    回覆刪除
  6. 你好請問你知道如何建造mosquitto bridges嗎
    可以教一下我嗎

    回覆刪除
  7. 你知道如何mosquitto bridges嗎
    可以教我一下嗎

    回覆刪除
  8. 請問我用ubuntu 32 64bit,都遇到無法持續連線,雖然有設定自動連接,可是還是會有斷線的問題,發送訊息的是一塊有wifi的板子,外網會有斷線的問題,但是內網卻是很穩定,這種情形有可以調整的地方嗎? 謝謝

    回覆刪除
  9. 請問有沒有工具可以看到 MQTT Server 上有哪些 Topics?以及各 Topics 裡有沒有 queue 的訊息還沒送出。

    回覆刪除
    回覆
    1. 要改用 RabbitMQ 才有你所講的這個功能, Mosquitto 屬於陽春型的只能下指令。
      http://www.rabbitmq.com/

      刪除
  10. 您好,再請問一下,
    如果 Subscriber 斷線,然後publisher發送三個訊息給 Mosquitto Server,
    此時把 Server 重啟,然後 Subscriber 重連,我希望 Subscriber 可以收到斷線後 publisher 送出的資訊。
    這樣的話,該如何設定呢?
    感謝~

    回覆刪除