diff --git a/code/components/jomjol_controlGPIO/server_GPIO.cpp b/code/components/jomjol_controlGPIO/server_GPIO.cpp index e54dcaa2..c21adde5 100644 --- a/code/components/jomjol_controlGPIO/server_GPIO.cpp +++ b/code/components/jomjol_controlGPIO/server_GPIO.cpp @@ -110,7 +110,7 @@ void GpioPin::init() // if (_interruptType != GPIO_INTR_DISABLE) { // ohne GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X, wenn das genutzt wird, dann soll auch der Handler hier nicht initialisiert werden, da das dann über SmartLED erfolgt. if ((_interruptType != GPIO_INTR_DISABLE) && (_interruptType != GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X)) { //hook isr handler for specific gpio pin - ESP_LOGD(TAG_SERVERGPIO, "GpioPin::init add isr handler for GPIO %d\r\n", _gpio); + ESP_LOGD(TAG_SERVERGPIO, "GpioPin::init add isr handler for GPIO %d", _gpio); gpio_isr_handler_add(_gpio, gpio_isr_handler, (void*)&_gpio); } @@ -131,7 +131,7 @@ bool GpioPin::getValue(std::string* errorText) void GpioPin::setValue(bool value, gpio_set_source setSource, std::string* errorText) { - ESP_LOGD(TAG_SERVERGPIO, "GpioPin::setValue %d\r\n", value); + ESP_LOGD(TAG_SERVERGPIO, "GpioPin::setValue %d", value); if ((_mode != GPIO_PIN_MODE_OUTPUT) && (_mode != GPIO_PIN_MODE_OUTPUT_PWM) && (_mode != GPIO_PIN_MODE_BUILT_IN_FLASH_LED)) { (*errorText) = "GPIO is not in output mode"; @@ -154,7 +154,7 @@ void GpioPin::publishState() { } bool GpioPin::handleMQTT(std::string, char* data, int data_len) { - ESP_LOGD(TAG_SERVERGPIO, "GpioPin::handleMQTT data %.*s\r\n", data_len, data); + ESP_LOGD(TAG_SERVERGPIO, "GpioPin::handleMQTT data %.*s", data_len, data); std::string dataStr(data, data_len); dataStr = toLower(dataStr); @@ -321,7 +321,7 @@ bool GpioHandler::readConfig() if (mainTopicMQTT.length() > 0) { mainTopicMQTT = mainTopicMQTT + "/GPIO"; - ESP_LOGD(TAG_SERVERGPIO, "MAINTOPICMQTT found\r\n"); + ESP_LOGD(TAG_SERVERGPIO, "MAINTOPICMQTT found"); } bool registerISR = false; @@ -333,9 +333,9 @@ bool GpioHandler::readConfig() // if (std::regex_match(zerlegt[0], pieces_match, pieces_regex) && (pieces_match.size() == 2)) // { // std::string gpioStr = pieces_match[1]; - ESP_LOGD(TAG_SERVERGPIO, "conf param %s\r\n", toUpper(zerlegt[0]).c_str()); + ESP_LOGD(TAG_SERVERGPIO, "conf param %s", toUpper(zerlegt[0]).c_str()); if (toUpper(zerlegt[0]) == "MAINTOPICMQTT") { -// ESP_LOGD(TAG_SERVERGPIO, "MAINTOPICMQTT found\r\n"); +// ESP_LOGD(TAG_SERVERGPIO, "MAINTOPICMQTT found"); // mainTopicMQTT = zerlegt[1]; } else if ((zerlegt[0].rfind("IO", 0) == 0) && (zerlegt.size() >= 6)) { @@ -420,7 +420,7 @@ bool GpioHandler::readConfig() void GpioHandler::clear() { - ESP_LOGD(TAG_SERVERGPIO, "GpioHandler::clear\r\n"); + ESP_LOGD(TAG_SERVERGPIO, "GpioHandler::clear"); if (gpioMap != NULL) { for(std::map::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) { @@ -541,7 +541,7 @@ esp_err_t GpioHandler::handleHttpRequest(httpd_req_t *req) void GpioHandler::flashLightEnable(bool value) { - ESP_LOGD(TAG_SERVERGPIO, "GpioHandler::flashLightEnable %s\r\n", value ? "true" : "false"); + ESP_LOGD(TAG_SERVERGPIO, "GpioHandler::flashLightEnable %s", value ? "true" : "false"); if (gpioMap != NULL) { for(std::map::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) @@ -552,9 +552,9 @@ void GpioHandler::flashLightEnable(bool value) it->second->setValue(value, GPIO_SET_SOURCE_INTERNAL, &resp_str); if (resp_str == "") { - ESP_LOGD(TAG_SERVERGPIO, "Flash light pin GPIO %d switched to %s\r\n", (int)it->first, (value ? "on" : "off")); + ESP_LOGD(TAG_SERVERGPIO, "Flash light pin GPIO %d switched to %s", (int)it->first, (value ? "on" : "off")); } else { - ESP_LOGE(TAG_SERVERGPIO, "Can't set flash light pin GPIO %d. Error: %s\r\n", (int)it->first, resp_str.c_str()); + ESP_LOGE(TAG_SERVERGPIO, "Can't set flash light pin GPIO %d. Error: %s", (int)it->first, resp_str.c_str()); } } else { diff --git a/code/components/jomjol_flowcontroll/ClassFlowControll.cpp b/code/components/jomjol_flowcontroll/ClassFlowControll.cpp index ae4f6d63..c306447c 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowControll.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowControll.cpp @@ -131,7 +131,6 @@ string ClassFlowControll::GetMQTTMainTopic() if (FlowControll[i]->name().compare("ClassFlowMQTT") == 0) return ((ClassFlowMQTT*) (FlowControll[i]))->GetMQTTMainTopic(); - return ""; } @@ -148,7 +147,6 @@ void ClassFlowControll::SetInitialParameter(void) disabled = false; aktRunNr = 0; aktstatus = "Booting ..."; - } bool ClassFlowControll::isAutoStart(long &_intervall) @@ -157,6 +155,11 @@ bool ClassFlowControll::isAutoStart(long &_intervall) return AutoStart; } +int ClassFlowControll::getAutoInterval() +{ + return AutoIntervall * 60; // AutoIntervall: Minuten -> seconds +} + ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type) { ClassFlow* cfc = NULL; diff --git a/code/components/jomjol_flowcontroll/ClassFlowControll.h b/code/components/jomjol_flowcontroll/ClassFlowControll.h index 5fd3b08a..0a2753c7 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowControll.h +++ b/code/components/jomjol_flowcontroll/ClassFlowControll.h @@ -63,6 +63,7 @@ public: std::string doSingleStep(std::string _stepname, std::string _host); bool isAutoStart(long &_intervall); + int getAutoInterval(); std::string* getActStatus(); diff --git a/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp b/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp index 430f9b18..2892b648 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp @@ -2,11 +2,12 @@ #include "ClassFlowMQTT.h" #include "Helper.h" #include "connect_wlan.h" +#include "ClassLogFile.h" #include "time_sntp.h" #include "interface_mqtt.h" #include "ClassFlowPostProcessing.h" -#include "ClassLogFile.h" +#include "ClassFlowControll.h" #include @@ -14,6 +15,156 @@ static const char *TAG = "class_flow_MQTT"; +#define LWT_TOPIC "connection" +#define LWT_CONNECTED "connected" +#define LWT_DISCONNECTED "connection lost" + +extern const char* libfive_git_version(void); +extern const char* libfive_git_revision(void); +extern const char* libfive_git_branch(void); + +std::vector* NUMBERS; +bool HomeassistantDiscovery = false; + +void sendHomeAssistantDiscoveryTopic(std::string maintopic, std::string group, std::string field, + std::string name, std::string icon, std::string unit, std::string deviceClass, std::string stateClass) { + std::string version = std::string(libfive_git_version()); + + if (version == "") { + version = std::string(libfive_git_branch()) + " (" + std::string(libfive_git_revision()) + ")"; + } + + std::string topic; + std::string topicFull; + std::string topicT; + std::string payload; + std::string nl = "\n"; + + if (group == "") { + topic = field; + topicT = field; + } + else { + topic = group + "/" + field; + topicT = group + "_" + field; + } + + if (group != "") { // Prepend the group to the name + name = group + " " + name; + } + + topicFull = "homeassistant/sensor/" + maintopic + "/" + topicT + "/config"; + + /* See https://www.home-assistant.io/docs/mqtt/discovery/ */ + payload = "{" + nl + + "\"~\": \"" + maintopic + "\"," + nl + + "\"unique_id\": \"" + maintopic + "-" + topicT + "\"," + nl + + "\"object_id\": \"" + maintopic + "_" + topicT + "\"," + nl + // This used to generate the Entity ID + "\"name\": \"" + name + "\"," + nl + + "\"icon\": \"mdi:" + icon + "\"," + nl; + + if (group != "") { + if (field == "problem") { // Special binary sensor which is based on error topic + payload += "\"state_topic\": \"~/" + group + "/error\"," + nl; + payload += "\"value_template\": \"{{ 'OFF' if 'no error' in value else 'ON'}}\"," + nl; + } + else { + payload += "\"state_topic\": \"~/" + group + "/" + field + "\"," + nl; + } + } + else { + payload += "\"state_topic\": \"~/" + field + "\"," + nl; + } + + if (unit != "") { + payload += "\"unit_of_meas\": \"" + unit + "\"," + nl; + } + + if (deviceClass != "") { + payload += "\"device_class\": \"" + deviceClass + "\"," + nl; + /* if (deviceClass == "problem") { + payload += "\"value_template\": \"{{ 'OFF' if 'no error' in value else 'ON'}}\"," + nl; + }*/ + } + + if (stateClass != "") { + payload += "\"state_class\": \"" + stateClass + "\"," + nl; + } + + payload += + "\"availability_topic\": \"~/" + std::string(LWT_TOPIC) + "\"," + nl + + "\"payload_available\": \"" + LWT_CONNECTED + "\"," + nl + + "\"payload_not_available\": \"" + LWT_DISCONNECTED + "\"," + nl; + + payload += + "\"device\": {" + nl + + "\"identifiers\": [\"" + maintopic + "\"]," + nl + + "\"name\": \"" + maintopic + "\"," + nl + + "\"model\": \"Meter Digitizer\"," + nl + + "\"manufacturer\": \"AI on the Edge Device\"," + nl + + "\"sw_version\": \"" + version + "\"," + nl + + "\"configuration_url\": \"http://" + *getIPAddress() + "\"" + nl + + "}" + nl + + "}" + nl; + + MQTTPublish(topicFull, payload, true); +} + +void MQTThomeassistantDiscovery(std::string maintopic) { + LogFile.WriteToFile(ESP_LOG_INFO, "MQTT - Sending Homeassistant Discovery Topics..."); + // maintopic group field User Friendly Name icon unit Device Class State Class + sendHomeAssistantDiscoveryTopic(maintopic, "", "uptime", "Uptime", "clock-time-eight-outline", "s", "", ""); + sendHomeAssistantDiscoveryTopic(maintopic, "", "IP", "IP", "network-outline", "", "", ""); + sendHomeAssistantDiscoveryTopic(maintopic, "", "MAC", "MAC Address", "network-outline", "", "", ""); + sendHomeAssistantDiscoveryTopic(maintopic, "", "hostname", "Hostname", "network-outline", "", "", ""); + sendHomeAssistantDiscoveryTopic(maintopic, "", "freeMem", "Free Memory", "memory", "B", "", "measurement"); + sendHomeAssistantDiscoveryTopic(maintopic, "", "wifiRSSI", "Wi-Fi RSSI", "wifi", "dBm", "signal_strength", ""); + sendHomeAssistantDiscoveryTopic(maintopic, "", "CPUtemp", "CPU Temperature", "thermometer", "°C", "temperature", "measurement"); + + for (int i = 0; i < (*NUMBERS).size(); ++i) { + // maintopic group field User Friendly Name icon unit Device Class State Class + sendHomeAssistantDiscoveryTopic(maintopic, (*NUMBERS)[i]->name, "value", "Value", "gauge", "", "", "total_increasing"); + sendHomeAssistantDiscoveryTopic(maintopic, (*NUMBERS)[i]->name, "error", "Error", "alert-circle-outline", "", "", ""); + sendHomeAssistantDiscoveryTopic(maintopic, (*NUMBERS)[i]->name, "rate", "Rate", "swap-vertical", "", "", ""); + sendHomeAssistantDiscoveryTopic(maintopic, (*NUMBERS)[i]->name, "changeabsolut", "Absolute Change", "arrow-expand-vertical", "", "", "measurement"); + sendHomeAssistantDiscoveryTopic(maintopic, (*NUMBERS)[i]->name, "raw", "Raw Value", "raw", "", "", "total_increasing"); + sendHomeAssistantDiscoveryTopic(maintopic, (*NUMBERS)[i]->name, "timestamp", "Timestamp", "clock-time-eight-outline", "", "timestamp", ""); + sendHomeAssistantDiscoveryTopic(maintopic, (*NUMBERS)[i]->name, "json", "JSON", "code-json", "", "", ""); + + sendHomeAssistantDiscoveryTopic(maintopic, (*NUMBERS)[i]->name, "problem", "Problem", "alert-outline", "", "", ""); // Special binary sensor which is based on error topic + } +} + +void publishRuntimeData(std::string maintopic, int SetRetainFlag) { + char tmp_char[50]; + + sprintf(tmp_char, "%ld", (long)getUpTime()); + MQTTPublish(maintopic + "/" + "uptime", std::string(tmp_char), SetRetainFlag); + + sprintf(tmp_char, "%zu", esp_get_free_heap_size()); + MQTTPublish(maintopic + "/" + "freeMem", std::string(tmp_char), SetRetainFlag); + + sprintf(tmp_char, "%d", get_WIFI_RSSI()); + MQTTPublish(maintopic + "/" + "wifiRSSI", std::string(tmp_char), SetRetainFlag); + + sprintf(tmp_char, "%d", (int)temperatureRead()); + MQTTPublish(maintopic + "/" + "CPUtemp", std::string(tmp_char), SetRetainFlag); +} + +void GotConnected(std::string maintopic, int SetRetainFlag) { + if (HomeassistantDiscovery) { + MQTThomeassistantDiscovery(maintopic); + } + + MQTTPublish(maintopic + "/" + "MAC", getMac(), SetRetainFlag); + MQTTPublish(maintopic + "/" + "IP", *getIPAddress(), SetRetainFlag); + MQTTPublish(maintopic + "/" + "hostname", hostname, SetRetainFlag); + + publishRuntimeData(maintopic, SetRetainFlag); +} + + + void ClassFlowMQTT::SetInitialParameter(void) { uri = ""; @@ -21,22 +172,22 @@ void ClassFlowMQTT::SetInitialParameter(void) topicError = ""; topicRate = ""; topicTimeStamp = ""; - maintopic = ""; - mainerrortopic = ""; + maintopic = hostname; topicUptime = ""; topicFreeMem = ""; - clientname = "watermeter"; + + clientname = "AIOTED-" + getMac(); + OldValue = ""; flowpostprocessing = NULL; user = ""; password = ""; - SetRetainFlag = 0; + SetRetainFlag = 0; previousElement = NULL; ListFlowControll = NULL; disabled = false; - MQTTenable = false; - keepAlive = 600; // TODO This must be greater than the Flow Interval! + keepAlive = 25*60; } ClassFlowMQTT::ClassFlowMQTT() @@ -51,11 +202,23 @@ ClassFlowMQTT::ClassFlowMQTT(std::vector* lfc) ListFlowControll = lfc; for (int i = 0; i < ListFlowControll->size(); ++i) { + // ESP_LOGW(TAG, "LCF: %s", ((*ListFlowControll)[i])->name().c_str()); + if (((*ListFlowControll)[i])->name().compare("ClassFlowPostProcessing") == 0) { flowpostprocessing = (ClassFlowPostProcessing*) (*ListFlowControll)[i]; } + +// TODO this does not work since ClassFlowControll is not in the list! + /* if (((*ListFlowControll)[i])->name().compare("ClassFlowControll") == 0) + { + ClassFlowControll *cfc = (ClassFlowControll*) (*ListFlowControll)[i]; + this->keepAlive = cfc->getAutoInterval()* 2.5; // Allow at least than 2 failed rounds before we are threated as disconnected + ESP_LOGW(TAG, "KEEPALIVE: %d", this->keepAlive); + }*/ } + + NUMBERS = flowpostprocessing->GetNumbers(); } ClassFlowMQTT::ClassFlowMQTT(std::vector* lfc, ClassFlow *_prev) @@ -108,7 +271,11 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph) if (toUpper(zerlegt[1]) == "TRUE") SetRetainFlag = 1; } - + if ((toUpper(zerlegt[0]) == "HOMEASSISTANTDISCOVERY") && (zerlegt.size() > 1)) + { + if (toUpper(zerlegt[1]) == "TRUE") + HomeassistantDiscovery = true; + } if ((toUpper(zerlegt[0]) == "CLIENTID") && (zerlegt.size() > 1)) { @@ -121,65 +288,13 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph) } } -#ifdef __HIDE_PASSWORD - ESP_LOGD(TAG, "Init Read with uri: %s, clientname: %s, user: %s, password: XXXXXX, maintopic: %s", uri.c_str(), clientname.c_str(), user.c_str(), mainerrortopic.c_str()); -#else - ESP_LOGD(TAG, "Init Read with uri: %s, clientname: %s, user: %s, password: %s, maintopic: %s", uri.c_str(), clientname.c_str(), user.c_str(), password.c_str(), mainerrortopic.c_str()); -#endif + MQTT_Configure(uri, clientname, user, password, maintopic, LWT_TOPIC, LWT_CONNECTED, LWT_DISCONNECTED, keepAlive, SetRetainFlag, (void *)&GotConnected); - if (!MQTTisConnected() && (uri.length() > 0) && (maintopic.length() > 0)) - { - ESP_LOGD(TAG, "InitMQTTInit"); - mainerrortopic = maintopic + "/connection"; -#ifdef __HIDE_PASSWORD - ESP_LOGD(TAG, "Init MQTT with uri: %s, clientname: %s, user: %s, password: XXXXXXXX, maintopic: %s", uri.c_str(), clientname.c_str(), user.c_str(), mainerrortopic.c_str()); -#else - ESP_LOGD(TAG, "Init MQTT with uri: %s, clientname: %s, user: %s, password: %s, maintopic: %s", uri.c_str(), clientname.c_str(), user.c_str(), password.c_str(), mainerrortopic.c_str()); -#endif - if (!MQTTInit(uri, clientname, user, password, mainerrortopic, keepAlive)) - { // Failed - MQTTenable = false; - return true; // We need to return true despite we failed, else it will retry 5x and then reboot! + if (!MQTT_Init()) { + if (!MQTT_Init()) { // Retry + return false; } } - - // Try sending mainerrortopic. If it fails, re-run init - if (!MQTTPublish(mainerrortopic, "connected", SetRetainFlag)) - { // Failed - LogFile.WriteToFile(ESP_LOG_WARN, "MQTT - Re-running init...!"); - if (!MQTTInit(this->uri, this->clientname, this->user, this->password, this->mainerrortopic, keepAlive)) - { // Failed - MQTTenable = false; - return false; - } - } - - // Try again and quit if it fails - if (!MQTTPublish(mainerrortopic, "connected", SetRetainFlag)) - { // Failed - MQTTenable = false; - return false; - } - - - - - /* if (!MQTTPublish(mainerrortopic, "connected", SetRetainFlag)) - { // Failed - LogFile.WriteToFile(ESP_LOG_ERROR, "MQTT - Could not publish connection status!"); - MQTTenable = false; - return true; // We need to return true despite we failed, else it will retry 5x and then reboot! - }*/ - - /* if(!MQTTPublish(_LWTContext, "", 1)) - { - LogFile.WriteToFile(ESP_LOG_ERROR, "MQTT - Could not publish LWT!"); - MQTTenable = false; - return true; // We need to return true despite we failed, else it will retry 5x and then reboot! - }*/ - - - MQTTenable = true; return true; } @@ -192,24 +307,6 @@ string ClassFlowMQTT::GetMQTTMainTopic() bool ClassFlowMQTT::doFlow(string zwtime) { - // Try sending mainerrortopic. If it fails, re-run init - if (!MQTTPublish(mainerrortopic, "connected", SetRetainFlag)) - { // Failed - LogFile.WriteToFile(ESP_LOG_WARN, "MQTT - Re-running init...!"); - if (!MQTTInit(this->uri, this->clientname, this->user, this->password, this->mainerrortopic, keepAlive)) - { // Failed - MQTTenable = false; - return true; // We need to return true despite we failed, else it will retry 5x and then reboot! - } - } - - // Try again and quit if it fails - if (!MQTTPublish(mainerrortopic, "connected", SetRetainFlag)) - { // Failed - MQTTenable = false; - return true; // We need to return true despite we failed, else it will retry 5x and then reboot! - } - std::string result; std::string resulterror = ""; std::string resultraw = ""; @@ -219,32 +316,7 @@ bool ClassFlowMQTT::doFlow(string zwtime) string zw = ""; string namenumber = ""; - // if (!MQTTPublish(mainerrortopic, "connected", SetRetainFlag)) - //{ // Failed, skip other topics - // return true; // We need to return true despite we failed, else it will retry 5x and then reboot! - //} - - zw = maintopic + "/" + "uptime"; - char uptimeStr[11]; - sprintf(uptimeStr, "%ld", (long)getUpTime()); - MQTTPublish(zw, uptimeStr, SetRetainFlag); - - zw = maintopic + "/" + "freeMem"; - char freeheapmem[11]; - sprintf(freeheapmem, "%zu", esp_get_free_heap_size()); - if (!MQTTPublish(zw, freeheapmem, SetRetainFlag)) - { // Failed, skip other topics - return true; // We need to return true despite we failed, else it will retry 5x and then reboot! - } - - zw = maintopic + "/" + "wifiRSSI"; - char rssi[11]; - sprintf(rssi, "%d", get_WIFI_RSSI()); - MQTTPublish(zw, rssi, SetRetainFlag); - - zw = maintopic + "/" + "CPUtemp"; - std::string cputemp = std::to_string(temperatureRead()); - MQTTPublish(zw, cputemp, SetRetainFlag); + publishRuntimeData(maintopic, SetRetainFlag); if (flowpostprocessing) { @@ -265,29 +337,23 @@ bool ClassFlowMQTT::doFlow(string zwtime) else namenumber = maintopic + "/" + namenumber + "/"; - zw = namenumber + "value"; if (result.length() > 0) - MQTTPublish(zw, result, SetRetainFlag); + MQTTPublish(namenumber + "value", result, SetRetainFlag); - zw = namenumber + "error"; if (resulterror.length() > 0) - MQTTPublish(zw, resulterror, SetRetainFlag); + MQTTPublish(namenumber + "error", resulterror, SetRetainFlag); - zw = namenumber + "rate"; if (resultrate.length() > 0) - MQTTPublish(zw, resultrate, SetRetainFlag); + MQTTPublish(namenumber + "rate", resultrate, SetRetainFlag); - zw = namenumber + "changeabsolut"; if (resultchangabs.length() > 0) - MQTTPublish(zw, resultchangabs, SetRetainFlag); + MQTTPublish(namenumber + "changeabsolut", resultchangabs, SetRetainFlag); - zw = namenumber + "raw"; if (resultraw.length() > 0) - MQTTPublish(zw, resultraw, SetRetainFlag); + MQTTPublish(namenumber + "raw", resultraw, SetRetainFlag); - zw = namenumber + "timestamp"; if (resulttimestamp.length() > 0) - MQTTPublish(zw, resulttimestamp, SetRetainFlag); + MQTTPublish(namenumber + "timestamp", resulttimestamp, SetRetainFlag); std::string json = ""; @@ -305,8 +371,7 @@ bool ClassFlowMQTT::doFlow(string zwtime) json += "\",\"rate\":\"\""; json += ",\"timestamp\":\""+resulttimestamp+"\"}"; - zw = namenumber + "json"; - MQTTPublish(zw, json, SetRetainFlag); + MQTTPublish(namenumber + "json", json, SetRetainFlag); } } else diff --git a/code/components/jomjol_flowcontroll/ClassFlowMQTT.h b/code/components/jomjol_flowcontroll/ClassFlowMQTT.h index 3a990c7d..62e07d52 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowMQTT.h +++ b/code/components/jomjol_flowcontroll/ClassFlowMQTT.h @@ -14,10 +14,9 @@ protected: ClassFlowPostProcessing* flowpostprocessing; std::string user, password; int SetRetainFlag; - bool MQTTenable; int keepAlive; - std::string maintopic, mainerrortopic; + std::string maintopic; void SetInitialParameter(void); public: diff --git a/code/components/jomjol_logfile/ClassLogFile.cpp b/code/components/jomjol_logfile/ClassLogFile.cpp index 05667514..d866eb53 100644 --- a/code/components/jomjol_logfile/ClassLogFile.cpp +++ b/code/components/jomjol_logfile/ClassLogFile.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -206,6 +207,8 @@ void ClassLogFile::WriteToFile(esp_log_level_t level, std::string info, bool _ti strftime(buffer, 30, logfile.c_str(), timeinfo); std::string logpath = logroot + "/" + buffer; + std::replace(info.begin(), info.end(), '\n', ' '); // Replace all newline characters + WriteToDedicatedFile(logpath, level, info, _time); ESP_LOG_LEVEL(level, TAG, "%s", info.c_str()); } diff --git a/code/components/jomjol_mqtt/interface_mqtt.cpp b/code/components/jomjol_mqtt/interface_mqtt.cpp index 9714f158..1f30d525 100644 --- a/code/components/jomjol_mqtt/interface_mqtt.cpp +++ b/code/components/jomjol_mqtt/interface_mqtt.cpp @@ -12,25 +12,51 @@ static const char *TAG_INTERFACEMQTT = "interface_mqtt"; std::map>* connectFunktionMap = NULL; std::map>* subscribeFunktionMap = NULL; -// #define CONFIG_BROKER_URL "mqtt://192.168.178.43:1883" esp_mqtt_event_id_t esp_mmqtt_ID = MQTT_EVENT_ANY; // ESP_EVENT_ANY_ID bool mqtt_connected = false; esp_mqtt_client_handle_t client = NULL; +std::string uri, client_id, lwt_topic, lwt_connected, lwt_disconnected, user, password, maintopic; +int keepalive, SetRetainFlag; +void (*callbackOnConnected)(std::string, int) = NULL; -bool MQTTPublish(std::string _key, std::string _content, int retained_flag){ - + +bool MQTTPublish(std::string _key, std::string _content, int retained_flag) { int msg_id; std::string zw; + + if (!mqtt_connected) { + LogFile.WriteToFile(ESP_LOG_WARN, "MQTT - Not connected, trying to re-connect..."); + if (!MQTT_Init()) { + if (!MQTT_Init()) { // Retry + LogFile.WriteToFile(ESP_LOG_ERROR, "MQTT - Failed to init!"); + return false; + } + } + } + msg_id = esp_mqtt_client_publish(client, _key.c_str(), _content.c_str(), 0, 1, retained_flag); if (msg_id < 0) { - LogFile.WriteToFile(ESP_LOG_ERROR, "MQTT - Failed to publish '" + _key + "'!"); - return false; + LogFile.WriteToFile(ESP_LOG_WARN, "MQTT - Failed to publish topic '" + _key + "', re-trying..."); + + msg_id = esp_mqtt_client_publish(client, _key.c_str(), _content.c_str(), 0, 1, retained_flag); + if (msg_id < 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, "MQTT - Failed to publish topic '" + _key + "'!"); + mqtt_connected = false; // Force re-init on next call + return false; + } } - zw = "MQTT - sent publish successful in MQTTPublish, msg_id=" + std::to_string(msg_id) + ", " + _key + ", " + _content; - LogFile.WriteToFile(ESP_LOG_INFO, zw); + + if (_content.length() > 80) { // Truncate message if too long + _content.resize(80); + _content.append(".."); + } + + zw = "MQTT - Published topic: " + _key + ", content: " + _content + " (msg_id=" + std::to_string(msg_id) + ")"; + LogFile.WriteToFile(ESP_LOG_DEBUG, zw); + return true; } @@ -50,6 +76,7 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) break; case MQTT_EVENT_DISCONNECTED: ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_DISCONNECTED"); + mqtt_connected = false; // Force re-init on next call esp_mqtt_client_reconnect(client); break; case MQTT_EVENT_SUBSCRIBED: @@ -79,6 +106,7 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) break; case MQTT_EVENT_ERROR: ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_ERROR"); + mqtt_connected = false; // Force re-init on next call break; default: ESP_LOGI(TAG_INTERFACEMQTT, "Other event id:%d", event->event_id); @@ -93,58 +121,81 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_ } -bool MQTTInit(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password, std::string _LWTContext, int _keepalive){ - std::string _zwmessage = "connection lost"; +void MQTT_Configure(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password, + std::string _maintopic, std::string _lwt, std::string _lwt_connected, std::string _lwt_disconnected, + int _keepalive, int _SetRetainFlag, void *_callbackOnConnected){ +#ifdef __HIDE_PASSWORD + LogFile.WriteToFile(ESP_LOG_INFO, "MQTT Configuration: uri: " + _mqttURI + ", clientname: " + _clientid + + ", user: " + _user + ", password: XXXXXXXX, maintopic: " + _maintopic + ", last-will-topic: " + _maintopic + "/" + _lwt + ", keepAlive: " + std::to_string(_keepalive)); +#else + LogFile.WriteToFile(ESP_LOG_INFO, "MQTT Configuration: uri: " + _mqttURI + ", clientname: " + _clientid + + ", user: " + _user + ", password: " + _password + ", maintopic: " + _maintopic + ", last-will-topic: " + _maintopic + "/" + _lwt + ", keepAlive: " + std::to_string(_keepalive)); +#endif - int _lzw = _zwmessage.length(); - - esp_mqtt_client_config_t mqtt_cfg = { - .uri = _mqttURI.c_str(), - .client_id = _clientid.c_str(), - .lwt_topic = _LWTContext.c_str(), - .lwt_msg = _zwmessage.c_str(), - .lwt_retain = 1, - .lwt_msg_len = _lzw, - .keepalive = _keepalive - }; - - LogFile.WriteToFile(ESP_LOG_INFO, "MQTT - Init"); + uri = _mqttURI; + client_id = _clientid; + lwt_topic = _maintopic + "/" + _lwt; + lwt_connected = _lwt_connected; + lwt_disconnected = _lwt_disconnected; + keepalive = _keepalive; + SetRetainFlag = _SetRetainFlag; + maintopic = _maintopic; + callbackOnConnected = ( void (*)(std::string, int) )(_callbackOnConnected); if (_user.length() && _password.length()){ - mqtt_cfg.username = _user.c_str(); - mqtt_cfg.password = _password.c_str(); + user = _user; + password = _password; + } +} -#ifdef __HIDE_PASSWORD - ESP_LOGI(TAG_INTERFACEMQTT, "Connect to MQTT: %s, XXXXXXXX", mqtt_cfg.username); -#else - ESP_LOGI(TAG_INTERFACEMQTT, "Connect to MQTT: %s, %s", mqtt_cfg.username, mqtt_cfg.password); -#endif +bool MQTT_Init() { + esp_err_t ret; + LogFile.WriteToFile(ESP_LOG_INFO, "MQTT - Init"); + + MQTTdestroy_client(); + + std::string lw = lwt_disconnected; + + esp_mqtt_client_config_t mqtt_cfg = { + .uri = uri.c_str(), + .client_id = client_id.c_str(), + .lwt_topic = lwt_topic.c_str(), + .lwt_msg = lw.c_str(), + .lwt_retain = 1, + .lwt_msg_len = (int)(lw.length()), + .keepalive = keepalive + }; + + if (user.length() && password.length()){ + mqtt_cfg.username = user.c_str(); + mqtt_cfg.password = password.c_str(); }; - MQTTdestroy(); client = esp_mqtt_client_init(&mqtt_cfg); if (client) { - if (esp_mqtt_client_register_event(client, esp_mmqtt_ID, mqtt_event_handler, client) != ESP_OK) + ret = esp_mqtt_client_register_event(client, esp_mmqtt_ID, mqtt_event_handler, client); + if (ret != ESP_OK) { - LogFile.WriteToFile(ESP_LOG_ERROR, "MQTT - Could not register event!"); - return false; - } - if (esp_mqtt_client_start(client) != ESP_OK) - { - LogFile.WriteToFile(ESP_LOG_ERROR, "MQTT - Could not start client!"); + LogFile.WriteToFile(ESP_LOG_ERROR, "MQTT - Could not register event (ret=" + std::to_string(ret) + ")!"); return false; } - /* if(!MQTTPublish(_LWTContext, "", 1)) + ret = esp_mqtt_client_start(client); + if (ret != ESP_OK) { - LogFile.WriteToFile(ESP_LOG_ERROR, "MQTT - Could not publish LWT!"); - return false; - }*/ + LogFile.WriteToFile(ESP_LOG_WARN, "MQTT - Could not start client (ret=" + std::to_string(ret) + "), retrying..."); + ret = esp_mqtt_client_start(client); + if (ret != ESP_OK) + { + LogFile.WriteToFile(ESP_LOG_ERROR, "MQTT - Could not start client (ret=" + std::to_string(ret) + ")!"); + return false; + } + } } else { - LogFile.WriteToFile(ESP_LOG_ERROR, "MQTT - Could not Init client!"); + LogFile.WriteToFile(ESP_LOG_ERROR, "MQTT - Could not init client!"); return false; } @@ -153,7 +204,7 @@ bool MQTTInit(std::string _mqttURI, std::string _clientid, std::string _user, st } -void MQTTdestroy() { +void MQTTdestroy_client() { if (client != NULL) { esp_mqtt_client_stop(client); esp_mqtt_client_destroy(client); @@ -211,6 +262,9 @@ void MQTTregisterSubscribeFunction(std::string topic, std::function>::iterator it = connectFunktionMap->begin(); it != connectFunktionMap->end(); ++it) { it->second(); @@ -224,6 +278,10 @@ void MQTTconnected(){ LogFile.WriteToFile(ESP_LOG_INFO, "MQTT - topic " + it->first + " subscribe successful, msg_id=" + std::to_string(msg_id)); } } + + if (callbackOnConnected) { + callbackOnConnected(maintopic, SetRetainFlag); + } } } @@ -240,4 +298,4 @@ void MQTTdestroySubscribeFunction(){ delete subscribeFunktionMap; subscribeFunktionMap = NULL; } -} \ No newline at end of file +} diff --git a/code/components/jomjol_mqtt/interface_mqtt.h b/code/components/jomjol_mqtt/interface_mqtt.h index 6e9ae85e..63d513a8 100644 --- a/code/components/jomjol_mqtt/interface_mqtt.h +++ b/code/components/jomjol_mqtt/interface_mqtt.h @@ -5,8 +5,11 @@ #include #include -bool MQTTInit(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password, std::string _LWTContext, int _keepalive); -void MQTTdestroy(); +void MQTT_Configure(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password, + std::string _maintopic, std::string _lwt, std::string _lwt_connected, std::string _lwt_disconnected, + int _keepalive, int SetRetainFlag, void *callbackOnConnected); +bool MQTT_Init(); +void MQTTdestroy_client(); bool MQTTPublish(std::string _key, std::string _content, int retained_flag = 1); // retained Flag as Standart diff --git a/sd-card/html/edit_config_param.html b/sd-card/html/edit_config_param.html index ac6b5a46..b58d23dd 100644 --- a/sd-card/html/edit_config_param.html +++ b/sd-card/html/edit_config_param.html @@ -625,7 +625,23 @@ textarea { Enable or disable the retain flag for all MQTT entries - + + + + + + + + + + Enable or disable the Homeassistand Discovery + + + +

