Skip to content

Commit

Permalink
Implement a default constructor and a setMqttServer() function to all…
Browse files Browse the repository at this point in the history
…ow configuring the connection in setup() instead of in the constructor (#84)

* First pass at implementing a default constructor in order to delay configuring mqtt server settings

* Remove const from mqtt port declaration so it can be overridden at runtime

* Put back mistakenly removed comment, fix spelling

* Expand _mqttServerIp conditional coverage

* Add DelayedMQTTClientConfiguration example to show using the default constructor along with loading configuration data from EEPROM
  • Loading branch information
davidbeauchamp authored May 5, 2021
1 parent 97d7794 commit d54a898
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
DelayedMQTTClientConfiguration.ino
The purpose of this example is to demonstrate using the default constructor in order to delay specifying
connection information until we are inside setup(). This allows us to load configuration data from EEPROM
instead of relying on hardcoded information. EEPROM provisioning is outside the scope of this example but
typically I provide an interface for setting configuration data via UART.
This example focuses on using Arduino EEPROM along with the default constructor, if you would like more
information on basic module usage please see SimpleMQTTClient.ino in the examples directory.
*/
#include <EEPROM.h>
#include "EspMQTTClient.h"

#define CONFIG_START 32 // position in EEPROM where our first byte gets written
#define CONFIG_VERSION "00001" // version string to let us compare current to whatever is in EEPROM

EspMQTTClient client; // using the default constructor

/*
This defines the struct we will use for storing our configuration data to EEPROM, it is an example however
most any struct can be written to EEPROM if it fits of course
*/
typedef struct {
char version[6]; // Version of the configuration in EEPROM, used in case we change the struct
uint8_t debug; // Debug on yes/no 1/0
char nodename[32]; // this node name
char ssid[32]; // WiFi SSID
char password[64]; // WiFi Password
char mqttip[32]; // Mosquitto server IP
uint16_t mqttport; // Mosquitto port
char mqttuser[32]; // Mosquitto Username (if needed, or "")
char mqttpass[64]; // Moqsuitto Password (if needed, or "")
} configuration_t;

/*
Declare a default configuration_t to use in case there is no EEPROM data, otherwise this gets
overwritten by whatever is in EEPROM
*/
configuration_t CONFIGURATION = {
CONFIG_VERSION,
1,
"TestClient",
"WiFiSSID",
"WifiPassword",
"192.168.1.100",
1883,
"MQTTUsername",
"MQTTPassword"
};

/*
Load whats in EEPROM in to CONFIGURATION if the version number matches
*/
int loadConfig() {
// validate its the correct version (and therefore the same struct...)
if (EEPROM.read(CONFIG_START + 0) == CONFIG_VERSION[0] &&
EEPROM.read(CONFIG_START + 1) == CONFIG_VERSION[1] &&
EEPROM.read(CONFIG_START + 2) == CONFIG_VERSION[2] &&
EEPROM.read(CONFIG_START + 3) == CONFIG_VERSION[3] &&
EEPROM.read(CONFIG_START + 4) == CONFIG_VERSION[4]) {
// and if so read configuration into struct
EEPROM.get(CONFIG_START, CONFIGURATION);
return 1;
}
return 0;
}

/*
Save the current CONFIGURATION definition to EEPROM
*/
void saveConfig() {
EEPROM.put(CONFIG_START, CONFIGURATION);
EEPROM.commit();
}

void setup()
{
Serial.begin(115200);
// need to make sure we have enough space for our struct and the offset
EEPROM.begin(sizeof(configuration_t) + CONFIG_START);

// attempt to load the current configuration from EEPROM, if it fails
// then save the default struct to the EEPROM
if (!loadConfig()) {
saveConfig();
}

// enable debug messages if our configuration tells us to
if (CONFIGURATION.debug)
client.enableDebuggingMessages();

// Set the WiFi and MQTT information that we loaded from EEPROM (or defaults as the case may be)
client.setWifiCredentials(CONFIGURATION.ssid, CONFIGURATION.password);
client.setMqttClientName(CONFIGURATION.nodename);
client.setMqttServer(CONFIGURATION.mqttip, CONFIGURATION.mqttuser, CONFIGURATION.mqttpass, CONFIGURATION.mqttport);
EEPROM.end();
}

// This function is called once everything is connected (Wifi and MQTT)
// WARNING : YOU MUST IMPLEMENT IT IF YOU USE EspMQTTClient
void onConnectionEstablished()
{
// Subscribe to "mytopic/test" and display received message to Serial
client.subscribe("mytopic/test", [](const String & payload) {
Serial.println(payload);
});

// Publish a message to "mytopic/test"
client.publish("mytopic/test", "This is a message"); // You can activate the retain flag by setting the third parameter to true
}

void loop()
{
client.loop();
}
31 changes: 26 additions & 5 deletions src/EspMQTTClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@

// =============== Constructor / destructor ===================

// default constructor
EspMQTTClient::EspMQTTClient(
const short mqttServerPort,
const char* mqttClientName) :
EspMQTTClient(nullptr, mqttServerPort, mqttClientName)
{
}

// MQTT only (no wifi connection attempt)
EspMQTTClient::EspMQTTClient(
const char* mqttServerIp,
Expand Down Expand Up @@ -246,14 +254,14 @@ bool EspMQTTClient::handleWiFi()

bool EspMQTTClient::handleMQTT()
{
// PubSubClient main lopp() call
// PubSubClient main loop() call
_mqttClient.loop();

// Get the current connextion status
bool isMqttConnected = (isWifiConnected() && _mqttClient.connected());


/***** Detect ans handle the current MQTT handling state *****/
/***** Detect and handle the current MQTT handling state *****/

// Connection established
if (isMqttConnected && !_mqttConnected)
Expand Down Expand Up @@ -536,10 +544,23 @@ void EspMQTTClient::connectToWifi()
// Try to connect to the MQTT broker and return True if the connection is successfull (blocking)
bool EspMQTTClient::connectToMqttBroker()
{
if (_enableSerialLogs)
Serial.printf("MQTT: Connecting to broker \"%s\" with client name \"%s\" ... (%fs)", _mqttServerIp, _mqttClientName, millis()/1000.0);
bool success = false;

bool success = _mqttClient.connect(_mqttClientName, _mqttUsername, _mqttPassword, _mqttLastWillTopic, 0, _mqttLastWillRetain, _mqttLastWillMessage, _mqttCleanSession);
if (_mqttServerIp != nullptr && strlen(_mqttServerIp) > 0)
{
if (_enableSerialLogs)
Serial.printf("MQTT: Connecting to broker \"%s\" with client name \"%s\" and username \"%s\" ... (%fs) ", _mqttServerIp, _mqttClientName, _mqttUsername, millis()/1000.0);

// explicitly set the server/port here in case they were not provided in the constructor
_mqttClient.setServer(_mqttServerIp, _mqttServerPort);
success = _mqttClient.connect(_mqttClientName, _mqttUsername, _mqttPassword, _mqttLastWillTopic, 0, _mqttLastWillRetain, _mqttLastWillMessage, _mqttCleanSession);
}
else
{
if (_enableSerialLogs)
Serial.printf("MQTT: Broker server ip is not set, not connecting (%fs)\n", millis()/1000.0);
success = false;
}

if (_enableSerialLogs)
{
Expand Down
12 changes: 11 additions & 1 deletion src/EspMQTTClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class EspMQTTClient
const char* _mqttUsername;
const char* _mqttPassword;
const char* _mqttClientName;
const short _mqttServerPort;
short _mqttServerPort;
bool _mqttCleanSession;
char* _mqttLastWillTopic;
char* _mqttLastWillMessage;
Expand Down Expand Up @@ -92,6 +92,10 @@ class EspMQTTClient
unsigned int _connectionEstablishedCount; // Incremented before each _connectionEstablishedCallback call

public:
EspMQTTClient(
const short mqttServerPort = 1883, // port and client name are swapped here to prevent a collision
const char* mqttClientName = "ESP8266"); // with the MQTT w/o auth constructor

// Wifi + MQTT with no MQTT authentification
EspMQTTClient(
const char* wifiSsid,
Expand Down Expand Up @@ -145,6 +149,12 @@ class EspMQTTClient
bool unsubscribe(const String &topic); //Unsubscribes from the topic, if it exists, and removes it from the CallbackList.
void setKeepAlive(uint16_t keepAliveSeconds); // Change the keepalive interval (15 seconds by default)
inline void setMqttClientName(const char* name) { _mqttClientName = name; }; // Allow to set client name manually (must be done in setup(), else it will not work.)
inline void setMqttServer(const char* server, const char* username = "", const char* password = "", const short port = 1883) { // Allow setting the MQTT info manually (must be done in setup())
_mqttServerIp = server;
_mqttUsername = username;
_mqttPassword = password;
_mqttServerPort = port;
};

// Wifi related
void setWifiCredentials(const char* wifiSsid, const char* wifiPassword);
Expand Down

0 comments on commit d54a898

Please sign in to comment.