Просмотр исходного кода

Improve MQTT (#2091)

* moved functions

* use hostname as default MQTT maintopic if parameter is not set

* use hostname as default MQTT client ID

* Only send Homassistant Discovery and Static Topics on the first connect. Retry in next round if any topic failed

* .

* add missing return code usage

* send maintopic/connection on every round like the system topics

---------

Co-authored-by: CaCO3 <caco@ruinelli.ch>
CaCO3 2 лет назад
Родитель
Сommit
a1a77ae5d9

+ 19 - 13
code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp

@@ -37,7 +37,7 @@ void ClassFlowMQTT::SetInitialParameter(void)
     topicUptime = "";
     topicUptime = "";
     topicFreeMem = "";
     topicFreeMem = "";
 
 
-    clientname = "AIOTED-" + getMac();
+    clientname = wlan_config.hostname;
 
 
     OldValue = "";
     OldValue = "";
     flowpostprocessing = NULL;  
     flowpostprocessing = NULL;  
@@ -166,7 +166,6 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
         if (((toUpper(splitted[0]) == "TOPIC") || (toUpper(splitted[0]) == "MAINTOPIC")) && (splitted.size() > 1))
         if (((toUpper(splitted[0]) == "TOPIC") || (toUpper(splitted[0]) == "MAINTOPIC")) && (splitted.size() > 1))
         {
         {
             maintopic = splitted[1];
             maintopic = splitted[1];
-            mqttServer_setMainTopic(maintopic);
         }
         }
     }
     }
 
 
@@ -175,6 +174,8 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
      * How ever we need the interval parameter from the ClassFlowControll, but that only gets started later.
      * How ever we need the interval parameter from the ClassFlowControll, but that only gets started later.
      * To work around this, we delay the start and trigger it from ClassFlowControll::ReadParameter() */
      * To work around this, we delay the start and trigger it from ClassFlowControll::ReadParameter() */
 
 
+    mqttServer_setMainTopic(maintopic);
+
     return true;
     return true;
 }
 }
 
 
@@ -210,6 +211,7 @@ bool ClassFlowMQTT::Start(float AutoInterval)
 
 
 bool ClassFlowMQTT::doFlow(string zwtime)
 bool ClassFlowMQTT::doFlow(string zwtime)
 {
 {
+    bool success;
     std::string result;
     std::string result;
     std::string resulterror = "";
     std::string resulterror = "";
     std::string resultraw = "";
     std::string resultraw = "";
@@ -221,7 +223,7 @@ bool ClassFlowMQTT::doFlow(string zwtime)
     string zw = "";
     string zw = "";
     string namenumber = "";
     string namenumber = "";
 
 
-    publishSystemData();
+    success = publishSystemData();
 
 
     if (flowpostprocessing && getMQTTisConnected())
     if (flowpostprocessing && getMQTTisConnected())
     {
     {
@@ -247,13 +249,13 @@ bool ClassFlowMQTT::doFlow(string zwtime)
 
 
 
 
             if (result.length() > 0)   
             if (result.length() > 0)   
-                MQTTPublish(namenumber + "value", result, SetRetainFlag);
+                success |= MQTTPublish(namenumber + "value", result, SetRetainFlag);
 
 
             if (resulterror.length() > 0)  
             if (resulterror.length() > 0)  
-                MQTTPublish(namenumber + "error", resulterror, SetRetainFlag);
+                success |= MQTTPublish(namenumber + "error", resulterror, SetRetainFlag);
 
 
             if (resultrate.length() > 0) {
             if (resultrate.length() > 0) {
-                MQTTPublish(namenumber + "rate", resultrate, SetRetainFlag);
+                success |= MQTTPublish(namenumber + "rate", resultrate, SetRetainFlag);
                 
                 
                 std::string resultRatePerTimeUnit;
                 std::string resultRatePerTimeUnit;
                 if (getTimeUnit() == "h") { // Need conversion to be per hour
                 if (getTimeUnit() == "h") { // Need conversion to be per hour
@@ -262,22 +264,22 @@ bool ClassFlowMQTT::doFlow(string zwtime)
                 else { // Keep per minute
                 else { // Keep per minute
                     resultRatePerTimeUnit = resultrate;
                     resultRatePerTimeUnit = resultrate;
                 }
                 }
-                MQTTPublish(namenumber + "rate_per_time_unit", resultRatePerTimeUnit, SetRetainFlag);
+                success |= MQTTPublish(namenumber + "rate_per_time_unit", resultRatePerTimeUnit, SetRetainFlag);
             }
             }
 
 
             if (resultchangabs.length() > 0) {
             if (resultchangabs.length() > 0) {
-                MQTTPublish(namenumber + "changeabsolut", resultchangabs, SetRetainFlag); // Legacy API
-                MQTTPublish(namenumber + "rate_per_digitalization_round", resultchangabs, SetRetainFlag);
+                success |= MQTTPublish(namenumber + "changeabsolut", resultchangabs, SetRetainFlag); // Legacy API
+                success |= MQTTPublish(namenumber + "rate_per_digitalization_round", resultchangabs, SetRetainFlag);
             }
             }
 
 
             if (resultraw.length() > 0)   
             if (resultraw.length() > 0)   
-                MQTTPublish(namenumber + "raw", resultraw, SetRetainFlag);
+                success |= MQTTPublish(namenumber + "raw", resultraw, SetRetainFlag);
 
 
             if (resulttimestamp.length() > 0)
             if (resulttimestamp.length() > 0)
-                MQTTPublish(namenumber + "timestamp", resulttimestamp, SetRetainFlag);
+                success |= MQTTPublish(namenumber + "timestamp", resulttimestamp, SetRetainFlag);
 
 
             std::string json = flowpostprocessing->getJsonFromNumber(i, "\n");
             std::string json = flowpostprocessing->getJsonFromNumber(i, "\n");
-            MQTTPublish(namenumber + "json", json, SetRetainFlag);
+            success |= MQTTPublish(namenumber + "json", json, SetRetainFlag);
         }
         }
     }
     }
     
     
@@ -295,10 +297,14 @@ bool ClassFlowMQTT::doFlow(string zwtime)
     //                 result = result + "\t" + zw;
     //                 result = result + "\t" + zw;
     //         }
     //         }
     //     }
     //     }
-    //     MQTTPublish(topic, result, SetRetainFlag);
+    //     success |= MQTTPublish(topic, result, SetRetainFlag);
     // }
     // }
     
     
     OldValue = result;
     OldValue = result;
+
+    if (!success) {
+        LogFile.WriteToFile(ESP_LOG_WARN, TAG, "One or more MQTT topics failed to be published!");
+    }
     
     
     return true;
     return true;
 }
 }

