MQTT訊息傳遞

在物聯網的應用情境中,如何把感應到的感測器數值傳回後台儲存起來,一直是一個很重要的議題,事實上也有許多的方法可以完成這樣的目的,除了直接把資料儲存在開發板的文字檔案之外,也可以利用藍牙或WiFi的方式傳遞到網站或資料庫上。傳遞資料使用的通訊協定中,MQTT一直是一個非常受歡迎的方式。

MQTT是一個使用Publish/Subscribe的方式傳遞訊息的機制,只要有一台運行中的MQTT Server,任何一個可以連線到此伺服器的節點,都可以指定要發佈(Publish)或是訂閱(Subscribe)某一個主題(Topic),不同的節點即可在不需要知道對方節點的情況下,送出資料或是取得指定的資料。

以下是維基百科對於MQTT的說明:

https://zh.wikipedia.org/wiki/MQTT

對於我們來說,簡單地講,我們只需要找到(或自己安裝)一台MQTT伺服器,其它任何的感測或處理節點,只要能夠透過網路連接到此伺服器,它就會幫我們轉送資料到感興趣的節點手中。免費的MQTT伺服器最受歡迎的是Mosquitto:

https://mosquitto.org/

幾乎任何作業系統均可支援Mosquitto的安裝,但最常見的還是被安裝在樹莓派上。各個作業系統安裝的方式不儘相同,下面這個頁面有詳細的說明:

https://mosquitto.org/download/

以Ubuntu Linux作業系統為例,需執行以下的幾個指令進行安裝:

sudo apt-add-repository ppa:mosquitto-dev/mosquitto-ppa
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install mosquitto, mosquitto-clients

安裝完畢之後,可以利用以下的指令檢查伺服器的運行狀態:

service mosquitto status

為了讓此伺服器可以接受其它IP位址的節點進行連線,還需要開啟設定檔(/etc/mosquitto/mosquitto.conf)的最後面加上以下這2行指令:

listener 1883
allow_anonymous true

然後再執行以下的指令重新啟動服務:

service mosquitto restart

在伺服器安裝及設定完成了之後,不同節點之間如需要進行傳遞資料,有許多種方法,最簡單的測試方式是利用先前安裝的命令列程式mosquitto_pub及mosquitto_sub,請開啟2個終端機,其中一個端終機先執行mosquitto_sub,訂閱感興趣的Topic(在此例為skynettw/test),如下:

然後即可在另外一個終端機中以mosquitto_pub發佈訊息,如下所示:

然而,我們在物聯網的設計中,最方便的還是使用Python語言來傳送資料,其中paho_mosquitto即為Python中最受歡迎的MQTT模組,它的安裝方式如下:

pip install paho-mqtt

以下即為傳遞資料的範例程式:

import paho.mqtt.client as mqtt
import random, json, datetime, time

client = mqtt.Client()
client.connect("*.*.*.*", 1883, 60)
date_format = '%Y-%m-%d %H:%M:%S'

for i in range(3):
    data = random.randint(0,100)
    date = datetime.datetime.now().strftime(date_format)
    payload = {'Data':data, 'Time':date}
    client.publish("skynettw/test", json.dumps(payload))
    time.sleep(1)

上面這個程式執行之後,即會對skynettw/test這個Topic發佈3筆資料。

到於在NodeMCU上也可以不需要安裝任何模組的方式直接發佈MQTT的訊息,但是如果你在執行下列的範例程式時出現找不到umqtt模組的訊息,或是你使用的是NodeMCU 32S (ESP32)的話,那麼可能要以如下所示的指令(在Mu Editor的REPL模式或是以PuTTY連線的方式下達指令)安裝umqtt模組(下面的「>>>」是命令提示字元,請勿輸入):

>>> import upip
>>> upip.install("micropython-umqtt.simple")

安裝完畢之後,即可在Mu Editor的REPL模式下執行以下的範例程式,或是把下列的程式命名為main.py,然後放到NodeMCU上再重新啟動即可執行:

from umqtt.simple import MQTTClient
import time, random, network

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect('SSID', 'password')
while not wlan.status() != 5 :
    pass
    
def m(t, h):
    c = MQTTClient("umqtt_client", "*.*.*.*")
    c.connect()
    c.publish(b"skynettw/test", b"{},{}%".format(t, h))
    c.disconnect()
    
for i in range(10):
    t = random.getrandbits(4)
    h = random.getrandbits(4)
    m(t, h)

利用ESP32每秒鐘傳遞一次亮度數值給MQTT的Publisher程式如下:

from umqtt.simple import MQTTClient
import time, network
from machine import ADC, Pin

led = Pin(2, Pin.OUT)
led.off()
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect('SSID', '****')
while not wlan.status() != 5 :
    pass
led.on()
adc = ADC(Pin(36))
c = MQTTClient("umqtt_client", "*.*.*.*")
def m(s):
    c.connect()
    c.publish(b"minhuang/test", b"light is {}".format(s))
    c.disconnect()

while True:
    s = adc.read()
    m(s)
    time.sleep(1)

那麼該如何利用Python程式來接收MQTT的資料呢?以下是一個簡單的示範程式(在PC的Python環境下):

import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, rc):
    print("Result Code:"+str(rc))
    client.subscribe("skynettw/test")

def on_message(client, userdata, msg):
    print(msg.topic+" "+ msg.payload.decode('utf-8'))

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("x.x.x.x", 1883, 60)

client.loop_forever()

只要你有一個正確設定的MQTT伺服器,不管你在哪一台可以連網的機器上,包括PC、樹莓派、以及NodeMCU上,都可以利用上述的程式進行傳送及接收訊息的操作。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *