BUG FIX: bad clientID due to bad MQTT library - causes disconnects with multiple AB's on one broker!

IMPROVEMENT: MQTT reconnect implemented.
This commit is contained in:
Ray Jones 2019-09-01 14:43:00 +10:00
parent fdf4e9af99
commit 3e4ce429c7
4 changed files with 162 additions and 48 deletions

View file

@ -37,7 +37,8 @@ AsyncMqttClient::AsyncMqttClient()
_client.onPoll([](void* obj, AsyncClient* c) { (static_cast<AsyncMqttClient*>(obj))->_onPoll(c); }, this); _client.onPoll([](void* obj, AsyncClient* c) { (static_cast<AsyncMqttClient*>(obj))->_onPoll(c); }, this);
#ifdef ESP32 #ifdef ESP32
sprintf(_generatedClientId, "esp32%06x", ESP.getEfuseMac()); // WHY OH WHY WON'T THE DEV DO THIS FIX (original is %06x - 32bits, excludes the important unique bits!)
sprintf(_generatedClientId, "esp32%06llx", ESP.getEfuseMac());
_xSemaphore = xSemaphoreCreateMutex(); _xSemaphore = xSemaphoreCreateMutex();
#elif defined(ESP8266) #elif defined(ESP8266)
sprintf(_generatedClientId, "esp8266%06x", ESP.getChipId()); sprintf(_generatedClientId, "esp8266%06x", ESP.getChipId());

View file

@ -123,8 +123,8 @@
#define RX_DATA_TIMOUT 50 #define RX_DATA_TIMOUT 50
const int FirmwareRevision = 31; const int FirmwareRevision = 31;
const int FirmwareSubRevision = 0; const int FirmwareSubRevision = 1;
const char* FirmwareDate = "31 Aug 2019"; const char* FirmwareDate = "1 Sep 2019";
#ifdef ESP32 #ifdef ESP32
@ -1624,7 +1624,8 @@ void doStreaming()
bHaveWebClient = doWebServer(); bHaveWebClient = doWebServer();
#endif //USE_WEBSERVER #endif //USE_WEBSERVER
#if USE_MQTT == 1 #if USE_MQTT == 1
// MQTT is managed via callbacks!!! // most MQTT is managed via callbacks, but need some sundry housekeeping
doMQTT();
#endif #endif

View file

