diff --git a/examples/DelayedMQTTClientConfiguration/DelayedMQTTClientConfiguration.ino b/examples/DelayedMQTTClientConfiguration/DelayedMQTTClientConfiguration.ino new file mode 100644 index 0000000..e875a84 --- /dev/null +++ b/examples/DelayedMQTTClientConfiguration/DelayedMQTTClientConfiguration.ino @@ -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 +#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(); +} diff --git a/src/EspMQTTClient.cpp b/src/EspMQTTClient.cpp index c98a6eb..92734f6 100644 --- a/src/EspMQTTClient.cpp +++ b/src/EspMQTTClient.cpp @@ -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, @@ -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) @@ -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) { diff --git a/src/EspMQTTClient.h b/src/EspMQTTClient.h index 5dc8feb..2505e22 100644 --- a/src/EspMQTTClient.h +++ b/src/EspMQTTClient.h @@ -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; @@ -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, @@ -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);