+ 31 - 0
code/components/jomjol_helper/Helper.cpp

@@ -963,3 +963,34 @@ std::string UrlDecode(const std::string& value)
 
 
     return result;
     return result;
 }
 }
+
+
+bool replaceString(std::string& s, std::string const& toReplace, std::string const& replaceWith) {
+    return replaceString(s, toReplace, replaceWith, true);
+}
+
+
+bool replaceString(std::string& s, std::string const& toReplace, std::string const& replaceWith, bool logIt) {
+    std::size_t pos = s.find(toReplace);
+
+    if (pos == std::string::npos) { // Not found
+        return false;
+    }
+
+    std::string old = s;
+    s.replace(pos, toReplace.length(), replaceWith);
+    if (logIt) {
+        LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line '" + old + "' to '" + s + "'");
+    }
+    return true;
+}
+
+
+bool isInString(std::string& s, std::string const& toFind) {
+    std::size_t pos = s.find(toFind);
+
+    if (pos == std::string::npos) { // Not found
+        return false;
+    }
+    return true;
+}

+ 4 - 0
code/components/jomjol_helper/Helper.h

@@ -95,4 +95,8 @@ const char* get404(void);
 
 
 std::string UrlDecode(const std::string& value);
 std::string UrlDecode(const std::string& value);
 
 
+bool replaceString(std::string& s, std::string const& toReplace, std::string const& replaceWith);
+bool replaceString(std::string& s, std::string const& toReplace, std::string const& replaceWith, bool logIt);
+bool isInString(std::string& s, std::string const& toFind);
+
 #endif //HELPER_H
 #endif //HELPER_H

+ 1 - 2
code/components/jomjol_mqtt/interface_mqtt.cpp