@ -5,6 +5,7 @@
#include "../cfg/BTCConfig.h" #include "../cfg/BTCConfig.h"
#if USE_MQTT == 1 #if USE_MQTT == 1
#include <Arduino.h> #include <Arduino.h>
#include "ABMqtt.h" #include "ABMqtt.h"
#include "../../lib/async-mqtt-client/src/AsyncMqttClient.h" #include "../../lib/async-mqtt-client/src/AsyncMqttClient.h"
@ -13,37 +14,68 @@
#include "../Utility/DebugPort.h" #include "../Utility/DebugPort.h"
#include "../Utility/NVStorage.h" #include "../Utility/NVStorage.h"
//IPAddress testMQTTserver(5, 196, 95, 208); // test.mosquito.org #define USE_RTOS_MQTTTIMER
IPAddress testMQTTserver(18, 194, 98, 249); // broker.hivemq.com //#define USE_LOCAL_MQTTSTRINGS
//IPAddress testMQTTserver(5, 196, 95, 208); // test.mosquito.org
//IPAddress testMQTTserver(18, 194, 98, 249); // broker.hivemq.com
AsyncMqttClient MQTTclient; AsyncMqttClient MQTTclient;
TimerHandle_t mqttReconnectTimer = NULL;
char topicnameJSONin[128]; char topicnameJSONin[128];
#ifdef USE_LOCAL_MQTTSTRINGS
char mqttHost[128];
char mqttUser[32];
char mqttPass[32];
#endif
#ifdef USE_RTOS_MQTTTIMER
TimerHandle_t mqttReconnectTimer = NULL;
#else
unsigned long mqttReconnect = 0;
#endif
void connectToMqtt() { void connectToMqtt() {
DebugPort.println("MQTT: Connecting..."); #ifdef USE_RTOS_MQTTTIMER
MQTTclient.connect(); xTimerStop(mqttReconnectTimer, 0);
#else
mqttReconnect = 0;
#endif
if(!MQTTclient.connected()) {
DebugPort.println("MQTT: Connecting...");
if(NVstore.getMQTTinfo().enabled) {
MQTTclient.connect();
}
}
} }
void onMqttConnect(bool sessionPresent) void onMqttConnect(bool sessionPresent)
{ {
#ifdef USE_RTOS_MQTTTIMER
xTimerStop(mqttReconnectTimer, 0);
#else
mqttReconnect = 0;
#endif
DebugPort.println("MQTT: Connected to broker."); DebugPort.println("MQTT: Connected to broker.");
// DebugPort.printf("Session present: %d\r\n", sessionPresent); // DebugPort.printf("Session present: %d\r\n", sessionPresent);
const sMQTTparams params = NVstore.getMQTTinfo(); // create the topicname we use to accept incoming JSON
char topic[128]; DebugPort.printf("MQTT: base topic name \"%s\"\r\n", NVstore.getMQTTinfo().topic);
DebugPort.printf("MQTT: base topic name \"%s\"\r\n", params.topic); sprintf(topicnameJSONin, "%s/JSONin", NVstore.getMQTTinfo().topic);
sprintf(topicnameJSONin, "%s/JSONin", params.topic); // subscribe to that topic
DebugPort.printf("MQTT: Subscribing to \"%s\"\r\n", topicnameJSONin); DebugPort.printf("MQTT: Subscribing to \"%s\"\r\n", topicnameJSONin);
MQTTclient.subscribe(topicnameJSONin, params.qos); MQTTclient.subscribe(topicnameJSONin, NVstore.getMQTTinfo().qos);
// spit out an "I'm here" message // spit out an "I'm here" message
sprintf(topic, "%s/Status", params.topic); char lcltopic[128];
MQTTclient.publish(topic, params.qos, true, "onMqttConnect"); sprintf(lcltopic, "%s/Status", NVstore.getMQTTinfo().topic);
MQTTclient.publish(lcltopic, NVstore.getMQTTinfo().qos, true, "onMqttConnect");
#ifdef MQTT_DBG_LOOPBACK #ifdef MQTT_DBG_LOOPBACK
// testo - loopback // testo - loopback
sprintf(topic, "%s/JSONout", params.topic); sprintflcl(topic, "%s/JSONout", NVstore.getMQTTinfo().topic);
MQTTclient.subscribe(topic, params.qos); MQTTclient.subscribe(lcltopic, NVstore.getMQTTinfo().qos);
#endif #endif
resetJSONmoderator(); resetJSONmoderator();
@ -73,11 +105,28 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties
} }
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) { void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
DebugPort.println("MQTT: Disconnected!"); DebugPort.print("MQTT: Disconnected, reason: ");
// ref: DisconnectReasons.hpp
switch(reason) {
case AsyncMqttClientDisconnectReason::TCP_DISCONNECTED: DebugPort.println("TCP disconnected"); break;
case AsyncMqttClientDisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION: DebugPort.println("protocol version"); break;
case AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED: DebugPort.println("Identifier rejected"); break;
case AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE: DebugPort.println("Server unavailable"); break;
case AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS: DebugPort.println("Malformed credentials"); break;
case AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED: DebugPort.println("No authorised"); break;
case AsyncMqttClientDisconnectReason::ESP8266_NOT_ENOUGH_SPACE: DebugPort.println("Not enough space"); break;
case AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT: DebugPort.println("Bad TLS fingerprint"); break;
}
// if (WiFi.isConnected()) { if (WiFi.isConnected()) {
// xTimerStart(mqttReconnectTimer, 0); if(NVstore.getMQTTinfo().enabled) {
// } #ifdef USE_RTOS_MQTTTIMER
xTimerStart(mqttReconnectTimer, 0);
#else
mqttReconnect = millis() + 5000;
#endif
}
}
} }
void onMqttSubscribe(uint16_t packetId, uint8_t qos) { void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
@ -88,37 +137,57 @@ void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
bool mqttInit() bool mqttInit()
{ {
// if(mqttReconnectTimer==NULL) #ifdef USE_RTOS_MQTTTIMER
// mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt)); if(mqttReconnectTimer==NULL)
mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
#else
mqttReconnect = 0;
#endif
memset(topicnameJSONin, 0, sizeof(topicnameJSONin)); memset(topicnameJSONin, 0, sizeof(topicnameJSONin));
MQTTclient.disconnect(true);
long escape = millis() + 10000;
while(MQTTclient.connected()) {
long tDelta = millis()-escape;
if(tDelta > 0) {
DebugPort.println("MQTT: TIMEOUT waiting for broker disconnect");
break;
}
}
const sMQTTparams params = NVstore.getMQTTinfo(); const sMQTTparams params = NVstore.getMQTTinfo();
if(params.enabled) { if(params.enabled) {
if(strlen(params.host)) { #ifdef USE_LOCAL_MQTTSTRINGS
MQTTclient.disconnect(); strncpy(mqttHost, params.host, 127);
long escape = millis() + 10000; strncpy(mqttUser, params.username, 31);
while(MQTTclient.connected()) { strncpy(mqttPass, params.password, 31);
long tDelta = millis()-escape; mqttHost[127] = 0;
if(tDelta > 0) { mqttUser[31] = 0;
DebugPort.println("MQTT: TIMEOUT waiting for broker disconnect"); mqttPass[31] = 0;
break; DebugPort.printf("MQTT: setting broker to %s:%d\r\n", mqttHost, params.port);
} DebugPort.printf("MQTT: %s/%s\r\n", mqttUser, mqttPass);
} MQTTclient.setServer(mqttHost, params.port);
DebugPort.printf("MQTT: setting broker to %s:%d\r\n", params.host, params.port); MQTTclient.setCredentials(mqttUser, mqttPass);
MQTTclient.setServer(params.host, params.port); #else
MQTTclient.setCredentials(params.username, params.password); // the client only stores a pointer - this must not be a volatile memory location!
static bool setCallbacks = false; // - NO STACK vars!!!
// callbacks should only be added once (vector of callbacks in client!) DebugPort.printf("MQTT: setting broker to %s:%d\r\n", NVstore.getMQTTinfo().host, NVstore.getMQTTinfo().port);
if(!setCallbacks) { MQTTclient.setServer(NVstore.getMQTTinfo().host, NVstore.getMQTTinfo().port);
MQTTclient.onConnect(onMqttConnect); DebugPort.printf("MQTT: %s/%s\r\n", NVstore.getMQTTinfo().username, NVstore.getMQTTinfo().password);
MQTTclient.onMessage(onMqttMessage); MQTTclient.setCredentials(NVstore.getMQTTinfo().username, NVstore.getMQTTinfo().password);
MQTTclient.onDisconnect(onMqttDisconnect); #endif
MQTTclient.onSubscribe(onMqttSubscribe); static bool setCallbacks = false;
setCallbacks = true; // callbacks should only be added once (vector of callbacks in client!)
} if(!setCallbacks) {
MQTTclient.connect(); MQTTclient.onConnect(onMqttConnect);
return true; MQTTclient.onMessage(onMqttMessage);
MQTTclient.onDisconnect(onMqttDisconnect);
MQTTclient.onSubscribe(onMqttSubscribe);
setCallbacks = true;
} }
// connection takes pplace via delayed start method
return true;
} }
return false; return false;
} }
@ -135,5 +204,44 @@ bool mqttPublishJSON(const char* str)
return false; return false;
} }
void kickMQTT() {
if (WiFi.isConnected()) {
if(NVstore.getMQTTinfo().enabled) {
#ifdef USE_RTOS_MQTTTIMER
xTimerStart(mqttReconnectTimer, 0);
#else
mqttReconnect = millis() + 5000;
#endif
}
}
}
void doMQTT()
{
// most MQTT is managed via callbacks!!!
if(NVstore.getMQTTinfo().enabled) {
#ifndef USE_RTOS_MQTTTIMER
if(mqttReconnect) {
long tDelta = millis() - mqttReconnect;
if(tDelta > 0) {
mqttReconnect = 0;
connectToMqtt();
}
}
#endif
#ifdef USE_RTOS_MQTTTIMER
if (!MQTTclient.connected() && WiFi.isConnected() && !xTimerIsTimerActive(mqttReconnectTimer)) {
xTimerStart(mqttReconnectTimer, 0);
}
#else
if (!MQTTclient.connected() && WiFi.isConnected() && mqttReconnect==0) {
mqttReconnect = millis() + 5000;
}
#endif
}
}
#endif #endif

View file

@ -5,7 +5,11 @@
bool mqttInit(); bool mqttInit();
void doMQTT();
bool mqttPublishJSON(const char* str); bool mqttPublishJSON(const char* str);
void connectToMqtt();
void kickMQTT();
#endif #endif