@@ -1715,6 +1731,7 @@ function UpdateInput() { WriteParameter(param, category, "MQTT", "user", true); WriteParameter(param, category, "MQTT", "password", true); WriteParameter(param, category, "MQTT", "SetRetainFlag", true); + WriteParameter(param, category, "MQTT", "HomeassistantDiscovery", true); WriteParameter(param, category, "InfluxDB", "Uri", true); WriteParameter(param, category, "InfluxDB", "Database", true); @@ -1831,6 +1848,7 @@ function ReadParameterAll() ReadParameter(param, "MQTT", "user", true); ReadParameter(param, "MQTT", "password", true); ReadParameter(param, "MQTT", "SetRetainFlag", true); + ReadParameter(param, "MQTT", "HomeassistantDiscovery", true); ReadParameter(param, "InfluxDB", "Uri", true); ReadParameter(param, "InfluxDB", "Database", true); diff --git a/sd-card/html/readconfigparam.js b/sd-card/html/readconfigparam.js index ffacacf8..60c57ba9 100644 --- a/sd-card/html/readconfigparam.js +++ b/sd-card/html/readconfigparam.js @@ -187,6 +187,7 @@ function ParseConfig() { ParamAddValue(param, catname, "user"); ParamAddValue(param, catname, "password"); ParamAddValue(param, catname, "SetRetainFlag"); + ParamAddValue(param, catname, "HomeassistantDiscovery"); var catname = "InfluxDB"; category[catname] = new Object();