在物聯網的應用情境中,如何把感應到的感測器數值傳回後台儲存起來,一直是一個很重要的議題,事實上也有許多的方法可以完成這樣的目的,除了直接把資料儲存在開發板的文字檔案之外,也可以利用藍牙或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上,都可以利用上述的程式進行傳送及接收訊息的操作。