MQTT(消息隊列遙測傳輸)是目前最重要的物聯網通信協議之一。
已經有許多工程項目實現了 MQTT協議。如:
樹莓派上基於Node.js 的Pimatic 家庭自動化框架提供了 MQTT 插件來完全支持 MQTT 協議。
用於對消息進行分類
是一個UTF-8字元串
可進行分級
MQTT中文文檔: https://mcxiaoke.gitbooks.io/mqtt-cn/content/
MQTT維基百科: https://zh.wikipedia.org/wiki/MQTT
ESP8266社區論壇:https://github.com/esp8266
Server: iot.eclipse.org
Port: 1883
網址: https://iot.eclipse.org/
在接下來的例子中, 我們使用 Eclipse IoT, 一個開源的物聯網雲伺服器, 缺點是服務質量不穩定, 容易丟包. 推薦使用實驗室提供的伺服器. 如有條件, 也可購買阿里或騰訊的雲伺服器(10+¥/月)搭建一個雲伺服器.
下載完成後,打開示例->pubsubclient->mqtt-esp8266,
// Update these with values suitable for your network.
const char* ssid = "Li-507-2"; const char* password = "blackwalnut"; const char* mqtt_server = "iot.eclipse.org";
運行程序, NodeMCU 每間隔 2S 向伺服器發送 "#hello World" 的信息.
void setup_wifi() { delay(10); WiFi.begin(ssid, password); } while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
2. 接收回調函數
void callback(char* topic, byte* payload, unsigned int length){ //接收消息處理 }
3. MQTT 配置
void setup() { ...... setup_wifi(); client.setServer(mqtt_server, 1883);//伺服器地址+埠 client.setCallback(callback);//設置接收消息回調函數 }
4. MQTT 連接
void reconnect() { while (!client.connected()) { //設置客戶端ID,如果重名,伺服器會斷開前一個連接 if (client.connect(ESP.getChipID())) { //發布消息 client.publish("outTopic", "hello world"); //訂閱消息 client.subscribe("inTopic"); } else { delay(5000); } } }
5. 消息接收或發送
void loop() { if (!client.connected()) { reconnect(); } //處理訂閱消息 client.loop(); long now = millis();
//通過判斷系統時間延遲信息的發送, 而非通過 delay()函數 //因delay會導致該進程阻塞,導致在延遲期間無法訂閱信息. if (now - lastMsg > 2000) { lastMsg = now; ++value; snprintf (msg, 75, "hello world #%ld", value); client.publish("outTopic", msg); //發送主題為「outTopic」的消息到伺服器 }
首先,保證你的手機連接上了網際網路。
Mqtt的andoid端軟體測試很多, 操作方式基本相同, 以下應用可在Google Play 下載,此處以MQTT Dashboard為例
與在Arduino端中一樣,配置Andoid端代理伺服器地址與埠:
Server : iot.eclipse.org
Port : 1883
完成上述配置,android手機與esp8266間即可根據彼此確定的主題,進行發布/訂閱雙向通信。
當我們想要傳輸多組物聯網節點屬性的信息時, 可以對數據進行打包再發布, 在訂閱端進行解包, 這樣做的優點是: 確定我們訂閱的信息歸屬於哪個屬性的, 防止信息被錯誤地歸屬到其他的屬性中, 保證信息的準確性. JSON 為我們提供了一種很好的數據編碼格式.
JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。易於人閱讀和編寫。同時也易於機器解析和生成。
JSON最常用的格式是對象的 鍵值對。例如下面這樣:
{"firstName": "Brett", "lastName": "McLaughlin"}
和普通的 JS 數組一樣,JSON 表示數組的方式也是使用方括弧 []。
{ "people": [
{ "firstName": "Brett", "lastName":"McLaughlin", "email": "aaaa" },
{ "firstName": "Jason", "lastName":"Hunter", "email": "bbbb"},
{ "firstName": "Elliotte", "lastName":"Harold", "email": "cccc" }
]}
ArduinoJson官網: https://arduinojson.org/
在 Arduino 庫管理界面下載 ArduinoJson 庫
打開示例->jsonGeneratorExample/ jsonParseExample, 可以嘗試Json 打包與解包的示例
DHT11感測器的通信協議是單匯流排協議,連線為:GND ~ GND, VCC ~ 3v3,data~ d×,非常簡明。
在 Arduino 庫管理器中搜索「dht」,下載庫:DHT sensor library for ESP
打開示例->DHT_Test
設置與DHT sensor 連接的引腳, 運行即可在串口監視器看到溫濕度等輸出.
// dht.setup(17); dht.setup(D1); // Connect DHT sensor to GPIO D1
注: 上述庫在運行時可能出現問題, 推薦下載庫 SampleDHT, 運行該庫中的示例
將溫濕度兩個屬性的值打包成 JSON 格式, 通過 MQTT 協議發送到 Node-RED 平台, 在該平台上繪製出相應的圖表完成數據的可視化. 這就是一個最小的物聯網系統. 只要你的物聯網節點與終端可以連接到 Internet, MQTT 代理伺服器的提供的代理可靠, 你就可以實現對物聯網節點的遠程監控.
根據實例所寫,可發送DHT溫濕度感測器數據的Arduino代碼如下:(要發送不同感測器的信息,只需替換感測器部分的代碼)
#include "DHTesp.h" #include <ArduinoJson.h> #include <ESP8266WiFi.h> #include <PubSubClient.h>
DHTesp dht;
char msg[100]; //存放json數據 float humidity; float temperature;
const char* ssid = "******"; //你的wifi名 const char* password = "*******"; //你的wifi密碼 const char* mqtt_server = "iot.eclipse.org"; //伺服器地址
WiFiClient espClient; PubSubClient client(espClient); long lastMsg = 0; int value = 0;
void setup() { Serial.begin(115200); Serial.println(); // Serial.println("Status Humidity (%) Temperature (C) (F) HeatIndex (C) (F)");
setup_wifi(); client.setServer(mqtt_server, 1883); client.setCallback(callback);
dht.setup(D1); // Connect DHT sensor to GPIO D1 }
void loop() { delay(dht.getMinimumSamplingPeriod());
humidity = dht.getHumidity(); temperature = dht.getTemperature();
if (!client.connected()) { reconnect(); } client.loop();
encodeJson();
long now = millis(); if (now - lastMsg > 2000) { lastMsg = now; ++value; // snprintf (msg, 75, "hello world #%ld", value); Serial.print("Publish message: "); Serial.println(msg); client.publish("DHT11", msg); }
}
//JSON編碼函數 void encodeJson(){ DynamicJsonBuffer jsonBuffer; JsonObject& root1 = jsonBuffer.createObject(); root1["Humidity"] = humidity; root1["Temperature"] = temperature; // root1.prettyPrintTo(Serial); root1.printTo(msg); }
//JSON解碼函數 void decodeJson(char msg[100]){ DynamicJsonBuffer jsonBuffer; JsonObject& root = jsonBuffer.parseObject(msg); float temp = root["Temperature"]; float hum = root["Humidity"];
Serial.println(temp); Serial.println(hum);
void setup_wifi() { delay(10); // We start by connecting to a WiFi network Serial.println(); Serial.print("Connecting to "); Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); }
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(); }
void reconnect() { // Loop until were 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); } } }
推薦閱讀:
TAG:物聯網 | 智能家居 | MQTT |