紀錄一下使用MQTT時採到的一個坑,在爬回平地前先來
看看Pubsubclient lib裡面一個基本的範例 ,不可否認的,這範例寫的很清楚。
我的MQTT Broker是mosquitto 1.4.x 版
#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 };
IPAddress ip(172, 16, 0, 100);
IPAddress server(172, 16, 0, 2);
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();
}
EthernetClient ethClient;
PubSubClient client(ethClient);
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("arduinoClient")) {
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);
}
}
}
void setup()
{
Serial.begin(57600);
client.setServer(server, 1883);
client.setCallback(callback);
Ethernet.begin(mac, ip);
// Allow the hardware to sort itself out
delay(1500);
}
void loop()
{
if (!client.connected()) {
reconnect();
}
client.loop();
}
單一台裝置運作時,非常順利,但是同樣的程式碼,在二個arduino上執行時會出現
漏訊息,而且拼命和MQTT Broker Reconnect問題。
查詢了一下錯誤代碼,rc=-4表示 Connection Timeout , 在MQTT中,client與server之間會
有一個keepalive的參數,這個lib預設是15秒,也就是在15內,client有義務和server保持連
接,當超過keepalive所設定的秒數內沒有傳送資料,client必須發送一個心跳訊號,而server
在收到心跳訊號後,必須回覆,這個client才能確認與server是保持連通的。
後來確認後發現是這一行程式碼導致的問題
if (client.connect("arduinoClient"))
一眼瞄過去我也不覺得那裡有異,直到去查詢後才發現
"arduinoClient" 其實是
ClientID , 所以不應該重覆,否則Server會無法正確識別與client連線狀態,導致Client
可能沒有正確收到Server response 的keepalive回覆,誤以為斷線。