@@ -326,8 +326,7 @@ bool mqtt_handler_flow_start(std::string _topic, char* _data, int _data_len) {
 void MQTTconnected(){
 void MQTTconnected(){
     if (mqtt_connected) {
     if (mqtt_connected) {
         LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Connected to broker");
         LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Connected to broker");
-        MQTTPublish(lwt_topic, lwt_connected, true);                        // Publish "connected" to maintopic/connection
-
+        
         if (connectFunktionMap != NULL) {
         if (connectFunktionMap != NULL) {
             for(std::map<std::string, std::function<void()>>::iterator it = connectFunktionMap->begin(); it != connectFunktionMap->end(); ++it) {
             for(std::map<std::string, std::function<void()>>::iterator it = connectFunktionMap->begin(); it != connectFunktionMap->end(); ++it) {
                 it->second();
                 it->second();

+ 104 - 51
code/components/jomjol_mqtt/server_mqtt.cpp

@@ -47,7 +47,7 @@ void mqttServer_setMeterType(std::string _meterType, std::string _valueUnit, std
     rateUnit = _rateUnit;
     rateUnit = _rateUnit;
 }
 }
 
 
-void sendHomeAssistantDiscoveryTopic(std::string group, std::string field,
+bool sendHomeAssistantDiscoveryTopic(std::string group, std::string field,
     std::string name, std::string icon, std::string unit, std::string deviceClass, std::string stateClass, std::string entityCategory) {
     std::string name, std::string icon, std::string unit, std::string deviceClass, std::string stateClass, std::string entityCategory) {
     std::string version = std::string(libfive_git_version());
     std::string version = std::string(libfive_git_version());
 
 
@@ -131,26 +131,29 @@ void sendHomeAssistantDiscoveryTopic(std::string group, std::string field,
     "}"  +
     "}"  +
     "}";
     "}";
 
 
-    MQTTPublish(topicFull, payload, true);
+    return MQTTPublish(topicFull, payload, true);
 }
 }
 
 
-void MQTThomeassistantDiscovery() {  
-    if (!getMQTTisConnected()) 
-        return;
+bool MQTThomeassistantDiscovery() {  
+    bool allSendsSuccessed = false;
 
 
-    LogFile.WriteToFile(ESP_LOG_INFO, TAG, "MQTT - Sending Homeassistant Discovery Topics (Meter Type: " + meterType + ", Value Unit: " + valueUnit + " , Rate Unit: " + rateUnit + ")...");
+    if (!getMQTTisConnected()) {
+        LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Unable to send Homeassistant Discovery Topics, we are not connected to the MQTT broker!");
+        return false;
+    }
 
 
-    //                              Group | Field            | User Friendly Name | Icon                      | Unit | Device Class     | State Class  | Entity Category
-    sendHomeAssistantDiscoveryTopic("",     "uptime",          "Uptime",            "clock-time-eight-outline", "s",   "",                "",            "diagnostic");
-    sendHomeAssistantDiscoveryTopic("",     "MAC",             "MAC Address",       "network-outline",          "",    "",                "",            "diagnostic");
-    sendHomeAssistantDiscoveryTopic("",     "hostname",        "Hostname",          "network-outline",          "",    "",                "",            "diagnostic");
-    sendHomeAssistantDiscoveryTopic("",     "freeMem",         "Free Memory",       "memory",                   "B",   "",                "measurement", "diagnostic");
-    sendHomeAssistantDiscoveryTopic("",     "wifiRSSI",        "Wi-Fi RSSI",        "wifi",                     "dBm", "signal_strength", "",            "diagnostic");
-    sendHomeAssistantDiscoveryTopic("",     "CPUtemp",         "CPU Temperature",   "thermometer",              "°C",  "temperature",     "measurement", "diagnostic");
-    sendHomeAssistantDiscoveryTopic("",     "interval",        "Interval",          "clock-time-eight-outline", "min",  ""           ,    "measurement", "diagnostic");
-    sendHomeAssistantDiscoveryTopic("",     "IP",              "IP",                "network-outline",           "",    "",               "",            "diagnostic");
-    sendHomeAssistantDiscoveryTopic("",     "status",          "Status",            "list-status",               "",    "",               "",            "diagnostic");
+    LogFile.WriteToFile(ESP_LOG_INFO, TAG, "MQTT - Sending Homeassistant Discovery Topics (Meter Type: " + meterType + ", Value Unit: " + valueUnit + " , Rate Unit: " + rateUnit + ")...");
 
 
+    //                                                   Group | Field            | User Friendly Name | Icon                      | Unit | Device Class     | State Class  | Entity Category
+    allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("",     "uptime",          "Uptime",            "clock-time-eight-outline", "s",   "",                "",            "diagnostic");
+    allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("",     "MAC",             "MAC Address",       "network-outline",          "",    "",                "",            "diagnostic");
+    allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("",     "hostname",        "Hostname",          "network-outline",          "",    "",                "",            "diagnostic");
+    allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("",     "freeMem",         "Free Memory",       "memory",                   "B",   "",                "measurement", "diagnostic");
+    allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("",     "wifiRSSI",        "Wi-Fi RSSI",        "wifi",                     "dBm", "signal_strength", "",            "diagnostic");
+    allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("",     "CPUtemp",         "CPU Temperature",   "thermometer",              "°C",  "temperature",     "measurement", "diagnostic");
+    allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("",     "interval",        "Interval",          "clock-time-eight-outline", "min",  ""           ,    "measurement", "diagnostic");
+    allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("",     "IP",              "IP",                "network-outline",           "",    "",               "",            "diagnostic");
+    allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("",     "status",          "Status",            "list-status",               "",    "",               "",            "diagnostic");
 
 
 
 
     for (int i = 0; i < (*NUMBERS).size(); ++i) {
     for (int i = 0; i < (*NUMBERS).size(); ++i) {
@@ -159,76 +162,126 @@ void MQTThomeassistantDiscovery() {
             group = "";
             group = "";
         }
         }
 
 
-    //                                  Group | Field                 | User Friendly Name                | Icon                   | Unit     | Device Class | State Class       | Entity Category
-        sendHomeAssistantDiscoveryTopic(group,   "value",              "Value",                            "gauge",                 valueUnit, meterType,     "total_increasing", "");
-        sendHomeAssistantDiscoveryTopic(group,   "raw",                "Raw Value",                        "raw",                   valueUnit, "",            "total_increasing", "diagnostic");
-        sendHomeAssistantDiscoveryTopic(group,   "error",              "Error",                            "alert-circle-outline",  "",        "",            "",                 "diagnostic");
+    //                                                       Group | Field                 | User Friendly Name                | Icon                   | Unit     | Device Class | State Class       | Entity Category
+        allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group,   "value",              "Value",                            "gauge",                 valueUnit, meterType,     "total_increasing", "");
+        allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group,   "raw",                "Raw Value",                        "raw",                   valueUnit, "",            "total_increasing", "diagnostic");
+        allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group,   "error",              "Error",                            "alert-circle-outline",  "",        "",            "",                 "diagnostic");
         /* Not announcing "rate" as it is better to use rate_per_time_unit resp. rate_per_digitalization_round */
         /* Not announcing "rate" as it is better to use rate_per_time_unit resp. rate_per_digitalization_round */
-        // sendHomeAssistantDiscoveryTopic(group,   "rate",               "Rate (Unit/Minute)",               "swap-vertical",         "",        "",            "",                 ""); // Legacy, always Unit per Minute
-        sendHomeAssistantDiscoveryTopic(group,   "rate_per_time_unit", "Rate (" + rateUnit + ")",          "swap-vertical",         rateUnit,  "",            "",                 "");        
-        sendHomeAssistantDiscoveryTopic(group,   "rate_per_digitalization_round",  "Change since last digitalization round", "arrow-expand-vertical", valueUnit, "",            "measurement",      ""); // correctly the Unit is Uint/Interval!
-        sendHomeAssistantDiscoveryTopic(group,   "timestamp",          "Timestamp",                  "clock-time-eight-outline", "",        "timestamp",   "",                "diagnostic");
-        sendHomeAssistantDiscoveryTopic(group,   "json",               "JSON",                       "code-json",                "",        "",            "",                 "diagnostic");
-        sendHomeAssistantDiscoveryTopic(group,   "problem",            "Problem",                    "alert-outline",            "",        "problem",            "",                 ""); // Special binary sensor which is based on error topic
+        // allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group,   "rate",               "Rate (Unit/Minute)",               "swap-vertical",         "",        "",            "",                 ""); // Legacy, always Unit per Minute
+        allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group,   "rate_per_time_unit", "Rate (" + rateUnit + ")",          "swap-vertical",         rateUnit,  "",            "",                 "");        
+        allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group,   "rate_per_digitalization_round",  "Change since last digitalization round", "arrow-expand-vertical", valueUnit, "",            "measurement",      ""); // correctly the Unit is Uint/Interval!
+        allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group,   "timestamp",          "Timestamp",                  "clock-time-eight-outline", "",        "timestamp",   "",                "diagnostic");
+        allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group,   "json",               "JSON",                       "code-json",                "",        "",            "",                 "diagnostic");
+        allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group,   "problem",            "Problem",                    "alert-outline",            "",        "problem",            "",                 ""); // Special binary sensor which is based on error topic
     }
     }
+
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Successfully published all Homeassistant Discovery MQTT topics");
+    return allSendsSuccessed;
 }
 }
 
 
