diff --git a/src/CHANGES.md b/src/CHANGES.md index 714dc8cc..f39a5640 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.81 - 2024-02-13 +* fixed authentication with empty token #1415 +* added new setting for future function to send log via MqTT +* combined firmware and hardware version to JSON topics (MqTT) #1212 + ## 0.8.80 - 2024-02-12 * optimize API authentication, Error-Codes #1415 * breaking change: authentication API command changed #1415 diff --git a/src/config/settings.h b/src/config/settings.h index 0cb9ed4e..18725b48 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -31,7 +31,7 @@ * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ -#define CONFIG_VERSION 10 +#define CONFIG_VERSION 11 #define PROT_MASK_INDEX 0x0001 @@ -120,6 +120,7 @@ typedef struct { bool debug; bool privacyLog; bool printWholeTrace; + bool log2mqtt; } cfgSerial_t; typedef struct { @@ -436,6 +437,7 @@ class settings { mCfg.serial.debug = false; mCfg.serial.privacyLog = true; mCfg.serial.printWholeTrace = false; + mCfg.serial.log2mqtt = false; mCfg.mqtt.port = DEF_MQTT_PORT; snprintf(mCfg.mqtt.broker, MQTT_ADDR_LEN, "%s", DEF_MQTT_BROKER); @@ -509,6 +511,9 @@ class settings { mCfg.sys.region = 0; // Europe mCfg.sys.timezone = 1; } + if(mCfg.configVersion < 11) { + mCfg.serial.log2mqtt = false; + } } } @@ -658,11 +663,13 @@ class settings { obj[F("debug")] = mCfg.serial.debug; obj[F("prv")] = (bool) mCfg.serial.privacyLog; obj[F("trc")] = (bool) mCfg.serial.printWholeTrace; + obj[F("mqtt")] = (bool) mCfg.serial.log2mqtt; } else { getVal(obj, F("show"), &mCfg.serial.showIv); getVal(obj, F("debug"), &mCfg.serial.debug); getVal(obj, F("prv"), &mCfg.serial.privacyLog); getVal(obj, F("trc"), &mCfg.serial.printWholeTrace); + getVal(obj, F("mqtt"), &mCfg.serial.log2mqtt); } } diff --git a/src/defines.h b/src/defines.h index 8913db5e..200c2561 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 80 +#define VERSION_PATCH 81 //------------------------------------- typedef struct { diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 06f8e629..c430da85 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -6,6 +6,7 @@ #ifndef __PUB_MQTT_IV_DATA_H__ #define __PUB_MQTT_IV_DATA_H__ +#include #include "../utils/dbg.h" #include "../hm/hmSystem.h" #include "pubMqttDefs.h" @@ -107,14 +108,14 @@ class PubMqttIvData { if(found) { record_t<> *rec = mIv->getRecordStruct(mCmd); if(MqttSentStatus::NEW_DATA == rec->mqttSentStatus) { - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/last_success", mIv->config->name); - snprintf(mVal, 40, "%d", mIv->getLastTs(rec)); - mPublish(mSubTopic, mVal, true, QOS_0); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/last_success", mIv->config->name); + snprintf(mVal.data(), mVal.size(), "%d", mIv->getLastTs(rec)); + mPublish(mSubTopic.data(), mVal.data(), true, QOS_0); if((mIv->ivGen == IV_HMS) || (mIv->ivGen == IV_HMT)) { - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/ch0/rssi", mIv->config->name); - snprintf(mVal, 40, "%d", mIv->rssi); - mPublish(mSubTopic, mVal, false, QOS_0); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch0/rssi", mIv->config->name); + snprintf(mVal.data(), mVal.size(), "%d", mIv->rssi); + mPublish(mSubTopic.data(), mVal.data(), false, QOS_0); } rec->mqttSentStatus = MqttSentStatus::LAST_SUCCESS_SENT; } @@ -144,7 +145,7 @@ class PubMqttIvData { if(mPos < rec->length) { bool retained = false; - if (mCmd == RealTimeRunData_Debug) { + if (RealTimeRunData_Debug == mCmd) { if((FLD_YT == rec->assign[mPos].fieldId) || (FLD_YD == rec->assign[mPos].fieldId)) retained = true; @@ -176,10 +177,32 @@ class PubMqttIvData { } if (MqttSentStatus::LAST_SUCCESS_SENT == rec->mqttSentStatus) { + if(InverterDevInform_All == mCmd) { + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/firmware", mIv->config->name); + snprintf(mVal.data(), mVal.size(), "{\"version\":%d,\"build_year\":\"%s\",\"build_month_day\":%d,\"build_hour_min\":%d,\"bootloader\":%d}", + mIv->getChannelFieldValue(CH0, FLD_FW_VERSION, rec), + mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_YEAR, rec), + mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_MONTH_DAY, rec), + mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec), + mIv->getChannelFieldValue(CH0, FLD_BOOTLOADER_VER, rec)); + retained = true; + } else if(InverterDevInform_Simple == mCmd) { + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/hardware", mIv->config->name); + snprintf(mVal.data(), mVal.size(), "{\"part\":%d,\"version\":\"%s\",\"grid_profile_code\":%d,\"grid_profile_version\":%d}", + mIv->getChannelFieldValue(CH0, FLD_PART_NUM, rec), + mIv->getChannelFieldValue(CH0, FLD_HW_VERSION, rec), + mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec), + mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_VERSION, rec)); + retained = true; + } else { + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d/%s", mIv->config->name, rec->assign[mPos].ch, fields[rec->assign[mPos].fieldId]); + snprintf(mVal.data(), mVal.size(), "%g", ah::round3(mIv->getValue(mPos, rec))); + } + uint8_t qos = (FLD_ACT_ACTIVE_PWR_LIMIT == rec->assign[mPos].fieldId) ? QOS_2 : QOS_0; - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", mIv->config->name, rec->assign[mPos].ch, fields[rec->assign[mPos].fieldId]); - snprintf(mVal, 40, "%g", ah::round3(mIv->getValue(mPos, rec))); - mPublish(mSubTopic, mVal, retained, qos); + if((FLD_EVT != rec->assign[mPos].fieldId) + && (FLD_LAST_ALARM_CODE != rec->assign[mPos].fieldId)) + mPublish(mSubTopic.data(), mVal.data(), retained, qos); } mPos++; } else { @@ -192,8 +215,8 @@ class PubMqttIvData { } inline void sendRadioStat(uint8_t start) { - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/radio_stat", mIv->config->name); - snprintf(mVal, 140, "{\"tx\":%d,\"success\":%d,\"fail\":%d,\"no_answer\":%d,\"retransmits\":%d,\"lossIvRx\":%d,\"lossIvTx\":%d,\"lossDtuRx\":%d,\"lossDtuTx\":%d}", + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/radio_stat", mIv->config->name); + snprintf(mVal.data(), mVal.size(), "{\"tx\":%d,\"success\":%d,\"fail\":%d,\"no_answer\":%d,\"retransmits\":%d,\"lossIvRx\":%d,\"lossIvTx\":%d,\"lossDtuRx\":%d,\"lossDtuTx\":%d}", mIv->radioStatistics.txCnt, mIv->radioStatistics.rxSuccess, mIv->radioStatistics.rxFail, @@ -203,7 +226,7 @@ class PubMqttIvData { mIv->radioStatistics.ivSent, mIv->radioStatistics.dtuLoss, mIv->radioStatistics.dtuSent); - mPublish(mSubTopic, mVal, false, QOS_0); + mPublish(mSubTopic.data(), mVal.data(), false, QOS_0); } void stateSendTotals() { @@ -240,9 +263,9 @@ class PubMqttIvData { retained = false; break; } - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "total/%s", fields[fieldId]); - snprintf(mVal, 40, "%g", ah::round3(mTotal[mPos])); - mPublish(mSubTopic, mVal, retained, QOS_0); + snprintf(mSubTopic.data(), mSubTopic.size(), "total/%s", fields[fieldId]); + snprintf(mVal.data(), mVal.size(), "%g", ah::round3(mTotal[mPos])); + mPublish(mSubTopic.data(), mVal.data(), retained, QOS_0); mPos++; } else { mSendList->pop(); @@ -266,8 +289,8 @@ class PubMqttIvData { uint8_t mPos = 0; bool mRTRDataHasBeenSent = false; - char mSubTopic[32 + MAX_NAME_LENGTH + 1]; - char mVal[140]; + std::array mSubTopic; + std::array mVal; std::queue *mSendList = nullptr; }; diff --git a/src/web/Protection.h b/src/web/Protection.h index 82e4be49..74f04b52 100644 --- a/src/web/Protection.h +++ b/src/web/Protection.h @@ -85,7 +85,7 @@ class Protection { if(isIdentical(clientIp, mApiIp)) return (0 != strncmp(token, mToken.data(), 16)); - return false; + return true; } private: diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 37e988c0..09bba06e 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -680,6 +680,7 @@ class RestApi { obj[F("debug")] = mConfig->serial.debug; obj[F("priv")] = mConfig->serial.privacyLog; obj[F("wholeTrace")] = mConfig->serial.printWholeTrace; + obj[F("log2mqtt")] = mConfig->serial.log2mqtt; } void getStaticIp(JsonObject obj) { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 4859fe34..47d935b9 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -43,24 +43,8 @@
-
+
{#SERIAL_CONSOLE} -
-
{#LOG_PRINT_INVERTER_DATA}
-
-
-
-
{#LOG_SERIAL_DEBUG}
-
-
-
-
{#LOG_PRIVACY_MODE}
-
-
-
-
{#LOG_PRINT_TRACES}
-
-
@@ -716,6 +700,13 @@ ivGlob(obj); } + function divRow(item0, item1) { + return ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-3 mt-2"}, item0), + ml("div", {class: "col-9"}, item1) + ]) + } + function ivModal(obj) { var lines = []; lines.push(ml("tr", {}, [ @@ -743,43 +734,23 @@ var html = ml("div", {}, [ tabs(["{#TAB_GENERAL}", "{#TAB_INPUTS}", "{#TAB_RADIO}", "{#TAB_ADVANCED}"]), ml("div", {id: "div{#TAB_GENERAL}", class: "tab-content"}, [ - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-2"}, "{#INV_ENABLE}"), - ml("div", {class: "col-10"}, cbEn) - ]), - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-2 mt-2"}, "{#INV_SERIAL}"), - ml("div", {class: "col-10"}, ser) - ]), - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-2 mt-2"}, "Name"), - ml("div", {class: "col-10"}, ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)) - ]) + divRow("{#INV_ENABLE}", cbEn), + divRow("{#INV_SERIAL}", ser), + divRow("Name", ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)) ]), ml("div", {id: "div{#TAB_INPUTS}", class: "tab-content hide"}, [ ml("div", {class: "row mb-3"}, - ml("table", {class: "table"}, - ml("tbody", {}, lines) - ) + ml("table", {class: "table"}, ml("tbody", {}, lines)) ) ]), ml("div", {id: "div{#TAB_RADIO}", class: "tab-content hide"}, [ ml("input", {type: "hidden", name: "isnrf"}, null), ml("div", {id: "setcmt"}, [ - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-3 mt-2"}, "{#INV_FREQUENCY}"), - ml("div", {class: "col-9"}, sel("freq", esp32cmtFreq, obj.freq)) - ]), - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-3 mt-2"}, "{#INV_POWER_LEVEL}"), - ml("div", {class: "col-9"}, sel("cmtpa", esp32cmtPa, obj.pa)) - ]), + divRow("{#INV_FREQUENCY}", sel("freq", esp32cmtFreq, obj.freq)), + divRow("{#INV_POWER_LEVEL}", sel("cmtpa", esp32cmtPa, obj.pa)) ]), ml("div", {id: "setnrf"}, - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-3 mt-2"}, "{#INV_POWER_LEVEL}"), - ml("div", {class: "col-9"}, sel("nrfpa", nrfPa, obj.pa)) - ]), + divRow("{#INV_POWER_LEVEL}", sel("nrfpa", nrfPa, obj.pa)) ), ]), ml("div", {id: "div{#TAB_ADVANCED}", class: "tab-content hide"}, [ @@ -1026,8 +997,18 @@ /*ENDIF_ESP32*/ function parseSerial(obj) { - for(var i of [["serEn", "show_live_data"], ["serDbg", "debug"], ["priv", "priv"], ["wholeTrace", "wholeTrace"]]) - document.getElementsByName(i[0])[0].checked = obj[i[1]]; + var e = document.getElementById("serialCb") + var l = [["serEn", "show_live_data", "{#LOG_PRINT_INVERTER_DATA}"], ["serDbg", "debug", "{#LOG_SERIAL_DEBUG}"], ["priv", "priv", "{#LOG_PRIVACY_MODE}"], ["wholeTrace", "wholeTrace", "{#LOG_PRINT_TRACES}"], ["log2mqtt", "log2mqtt", "{#LOG_TO_MQTT}"]] + for(var i of l) { + var cb = ml("input", {name: i[0], type: "checkbox"}, null) + cb.checked = obj[i[1]] + e.appendChild( + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-8 col-sm-3"}, i[2]), + ml("div", {class: "col-4 col-sm-9"}, cb) + ]) + ) + } } function parseDisplay(obj, type, system) { diff --git a/src/web/lang.json b/src/web/lang.json index 335f0d2a..066370c5 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -203,6 +203,11 @@ "en": "Print whole traces in Log", "de": "alle Informationen in Log schreiben" }, + { + "token": "LOG_TO_MQTT", + "en": "Send Serial debug over MqTT", + "de": "sende serielles Log über MqTT" + }, { "token": "NETWORK", "en": "Network", diff --git a/src/web/web.h b/src/web/web.h index 692dd779..8495ba23 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -552,6 +552,7 @@ class Web { mConfig->serial.privacyLog = (request->arg("priv") == "on"); mConfig->serial.printWholeTrace = (request->arg("wholeTrace") == "on"); mConfig->serial.showIv = (request->arg("serEn") == "on"); + mConfig->serial.log2mqtt = (request->arg("log2mqtt") == "on"); // display mConfig->plugin.display.pwrSaveAtIvOffline = (request->arg("disp_pwr") == "on");