Yes, of course. Feel free to make C++ related best/better practice recommendations as well.
#ifndef NetworkConnectionManager_h
#define NetworkConnectionManager_h
#include <MQTT.h>
#include <memory>
class NetworkConnectionManager {
public:
NetworkConnectionManager(const char *mqttBrokerUrl,
const char *commandSubscribeTopic,
const char *eventSubscribeTopic,
void (*messageReceivedCallback)(char *, uint8_t *,
unsigned int));
~NetworkConnectionManager();
void loop();
void ensureMqttBrokerConnectivity();
bool publish(const char *topic, const uint8_t *payload, unsigned int plength,
bool retain, MQTT::EMQTT_QOS qos);
private:
std::unique_ptr<MQTT> m_mqttClient = nullptr;
const char *m_mqttBrokerUrl = nullptr;
const char *m_commandSubscribeTopic = nullptr;
const char *m_eventSubscribeTopic = nullptr;
int m_ConnectionAttempts = 0;
std::unique_ptr<MQTT> createMqttClient();
void (*m_messageReceivedCallback)(char *, uint8_t *, unsigned int);
};
#endif
#include "NetworkConnectionManager.h"
NetworkConnectionManager::NetworkConnectionManager(
const char *mqttBrokerUrl, const char *commandSubscribeTopic,
const char *eventSubscribeTopic,
void (*messageReceivedCallback)(char *, uint8_t *, unsigned int)) {
m_mqttBrokerUrl = mqttBrokerUrl;
m_commandSubscribeTopic = commandSubscribeTopic;
m_eventSubscribeTopic = eventSubscribeTopic;
m_messageReceivedCallback = messageReceivedCallback;
}
NetworkConnectionManager::~NetworkConnectionManager() {}
std::unique_ptr<MQTT> NetworkConnectionManager::createMqttClient() {
return std::unique_ptr<MQTT>(
new MQTT((char *)m_mqttBrokerUrl, 1883, m_messageReceivedCallback));
}
void NetworkConnectionManager::loop() {
if (m_mqttClient == nullptr) {
m_mqttClient = createMqttClient();
}
if (!m_mqttClient->loop()) {
ensureMqttBrokerConnectivity();
}
}
bool NetworkConnectionManager::publish(const char *topic,
const uint8_t *payload,
unsigned int plength, bool retain,
MQTT::EMQTT_QOS qos) {
if (m_mqttClient == nullptr) {
m_mqttClient = createMqttClient();
}
return m_mqttClient->publish(topic, payload, plength, retain, qos);
}
void NetworkConnectionManager::ensureMqttBrokerConnectivity() {
while (!WiFi.ready()) {
Serial.println("Connecting to WiFi...");
delay(300);
}
Serial.println("Connected to WiFi");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
if (m_mqttClient == nullptr) {
m_mqttClient = createMqttClient();
}
if (m_mqttClient->isConnected()) {
return;
}
uint8_t noOfRetries = 5;
uint8_t noOfRetryAttepmts = 0;
while (!m_mqttClient->isConnected() && noOfRetryAttepmts < noOfRetries) {
Serial.println("\rMQTT Client Not Connected");
byte mac[6];
WiFi.macAddress(mac);
char clientId[18];
sprintf(clientId, "%02x%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5], random(0xffff));
Serial.print("ClientId: ");
Serial.println(clientId);
Serial.print("Connecting to MQTT Broker: ");
Serial.println(m_mqttBrokerUrl);
if (m_mqttClient->connect(clientId)) {
Serial.println("\rConnected to MQTT Broker");
m_mqttClient->subscribe(m_commandSubscribeTopic);
m_mqttClient->subscribe(m_eventSubscribeTopic);
Serial.print("Subscribed to Command Topic: ");
Serial.println(m_commandSubscribeTopic);
Serial.print("Subscribed to Event Topic: ");
Serial.println(m_eventSubscribeTopic);
Serial.println("");
} else {
Serial.print("Failed to connect to MQTT Broker: ");
Serial.println(noOfRetryAttepmts + 1);
Serial.println("Creating a new instance of Mqtt Client");
m_mqttClient = createMqttClient();
Serial.println("Trying again in 5 seconds...");
delay(5000);
Particle.process();
noOfRetryAttepmts++;
}
}
if (noOfRetryAttepmts == noOfRetries) {
Serial.println("MQTT Broker Connection Re-Try attempts exceeded...");
Serial.println("System Resetting");
System.reset();
}
}
Essentially. is I create an instance of the m_mqttClient member in the constructor, rather than checking to see if is nullptr (like I'm doing say in the loop() method and others, the Photon goes into SOS mode at some point when execution tries to access the m_mqttClient member. Not at first access however, but at some point.
For example, I'll see the following Serial.println() statements in the serial monitor.
Connected to Wifi
IP Address: 192.168.1.9
MQTT Client Not Connected
ClientId: 6c0b84ca38224c7f
Connecting to MQTT Broker: iot.eclipse.org
So it figures out that the mqttClient is not connected (no access violation here). But then as soon as it attempts to execute the next line. if (m_mqttClient->connect(clientId)) {
Bam! SOS.
Using additional Serial.println() statements scattered all over the place. I see that the m_mqttClient member is created only once (it is nullptr only once). So I don't understand the difference in behavior.