-void publishSystemData() {
-    if (!getMQTTisConnected()) 
-        return;
+bool publishSystemData() {
+    bool allSendsSuccessed = false;
+
+    if (!getMQTTisConnected()) {
+        LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Unable to send System Topics, we are not connected to the MQTT broker!");
+        return false;
+    }
 
 
     char tmp_char[50];
     char tmp_char[50];
 
 
     LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Publishing system MQTT topics...");
     LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Publishing system MQTT topics...");
 
 
+    allSendsSuccessed |= MQTTPublish(maintopic + "/" + std::string(LWT_TOPIC), LWT_CONNECTED, retainFlag); // Publish "connected" to maintopic/connection
+
     sprintf(tmp_char, "%ld", (long)getUpTime());
     sprintf(tmp_char, "%ld", (long)getUpTime());
-    MQTTPublish(maintopic + "/" + "uptime", std::string(tmp_char), retainFlag);
+    allSendsSuccessed |= MQTTPublish(maintopic + "/" + "uptime", std::string(tmp_char), retainFlag);
     
     
     sprintf(tmp_char, "%lu", (long) getESPHeapSize());
     sprintf(tmp_char, "%lu", (long) getESPHeapSize());
-    MQTTPublish(maintopic + "/" + "freeMem", std::string(tmp_char), retainFlag);
+    allSendsSuccessed |= MQTTPublish(maintopic + "/" + "freeMem", std::string(tmp_char), retainFlag);
 
 
     sprintf(tmp_char, "%d", get_WIFI_RSSI());
     sprintf(tmp_char, "%d", get_WIFI_RSSI());
-    MQTTPublish(maintopic + "/" + "wifiRSSI", std::string(tmp_char), retainFlag);
+    allSendsSuccessed |= MQTTPublish(maintopic + "/" + "wifiRSSI", std::string(tmp_char), retainFlag);
 
 
     sprintf(tmp_char, "%d", (int)temperatureRead());
     sprintf(tmp_char, "%d", (int)temperatureRead());
-    MQTTPublish(maintopic + "/" + "CPUtemp", std::string(tmp_char), retainFlag);
+    allSendsSuccessed |= MQTTPublish(maintopic + "/" + "CPUtemp", std::string(tmp_char), retainFlag);
+
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Successfully published all System MQTT topics");
+    return allSendsSuccessed;
 }
 }
 
 
 
 
-void publishStaticData() {
-    if (!getMQTTisConnected()) 
-        return;
+bool publishStaticData() {
+    bool allSendsSuccessed = false;
+
+    if (!getMQTTisConnected()) {
+        LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Unable to send Static Topics, we are not connected to the MQTT broker!");
+        return false;
+    }
 
 
     LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Publishing static MQTT topics...");
     LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Publishing static MQTT topics...");
-    MQTTPublish(maintopic + "/" + "MAC", getMac(), retainFlag);
-    MQTTPublish(maintopic + "/" + "IP", *getIPAddress(), retainFlag);
-    MQTTPublish(maintopic + "/" + "hostname", wlan_config.hostname, retainFlag);
+    allSendsSuccessed |= MQTTPublish(maintopic + "/" + "MAC", getMac(), retainFlag);
+    allSendsSuccessed |= MQTTPublish(maintopic + "/" + "IP", *getIPAddress(), retainFlag);
+    allSendsSuccessed |= MQTTPublish(maintopic + "/" + "hostname", wlan_config.hostname, retainFlag);
 
 
     std::stringstream stream;
     std::stringstream stream;
     stream << std::fixed << std::setprecision(1) << roundInterval; // minutes
     stream << std::fixed << std::setprecision(1) << roundInterval; // minutes
-    MQTTPublish(maintopic + "/" + "interval", stream.str(), retainFlag);
+    allSendsSuccessed |= MQTTPublish(maintopic + "/" + "interval", stream.str(), retainFlag);
+
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Successfully published all Static MQTT topics");
+    return allSendsSuccessed;
 }
 }
 
 
 esp_err_t sendDiscovery_and_static_Topics(httpd_req_t *req) {
 esp_err_t sendDiscovery_and_static_Topics(httpd_req_t *req) {
+    bool success = false;
+
     if (HomeassistantDiscovery) {
     if (HomeassistantDiscovery) {
-        MQTThomeassistantDiscovery();
+        success = MQTThomeassistantDiscovery();
     }
     }
 
 
-    publishStaticData();
-
-    const char* resp_str = (const char*) req->user_ctx;
-    httpd_resp_send(req, resp_str, strlen(resp_str));  
+    success |= publishStaticData();
 
 
-    return ESP_OK;
+    if (success) {
+        char msg[] = "MQTT Homeassistant Discovery and Static Topics sent!";
+        httpd_resp_send(req, msg, strlen(msg));  
+        return ESP_OK;
+    }
+    else {
+        LogFile.WriteToFile(ESP_LOG_WARN, TAG, "One or more MQTT topics failed to be published!");
+        char msg[] = "Failed to send MQTT topics!";
+        httpd_resp_send(req, msg, strlen(msg)); 
+        return ESP_FAIL;
+    }
 }
 }
 
 
 void GotConnected(std::string maintopic, bool retainFlag) {
 void GotConnected(std::string maintopic, bool retainFlag) {
-    if (HomeassistantDiscovery) {
-        MQTThomeassistantDiscovery();
+    static bool initialStaticOrHomeassistantDiscoveryTopicsGotSent = false;
+    bool success = false;
+
+    /* Only send Homeassistant Discovery and Static topics on the first time connecting */
+    if (!initialStaticOrHomeassistantDiscoveryTopicsGotSent) {
+        if (HomeassistantDiscovery) {
+            success = MQTThomeassistantDiscovery();
+        }
+
+        success |= publishStaticData();
+
+        if (success) {
+            /* Sending of all Homeassistant Discovery and Static Topics was successfull.
+             * Will no no longer send it on a re-connect!
+             * (But it is still possible to trigger sending through the REST API). */
+            initialStaticOrHomeassistantDiscoveryTopicsGotSent = true;
+        }
+        else {
+        LogFile.WriteToFile(ESP_LOG_WARN, TAG, "One or more static or Homeassistant Discovery MQTT topics failed to be published! Will try again on the next round.");
+        }
     }
     }
 
 
-    publishStaticData();
-    publishSystemData();
+    /* The System Data changes at runtime, therefore we always send it after a re-connect */
+    success |= publishSystemData();
+
+    if (!success) {
+        LogFile.WriteToFile(ESP_LOG_WARN, TAG, "One or more MQTT topics failed to be published!");
+    }
 }
 }
 
 
 void register_server_mqtt_uri(httpd_handle_t server) {
 void register_server_mqtt_uri(httpd_handle_t server) {
@@ -237,7 +290,7 @@ void register_server_mqtt_uri(httpd_handle_t server) {
 
 
     uri.uri       = "/mqtt_publish_discovery";
     uri.uri       = "/mqtt_publish_discovery";
     uri.handler   = sendDiscovery_and_static_Topics;
     uri.handler   = sendDiscovery_and_static_Topics;
-    uri.user_ctx  = (void*) "MQTT Discovery and Static Topics sent";    
+    uri.user_ctx  = (void*) "";    
     httpd_register_uri_handler(server, &uri); 
     httpd_register_uri_handler(server, &uri); 
 }
 }
 
 

+ 1 - 1
code/components/jomjol_mqtt/server_mqtt.h

@@ -16,7 +16,7 @@ std::string mqttServer_getMainTopic();
 
 
 void register_server_mqtt_uri(httpd_handle_t server);
 void register_server_mqtt_uri(httpd_handle_t server);
 
 
-void publishSystemData();
+bool publishSystemData();
 
 
 std::string getTimeUnit(void);
 std::string getTimeUnit(void);
 void GotConnected(std::string maintopic, bool SetRetainFlag);
 void GotConnected(std::string maintopic, bool SetRetainFlag);

+ 49 - 83
code/main/main.cpp

@@ -86,10 +86,6 @@ extern std::string getHTMLversion(void);
 extern std::string getHTMLcommit(void);
 extern std::string getHTMLcommit(void);
 
 
 std::vector<std::string> splitString(const std::string& str);
 std::vector<std::string> splitString(const std::string& str);
-bool replace(std::string& s, std::string const& toReplace, std::string const& replaceWith);
-bool replace(std::string& s, std::string const& toReplace, std::string const& replaceWith, bool logIt);
-//bool replace_all(std::string& s, std::string const& toReplace, std::string const& replaceWith);
-bool isInString(std::string& s, std::string const& toFind);
 void migrateConfiguration(void);
 void migrateConfiguration(void);
 
 
 static const char *TAG = "MAIN";
 static const char *TAG = "MAIN";
@@ -495,7 +491,7 @@ void migrateConfiguration(void) {
 
 
         if (configLines[i].find("[") != std::string::npos) { // Start of new section
         if (configLines[i].find("[") != std::string::npos) { // Start of new section
             section = configLines[i];
             section = configLines[i];
-            replace(section, ";", "", false); // Remove possible semicolon (just for the string comparison)
+            replaceString(section, ";", "", false); // Remove possible semicolon (just for the string comparison)
             //ESP_LOGI(TAG, "New section: %s", section.c_str());
             //ESP_LOGI(TAG, "New section: %s", section.c_str());
         }
         }
 
 
@@ -510,79 +506,79 @@ void migrateConfiguration(void) {
          *  - Only one whitespace before/after the equal sign
          *  - Only one whitespace before/after the equal sign
          */
          */
         if (section == "[MakeImage]") {
         if (section == "[MakeImage]") {
-            migrated = migrated | replace(configLines[i], "[MakeImage]", "[TakeImage]"); // Rename the section itself
+            migrated = migrated | replaceString(configLines[i], "[MakeImage]", "[TakeImage]"); // Rename the section itself
         }
         }
 
 
         if (section == "[MakeImage]" || section == "[TakeImage]") {
         if (section == "[MakeImage]" || section == "[TakeImage]") {
-            migrated = migrated | replace(configLines[i], "LogImageLocation", "RawImagesLocation");
-            migrated = migrated | replace(configLines[i], "LogfileRetentionInDays", "RawImagesRetention");
+            migrated = migrated | replaceString(configLines[i], "LogImageLocation", "RawImagesLocation");
+            migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "RawImagesRetention");
 
 
-            migrated = migrated | replace(configLines[i], ";Demo = true", ";Demo = false"); // Set it to its default value
-            migrated = migrated | replace(configLines[i], ";Demo", "Demo"); // Enable it
+            migrated = migrated | replaceString(configLines[i], ";Demo = true", ";Demo = false"); // Set it to its default value
+            migrated = migrated | replaceString(configLines[i], ";Demo", "Demo"); // Enable it
 
 
-            migrated = migrated | replace(configLines[i], ";FixedExposure = true", ";FixedExposure = false"); // Set it to its default value
-            migrated = migrated | replace(configLines[i], ";FixedExposure", "FixedExposure"); // Enable it
+            migrated = migrated | replaceString(configLines[i], ";FixedExposure = true", ";FixedExposure = false"); // Set it to its default value
+            migrated = migrated | replaceString(configLines[i], ";FixedExposure", "FixedExposure"); // Enable it
         }
         }
 
 
         if (section == "[Alignment]") {
         if (section == "[Alignment]") {
-            migrated = migrated | replace(configLines[i], ";InitialMirror = true", ";InitialMirror = false"); // Set it to its default value
-            migrated = migrated | replace(configLines[i], ";InitialMirror", "InitialMirror"); // Enable it
+            migrated = migrated | replaceString(configLines[i], ";InitialMirror = true", ";InitialMirror = false"); // Set it to its default value
+            migrated = migrated | replaceString(configLines[i], ";InitialMirror", "InitialMirror"); // Enable it
 
 
-            migrated = migrated | replace(configLines[i], ";FlipImageSize = true", ";FlipImageSize = false"); // Set it to its default value
-            migrated = migrated | replace(configLines[i], ";FlipImageSize", "FlipImageSize"); // Enable it
+            migrated = migrated | replaceString(configLines[i], ";FlipImageSize = true", ";FlipImageSize = false"); // Set it to its default value
+            migrated = migrated | replaceString(configLines[i], ";FlipImageSize", "FlipImageSize"); // Enable it
         }
         }
 
 
         if (section == "[Digits]") {
         if (section == "[Digits]") {
-            migrated = migrated | replace(configLines[i], "LogImageLocation", "ROIImagesLocation");
-            migrated = migrated | replace(configLines[i], "LogfileRetentionInDays", "ROIImagesRetention");
+            migrated = migrated | replaceString(configLines[i], "LogImageLocation", "ROIImagesLocation");
+            migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "ROIImagesRetention");
         }
         }
 
 
         if (section == "[Analog]") {
         if (section == "[Analog]") {
-            migrated = migrated | replace(configLines[i], "LogImageLocation", "ROIImagesLocation");
-            migrated = migrated | replace(configLines[i], "LogfileRetentionInDays", "ROIImagesRetention");
-            migrated = migrated | replace(configLines[i], "ExtendedResolution", ";UNUSED_PARAMETER"); // This parameter is no longer used
+            migrated = migrated | replaceString(configLines[i], "LogImageLocation", "ROIImagesLocation");
+            migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "ROIImagesRetention");
+            migrated = migrated | replaceString(configLines[i], "ExtendedResolution", ";UNUSED_PARAMETER"); // This parameter is no longer used
         }
         }
 
 
         if (section == "[PostProcessing]") {
         if (section == "[PostProcessing]") {
-            migrated = migrated | replace(configLines[i], ";PreValueUse = true", ";PreValueUse = false"); // Set it to its default value
-            migrated = migrated | replace(configLines[i], ";PreValueUse", "PreValueUse"); // Enable it
+            migrated = migrated | replaceString(configLines[i], ";PreValueUse = true", ";PreValueUse = false"); // Set it to its default value
+            migrated = migrated | replaceString(configLines[i], ";PreValueUse", "PreValueUse"); // Enable it
 
 
             /* AllowNegativeRates has a <NUMBER> as prefix! */
             /* AllowNegativeRates has a <NUMBER> as prefix! */
             if (isInString(configLines[i], "AllowNegativeRates") && isInString(configLines[i], ";")) { // It is the parameter "AllowNegativeRates" and it is commented out
             if (isInString(configLines[i], "AllowNegativeRates") && isInString(configLines[i], ";")) { // It is the parameter "AllowNegativeRates" and it is commented out
-                migrated = migrated | replace(configLines[i], "true", "false"); // Set it to its default value
-                migrated = migrated | replace(configLines[i], ";", ""); // Enable it
+                migrated = migrated | replaceString(configLines[i], "true", "false"); // Set it to its default value
+                migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
             }
             }
 
 
             /* IgnoreLeadingNaN has a <NUMBER> as prefix! */
             /* IgnoreLeadingNaN has a <NUMBER> as prefix! */
             if (isInString(configLines[i], "IgnoreLeadingNaN") && isInString(configLines[i], ";")) { // It is the parameter "IgnoreLeadingNaN" and it is commented out
             if (isInString(configLines[i], "IgnoreLeadingNaN") && isInString(configLines[i], ";")) { // It is the parameter "IgnoreLeadingNaN" and it is commented out
-                migrated = migrated | replace(configLines[i], "true", "false"); // Set it to its default value
-                migrated = migrated | replace(configLines[i], ";", ""); // Enable it
+                migrated = migrated | replaceString(configLines[i], "true", "false"); // Set it to its default value
+                migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
             }
             }
 
 
             /* ExtendedResolution has a <NUMBER> as prefix! */
             /* ExtendedResolution has a <NUMBER> as prefix! */
             if (isInString(configLines[i], "ExtendedResolution") && isInString(configLines[i], ";")) { // It is the parameter "ExtendedResolution" and it is commented out
             if (isInString(configLines[i], "ExtendedResolution") && isInString(configLines[i], ";")) { // It is the parameter "ExtendedResolution" and it is commented out
-                migrated = migrated | replace(configLines[i], "true", "false"); // Set it to its default value
-                migrated = migrated | replace(configLines[i], ";", ""); // Enable it
+                migrated = migrated | replaceString(configLines[i], "true", "false"); // Set it to its default value
+                migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
             }
             }
 
 
-            migrated = migrated | replace(configLines[i], ";ErrorMessage = true", ";ErrorMessage = false"); // Set it to its default value
-            migrated = migrated | replace(configLines[i], ";ErrorMessage", "ErrorMessage"); // Enable it
+            migrated = migrated | replaceString(configLines[i], ";ErrorMessage = true", ";ErrorMessage = false"); // Set it to its default value
+            migrated = migrated | replaceString(configLines[i], ";ErrorMessage", "ErrorMessage"); // Enable it
 
 
-            migrated = migrated | replace(configLines[i], ";CheckDigitIncreaseConsistency = true", ";CheckDigitIncreaseConsistency = false"); // Set it to its default value
-            migrated = migrated | replace(configLines[i], ";CheckDigitIncreaseConsistency", "CheckDigitIncreaseConsistency"); // Enable it
+            migrated = migrated | replaceString(configLines[i], ";CheckDigitIncreaseConsistency = true", ";CheckDigitIncreaseConsistency = false"); // Set it to its default value
+            migrated = migrated | replaceString(configLines[i], ";CheckDigitIncreaseConsistency", "CheckDigitIncreaseConsistency"); // Enable it
         }
         }
 
 
         if (section == "[MQTT]") {
         if (section == "[MQTT]") {
-            migrated = migrated | replace(configLines[i], "SetRetainFlag", "RetainMessages"); // First rename it, enable it with its default value
-            migrated = migrated | replace(configLines[i], ";RetainMessages = true", ";RetainMessages = false"); // Set it to its default value
-            migrated = migrated | replace(configLines[i], ";RetainMessages", "RetainMessages"); // Enable it
+            migrated = migrated | replaceString(configLines[i], "SetRetainFlag", "RetainMessages"); // First rename it, enable it with its default value
+            migrated = migrated | replaceString(configLines[i], ";RetainMessages = true", ";RetainMessages = false"); // Set it to its default value
+            migrated = migrated | replaceString(configLines[i], ";RetainMessages", "RetainMessages"); // Enable it
 
 
-            migrated = migrated | replace(configLines[i], ";HomeassistantDiscovery = true", ";HomeassistantDiscovery = false"); // Set it to its default value
-            migrated = migrated | replace(configLines[i], ";HomeassistantDiscovery", "HomeassistantDiscovery"); // Enable it
+            migrated = migrated | replaceString(configLines[i], ";HomeassistantDiscovery = true", ";HomeassistantDiscovery = false"); // Set it to its default value
+            migrated = migrated | replaceString(configLines[i], ";HomeassistantDiscovery", "HomeassistantDiscovery"); // Enable it
 
 
             if (configLines[i].rfind("Topic", 0) != std::string::npos)  // only if string starts with "Topic" (Was the naming in very old version)
             if (configLines[i].rfind("Topic", 0) != std::string::npos)  // only if string starts with "Topic" (Was the naming in very old version)
             {
             {
-                migrated = migrated | replace(configLines[i], "Topic", "MainTopic");
+                migrated = migrated | replaceString(configLines[i], "Topic", "MainTopic");
             }
             }
         }
         }
 
 
@@ -595,34 +591,34 @@ void migrateConfiguration(void) {
         }
         }
 
 
         if (section == "[DataLogging]") {
         if (section == "[DataLogging]") {
-            migrated = migrated | replace(configLines[i], "DataLogRetentionInDays", "DataFilesRetention");
+            migrated = migrated | replaceString(configLines[i], "DataLogRetentionInDays", "DataFilesRetention");
             /* DataLogActive is true by default! */
             /* DataLogActive is true by default! */
-            migrated = migrated | replace(configLines[i], ";DataLogActive = false", ";DataLogActive = true"); // Set it to its default value
-            migrated = migrated | replace(configLines[i], ";DataLogActive", "DataLogActive"); // Enable it
+            migrated = migrated | replaceString(configLines[i], ";DataLogActive = false", ";DataLogActive = true"); // Set it to its default value
+            migrated = migrated | replaceString(configLines[i], ";DataLogActive", "DataLogActive"); // Enable it
         }
         }
 
 
         if (section == "[AutoTimer]") {
         if (section == "[AutoTimer]") {
-            migrated = migrated | replace(configLines[i], "Intervall", "Interval");
-            migrated = migrated | replace(configLines[i], ";AutoStart = true", ";AutoStart = false"); // Set it to its default value
-            migrated = migrated | replace(configLines[i], ";AutoStart", "AutoStart"); // Enable it
+            migrated = migrated | replaceString(configLines[i], "Intervall", "Interval");
+            migrated = migrated | replaceString(configLines[i], ";AutoStart = true", ";AutoStart = false"); // Set it to its default value
+            migrated = migrated | replaceString(configLines[i], ";AutoStart", "AutoStart"); // Enable it
 
 
         }
         }
 
 
         if (section == "[Debug]") {
         if (section == "[Debug]") {
-            migrated = migrated | replace(configLines[i], "Logfile ", "LogLevel "); // Whitespace needed so it does not match `LogfileRetentionInDays`
+            migrated = migrated | replaceString(configLines[i], "Logfile ", "LogLevel "); // Whitespace needed so it does not match `LogfileRetentionInDays`
             /* LogLevel (resp. LogFile) was originally a boolean, but we switched it to an int
             /* LogLevel (resp. LogFile) was originally a boolean, but we switched it to an int
              * For both cases (true/false), we set it to level 2 (WARNING) */
              * For both cases (true/false), we set it to level 2 (WARNING) */
-            migrated = migrated | replace(configLines[i], "LogLevel = true", "LogLevel = 2");
-            migrated = migrated | replace(configLines[i], "LogLevel = false", "LogLevel = 2");
-            migrated = migrated | replace(configLines[i], "LogfileRetentionInDays", "LogfilesRetention");
+            migrated = migrated | replaceString(configLines[i], "LogLevel = true", "LogLevel = 2");
+            migrated = migrated | replaceString(configLines[i], "LogLevel = false", "LogLevel = 2");
+            migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "LogfilesRetention");
         }
         }
 
 
         if (section == "[System]") {
         if (section == "[System]") {
-            migrated = migrated | replace(configLines[i], "RSSIThreashold", "RSSIThreshold");
-            migrated = migrated | replace(configLines[i], "AutoAdjustSummertime", ";UNUSED_PARAMETER"); // This parameter is no longer used
+            migrated = migrated | replaceString(configLines[i], "RSSIThreashold", "RSSIThreshold");
+            migrated = migrated | replaceString(configLines[i], "AutoAdjustSummertime", ";UNUSED_PARAMETER"); // This parameter is no longer used
 
 
-            migrated = migrated | replace(configLines[i], ";SetupMode = true", ";SetupMode = false"); // Set it to its default value
-            migrated = migrated | replace(configLines[i], ";SetupMode", "SetupMode"); // Enable it
+            migrated = migrated | replaceString(configLines[i], ";SetupMode = true", ";SetupMode = false"); // Set it to its default value
+            migrated = migrated | replaceString(configLines[i], ";SetupMode", "SetupMode"); // Enable it
         }
         }
     }
     }
 
 
@@ -683,33 +679,3 @@ std::vector<std::string> splitString(const std::string& str) {
 
 
     return found;
     return found;
 }*/
 }*/
-
-
-bool replace(std::string& s, std::string const& toReplace, std::string const& replaceWith) {
-    return replace(s, toReplace, replaceWith, true);
-}
-
-bool replace(std::string& s, std::string const& toReplace, std::string const& replaceWith, bool logIt) {
-    std::size_t pos = s.find(toReplace);
-
-    if (pos == std::string::npos) { // Not found
-        return false;
-    }
-
-    std::string old = s;
-    s.replace(pos, toReplace.length(), replaceWith);
-    if (logIt) {
-        LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line '" + old + "' to '" + s + "'");
-    }
-    return true;
-}
-
-
-bool isInString(std::string& s, std::string const& toFind) {
-    std::size_t pos = s.find(toFind);
-
-    if (pos == std::string::npos) { // Not found
-        return false;
-    }
-    return true;
-}