diff --git a/scripts/__pycache__/htmlPreprocessorDefines.cpython-311.pyc b/scripts/__pycache__/htmlPreprocessorDefines.cpython-311.pyc
new file mode 100644
index 00000000..8b8e3440
Binary files /dev/null and b/scripts/__pycache__/htmlPreprocessorDefines.cpython-311.pyc differ
diff --git a/src/app.h b/src/app.h
index 634696f2..12d03d0b 100644
--- a/src/app.h
+++ b/src/app.h
@@ -239,6 +239,14 @@ class app : public IApp, public ah::Scheduler {
#endif
}
+ bool getMqttJsonEnabled() override {
+ #if defined(ENABLE_MQTT)
+ return mMqtt.isJson();
+ #else
+ return 0;
+ #endif
+ }
+
uint32_t getMqttTxCnt() override {
#if defined(ENABLE_MQTT)
return mMqtt.getTxCnt();
diff --git a/src/appInterface.h b/src/appInterface.h
index f2292ec8..92fade46 100644
--- a/src/appInterface.h
+++ b/src/appInterface.h
@@ -52,6 +52,7 @@ class IApp {
virtual bool getSettingsValid() = 0;
virtual void setMqttDiscoveryFlag() = 0;
virtual bool getMqttIsConnected() = 0;
+ virtual bool getMqttJsonEnabled() = 0;
virtual bool getNrfEnabled() = 0;
virtual bool getCmtEnabled() = 0;
diff --git a/src/config/settings.h b/src/config/settings.h
index 25243fe7..d10f641b 100644
--- a/src/config/settings.h
+++ b/src/config/settings.h
@@ -164,6 +164,7 @@ typedef struct {
char user[MQTT_USER_LEN];
char pwd[MQTT_PWD_LEN];
char topic[MQTT_TOPIC_LEN];
+ bool json;
uint16_t interval;
bool enableRetain;
} cfgMqtt_t;
@@ -485,6 +486,7 @@ class settings {
snprintf(mCfg.mqtt.pwd, MQTT_PWD_LEN, "%s", DEF_MQTT_PWD);
snprintf(mCfg.mqtt.topic, MQTT_TOPIC_LEN, "%s", DEF_MQTT_TOPIC);
mCfg.mqtt.interval = 0; // off
+ mCfg.mqtt.json = 0; // off
mCfg.mqtt.enableRetain = true;
mCfg.inst.sendInterval = SEND_INTERVAL;
@@ -742,12 +744,14 @@ class settings {
obj[F("user")] = mCfg.mqtt.user;
obj[F("pwd")] = mCfg.mqtt.pwd;
obj[F("topic")] = mCfg.mqtt.topic;
+ obj[F("json")] = mCfg.mqtt.json;
obj[F("intvl")] = mCfg.mqtt.interval;
obj[F("retain")] = mCfg.mqtt.enableRetain;
} else {
getVal(obj, F("port"), &mCfg.mqtt.port);
getVal(obj, F("intvl"), &mCfg.mqtt.interval);
+ getVal(obj, F("json"), &mCfg.mqtt.json);
getChar(obj, F("broker"), mCfg.mqtt.broker, MQTT_ADDR_LEN);
getChar(obj, F("user"), mCfg.mqtt.user, MQTT_USER_LEN);
getChar(obj, F("clientId"), mCfg.mqtt.clientId, MQTT_CLIENTID_LEN);
diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h
index 98281805..4287d26e 100644
--- a/src/hm/hmDefines.h
+++ b/src/hm/hmDefines.h
@@ -62,8 +62,8 @@ enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT,
FLD_GRID_PROFILE_VERSION, /*FLD_ACT_REACTIVE_PWR_LIMIT, FLD_ACT_PF,*/ FLD_LAST_ALARM_CODE, FLD_MP, FLD_MT};
const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal",
- "U_AC", "U_AC_1N", "U_AC_2N", "U_AC_3N", "UAC_12", "UAC_23", "UAC_31", "I_AC",
- "IAC_1", "I_AC_2", "I_AC_3", "P_AC", "F_AC", "Temp", "PF_AC", "Efficiency", "Irradiation","Q_AC",
+ "U_AC", "U_AC_1N", "U_AC_2N", "U_AC_3N", "U_AC_12", "U_AC_23", "U_AC_31", "I_AC",
+ "I_AC_1", "I_AC_2", "I_AC_3", "P_AC", "F_AC", "Temp", "PF_AC", "Efficiency", "Irradiation","Q_AC",
"ALARM_MES_ID","FWVersion","FWBuildYear","FWBuildMonthDay","FWBuildHourMinute","BootloaderVersion",
"active_PowerLimit", "HWPartNumber", "HWVersion", "GridProfileCode",
"GridProfileVersion", /*"reactivePowerLimit","Powerfactor",*/ "LastAlarmCode", "MaxPower", "MaxTemp"};
@@ -72,7 +72,7 @@ const char* const notAvail = "n/a";
const uint8_t fieldUnits[] = {UNIT_V, UNIT_A, UNIT_W, UNIT_WH, UNIT_KWH, UNIT_KWH,
UNIT_V, UNIT_V, UNIT_V, UNIT_V, UNIT_V, UNIT_V, UNIT_V, UNIT_A, UNIT_A, UNIT_A, UNIT_A,
UNIT_W, UNIT_HZ, UNIT_C, UNIT_NONE, UNIT_PCT, UNIT_PCT, UNIT_VAR,
- UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_PCT, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_W};
+ UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_PCT, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_W, UNIT_C};
// mqtt discovery device classes
enum {DEVICE_CLS_NONE = 0, DEVICE_CLS_CURRENT, DEVICE_CLS_ENERGY, DEVICE_CLS_PWR, DEVICE_CLS_VOLTAGE, DEVICE_CLS_FREQ, DEVICE_CLS_TEMP};
@@ -389,8 +389,11 @@ const devInfo_t devInfo[] = {
{ 0x102271, 2000 }, // v2 black backplane, 16A
// HMT
- { 0x103311, 1800 },
- { 0x103331, 2250 }
+ { 0x103241, 1600 }, // -4T
+ { 0x103251, 1800 }, // -4T
+ { 0x103271, 2000 }, // -4T
+ { 0x103311, 1800 }, // -6T
+ { 0x103331, 2250 } // -6T
};
#define MI_REQ_CH1 0x09
diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h
index 5a9f2130..860cf51d 100644
--- a/src/hm/hmInverter.h
+++ b/src/hm/hmInverter.h
@@ -53,6 +53,9 @@ T calcIrradiation(Inverter<> *iv, uint8_t arg0);
template
T calcMaxPowerAcCh0(Inverter<> *iv, uint8_t arg0);
+template
+T calcMaxTempCh0(Inverter<> *iv, uint8_t arg0);
+
template
T calcMaxPowerDc(Inverter<> *iv, uint8_t arg0);
@@ -538,6 +541,10 @@ class Inverter {
rec->length = (uint8_t)(HMS4CH_LIST_LEN);
rec->assign = reinterpret_cast(const_cast(hms4chAssignment));
rec->pyldLen = HMS4CH_PAYLOAD_LEN;
+ } else if(IV_HMT == ivGen){
+ rec->length = (uint8_t)(HMT4CH_LIST_LEN);
+ rec->assign = reinterpret_cast(const_cast(hmt4chAssignment));
+ rec->pyldLen = HMT4CH_PAYLOAD_LEN;
}
channels = 4;
}
@@ -968,6 +975,28 @@ T calcMaxPowerAcCh0(Inverter<> *iv, uint8_t arg0) {
return acMaxPower;
}
+template
+T calcMaxTempCh0(Inverter<> *iv, uint8_t arg0) {
+ DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcMaxTempCh0"));
+ T maxTemp = 0.0;
+ if(NULL != iv) {
+ record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
+ T Temp = iv->getChannelFieldValue(arg0, FLD_T, rec);
+
+ for(uint8_t i = 0; i < rec->length; i++) {
+ if((FLD_MT == rec->assign[i].fieldId) && (0 == rec->assign[i].ch)) {
+ maxTemp = iv->getValue(i, rec);
+ }
+ }
+ if(Temp > maxTemp) {
+ iv->tsMaxTemperature = *iv->Timestamp;
+ return Temp;
+ }
+ }
+ return maxTemp;
+}
+
+
template
T calcMaxPowerDc(Inverter<> *iv, uint8_t arg0) {
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcMaxPowerDc"));
diff --git a/src/hms/hmsDefines.h b/src/hms/hmsDefines.h
index c71aa796..07aec682 100644
--- a/src/hms/hmsDefines.h
+++ b/src/hms/hmsDefines.h
@@ -131,6 +131,67 @@ const byteAssign_t hms4chAssignment[] = {
#define HMS4CH_LIST_LEN (sizeof(hms4chAssignment) / sizeof(byteAssign_t))
#define HMS4CH_PAYLOAD_LEN 66
+//-------------------------------------
+// HMT-1600, HMT-1800, HMT-2000
+//-------------------------------------
+const byteAssign_t hmt4chAssignment[] = {
+ { FLD_UDC, UNIT_V, CH1, 2, 2, 10 },
+ { FLD_IDC, UNIT_A, CH1, 4, 2, 100 },
+ { FLD_PDC, UNIT_W, CH1, 8, 2, 10 },
+ { FLD_YT, UNIT_KWH, CH1, 12, 4, 1000 },
+ { FLD_YD, UNIT_WH, CH1, 20, 2, 1 },
+ { FLD_IRR, UNIT_PCT, CH1, CALC_IRR_CH, CH1, CMD_CALC },
+ { FLD_MP, UNIT_W, CH1, CALC_MPDC_CH, CH1, CMD_CALC },
+
+ { FLD_UDC, UNIT_V, CH2, CALC_UDC_CH, CH1, CMD_CALC },
+ { FLD_IDC, UNIT_A, CH2, 6, 2, 100 },
+ { FLD_PDC, UNIT_W, CH2, 10, 2, 10 },
+ { FLD_YT, UNIT_KWH, CH2, 16, 4, 1000 },
+ { FLD_YD, UNIT_WH, CH2, 22, 2, 1 },
+ { FLD_IRR, UNIT_PCT, CH2, CALC_IRR_CH, CH2, CMD_CALC },
+ { FLD_MP, UNIT_W, CH2, CALC_MPDC_CH, CH2, CMD_CALC },
+
+ { FLD_UDC, UNIT_V, CH3, 24, 2, 10 },
+ { FLD_IDC, UNIT_A, CH3, 26, 2, 100 },
+ { FLD_PDC, UNIT_W, CH3, 30, 2, 10 },
+ { FLD_YT, UNIT_KWH, CH3, 34, 4, 1000 },
+ { FLD_YD, UNIT_WH, CH3, 42, 2, 1 },
+ { FLD_IRR, UNIT_PCT, CH3, CALC_IRR_CH, CH3, CMD_CALC },
+ { FLD_MP, UNIT_W, CH3, CALC_MPDC_CH, CH3, CMD_CALC },
+
+ { FLD_UDC, UNIT_V, CH4, CALC_UDC_CH, CH3, CMD_CALC },
+ { FLD_IDC, UNIT_A, CH4, 28, 2, 100 },
+ { FLD_PDC, UNIT_W, CH4, 32, 2, 10 },
+ { FLD_YT, UNIT_KWH, CH4, 38, 4, 1000 },
+ { FLD_YD, UNIT_WH, CH4, 44, 2, 1 },
+ { FLD_IRR, UNIT_PCT, CH4, CALC_IRR_CH, CH4, CMD_CALC },
+ { FLD_MP, UNIT_W, CH4, CALC_MPDC_CH, CH4, CMD_CALC },
+
+ { FLD_UAC_1N, UNIT_V, CH0, 68, 2, 10 },
+ { FLD_UAC_2N, UNIT_V, CH0, 70, 2, 10 },
+ { FLD_UAC_3N, UNIT_V, CH0, 72, 2, 10 },
+ { FLD_UAC_12, UNIT_V, CH0, 74, 2, 10 },
+ { FLD_UAC_23, UNIT_V, CH0, 76, 2, 10 },
+ { FLD_UAC_31, UNIT_V, CH0, 78, 2, 10 },
+ { FLD_F, UNIT_HZ, CH0, 80, 2, 100 },
+ { FLD_PAC, UNIT_W, CH0, 82, 2, 10 },
+ { FLD_Q, UNIT_VAR, CH0, 84, 2, 10 },
+ { FLD_IAC_1, UNIT_A, CH0, 86, 2, 100 },
+ { FLD_IAC_2, UNIT_A, CH0, 88, 2, 100 },
+ { FLD_IAC_3, UNIT_A, CH0, 90, 2, 100 },
+ { FLD_PF, UNIT_NONE, CH0, 92, 2, 1000 },
+ { FLD_T, UNIT_C, CH0, 94, 2, 10 },
+ { FLD_EVT, UNIT_NONE, CH0, 96, 2, 1 },
+ { FLD_YD, UNIT_WH, CH0, CALC_YD_CH0, 0, CMD_CALC },
+ { FLD_YT, UNIT_KWH, CH0, CALC_YT_CH0, 0, CMD_CALC },
+ { FLD_PDC, UNIT_W, CH0, CALC_PDC_CH0, 0, CMD_CALC },
+ { FLD_EFF, UNIT_PCT, CH0, CALC_EFF_CH0, 0, CMD_CALC },
+ { FLD_MP, UNIT_W, CH0, CALC_MPAC_CH0, 0, CMD_CALC },
+ { FLD_MT, UNIT_C, CH0, CALC_MT_CH0, 0, CMD_CALC }
+};
+#define HMT4CH_LIST_LEN (sizeof(hmt4chAssignment) / sizeof(byteAssign_t))
+#define HMT4CH_PAYLOAD_LEN 98
+
//-------------------------------------
// HMT-1800, HMT-2250
//-------------------------------------
diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h
index 4ce2b76c..f422fad7 100644
--- a/src/publisher/pubMqtt.h
+++ b/src/publisher/pubMqtt.h
@@ -235,6 +235,10 @@ class PubMqtt {
return mRxCnt;
}
+ inline bool isJson() {
+ return mCfgMqtt->json;
+ }
+
void sendDiscoveryConfig(void) {
DPRINTLN(DBG_VERBOSE, F("sendMqttDiscoveryConfig"));
mDiscovery.running = true;
@@ -564,6 +568,9 @@ class PubMqtt {
}
void sendData(Inverter<> *iv, uint8_t curInfoCmd) {
+ if (mCfgMqtt->json)
+ return;
+
record_t<> *rec = iv->getRecordStruct(curInfoCmd);
uint32_t lastTs = iv->getLastTs(rec);
diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h
index aa221be7..afd6165b 100644
--- a/src/publisher/pubMqttIvData.h
+++ b/src/publisher/pubMqttIvData.h
@@ -27,6 +27,7 @@ class PubMqttIvData {
void setup(IApp *app, HMSYSTEM *sys, uint32_t *utcTs, std::queue *sendList) {
mApp = app;
mSys = sys;
+ mJson = app->getMqttJsonEnabled();
mUtcTimestamp = utcTs;
mSendList = sendList;
mState = IDLE;
@@ -115,7 +116,7 @@ class PubMqttIvData {
mPublish(mSubTopic.data(), mVal.data(), true, QOS_0);
if((mIv->ivGen == IV_HMS) || (mIv->ivGen == IV_HMT)) {
- snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch0/rssi", mIv->config->name);
+ snprintf(mSubTopic.data(), mSubTopic.size(), "%s/rssi", mIv->config->name);
snprintf(mVal.data(), mVal.size(), "%d", mIv->rssi);
mPublish(mSubTopic.data(), mVal.data(), false, QOS_0);
}
@@ -193,18 +194,47 @@ class PubMqttIvData {
static_cast(mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec)),
static_cast(mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_VERSION, rec)));
} 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)));
+ if (!mJson) {
+ 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;
- if((FLD_EVT != rec->assign[mPos].fieldId)
- && (FLD_LAST_ALARM_CODE != rec->assign[mPos].fieldId))
- mPublish(mSubTopic.data(), mVal.data(), retained, qos);
+ if (InverterDevInform_All == mCmd || InverterDevInform_Simple == mCmd || !mJson) {
+ uint8_t qos = (FLD_ACT_ACTIVE_PWR_LIMIT == rec->assign[mPos].fieldId) ? QOS_2 : QOS_0;
+ if((FLD_EVT != rec->assign[mPos].fieldId)
+ && (FLD_LAST_ALARM_CODE != rec->assign[mPos].fieldId))
+ mPublish(mSubTopic.data(), mVal.data(), retained, qos);
+ }
}
mPos++;
} else {
if (MqttSentStatus::LAST_SUCCESS_SENT == rec->mqttSentStatus) {
+ if (mJson && RealTimeRunData_Debug == mCmd) {
+ DynamicJsonDocument doc(300);
+ std::array buf;
+
+ for (mPos = 0; mPos < rec->length; mPos++) {
+ doc[fields[rec->assign[mPos].fieldId]] = ah::round3(mIv->getValue(mPos, rec));
+
+ bool publish = false;
+ if (mPos != rec->length - 1) { // not last one
+ if (rec->assign[mPos].ch != rec->assign[mPos+1].ch)
+ publish = true;
+ } else
+ publish = true;
+
+ if (publish) {
+ publish = false;
+ // if next channel or end->publish
+ serializeJson(doc, buf.data(), buf.size());
+ snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d", mIv->config->name, rec->assign[mPos].ch);
+ mPublish(mSubTopic.data(), buf.data(), false, QOS_0);
+ doc.clear();
+ }
+ }
+ }
+
sendRadioStat(rec->length);
rec->mqttSentStatus = MqttSentStatus::DATA_SENT;
}
@@ -262,11 +292,27 @@ class PubMqttIvData {
mTotal[4] = mApp->getTotalMaxPower();
break;
}
- 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);
+ if (!mJson) {
+ 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 {
+ if (mJson) {
+ int type[5] = {FLD_PAC, FLD_YT, FLD_YD, FLD_PDC, FLD_MP};
+ snprintf(mVal.data(), mVal.size(), "{");
+
+ for (mPos = 0; mPos < 5; mPos++) {
+ snprintf(mSubTopic.data(), mSubTopic.size(), "\"%s\":%g", fields[type[mPos]], ah::round3(mTotal[mPos]));
+ strcat(mVal.data(), mSubTopic.data());
+ if (mPos < 4)
+ strcat(mVal.data(), ",");
+ else
+ strcat(mVal.data(), "}");
+ }
+ mPublish(F("total"), mVal.data(), true, QOS_0);
+ }
mSendList->pop();
mSendTotals = false;
mState = IDLE;
@@ -294,6 +340,7 @@ class PubMqttIvData {
std::array mSubTopic;
std::array mVal;
+ bool mJson;
std::queue *mSendList = nullptr;
};
diff --git a/src/web/RestApi.h b/src/web/RestApi.h
index dd8c5ca5..6dffe3bb 100644
--- a/src/web/RestApi.h
+++ b/src/web/RestApi.h
@@ -83,7 +83,7 @@ class RestApi {
mHeapFrag = ESP.getHeapFragmentation();
#endif
- AsyncJsonResponse* response = new AsyncJsonResponse(false, 6000);
+ AsyncJsonResponse* response = new AsyncJsonResponse(false, 8000);
JsonObject root = response->getRoot();
String path = request->url().substring(5);
@@ -750,6 +750,7 @@ class RestApi {
obj[F("user")] = String(mConfig->mqtt.user);
obj[F("pwd")] = (strlen(mConfig->mqtt.pwd) > 0) ? F("{PWD}") : String("");
obj[F("topic")] = String(mConfig->mqtt.topic);
+ obj[F("json")] = (bool) mConfig->mqtt.json;
obj[F("interval")] = String(mConfig->mqtt.interval);
obj[F("retain")] = (bool)mConfig->mqtt.enableRetain;
}
diff --git a/src/web/html/index.html b/src/web/html/index.html
index 70a9cd26..864dc762 100644
--- a/src/web/html/index.html
+++ b/src/web/html/index.html
@@ -14,6 +14,7 @@
System Infos:
+
@@ -111,6 +112,8 @@
function parseIv(obj, ts) {
var p = div(["none"]);
+ var total = 0;
+ var count = 0;
for(var i of obj) {
var icon = iconSuccess;
var cl = "icon-success";
@@ -131,7 +134,9 @@
avail += "{#NOT_PRODUCING}";
else {
icon = iconSuccessFull;
- avail += "{#PRODUCING} " + i.cur_pwr + "W";
+ avail += "{#PRODUCING} " + i.cur_pwr + " W";
+ total += i.cur_pwr;
+ count += 1;
}
}
@@ -149,6 +154,13 @@
}
}
document.getElementById("iv").replaceChildren(p);
+
+ if (count > 1) {
+ var t = div(["none"]);
+ t.append(svg(iconInfo, 30, 30, "icon icon-info"), span("Total: " + Math.round(total).toLocaleString() + " W"), br());
+ document.getElementById("total").replaceChildren(t);
+ document.getElementById("total").appendChild(div(["hr"]));
+ }
}
function parseWarn(warn) {
@@ -165,7 +177,7 @@
p.append(svg(iconInfo, 30, 30, "icon icon-info"), span("{#UPDATE_AVAIL}: " + release), br());
else if(getVerInt("{#VERSION}") > getVerInt(release))
p.append(svg(iconInfo, 30, 30, "icon icon-info"), span("{#USING_DEV_VERSION} {#VERSION}. {#DEV_ISSUE_RELEASE_VERSION}: " + release), br());
- else
+ else
p.append(svg(iconInfo, 30, 30, "icon icon-info"), span("{#RELEASE_INSTALLED}: " + release), br());
}
diff --git a/src/web/html/setup.html b/src/web/html/setup.html
index 37193be1..b5f5a6f2 100644
--- a/src/web/html/setup.html
+++ b/src/web/html/setup.html
@@ -238,6 +238,10 @@
Topic
+
{#MQTT_NOTE}
{#INTERVAL}
@@ -946,6 +950,7 @@
function parseMqtt(obj) {
for(var i of [["Addr", "broker"], ["Port", "port"], ["ClientId", "clientId"], ["User", "user"], ["Pwd", "pwd"], ["Topic", "topic"], ["Interval", "interval"]])
document.getElementsByName("mqtt"+i[0])[0].value = obj[i[1]];
+ document.getElementsByName("mqttJson")[0].checked = obj["json"];
document.getElementsByName("retain")[0].checked = obj.retain
}
diff --git a/src/web/lang.json b/src/web/lang.json
index 0b0754b2..6f1b7c03 100644
--- a/src/web/lang.json
+++ b/src/web/lang.json
@@ -413,6 +413,11 @@
"en": "Password (optional)",
"de": "Passwort (optional)"
},
+ {
+ "token": "MQTT_JSON",
+ "en": "Payload as JSON",
+ "de": "Ausgabe als JSON"
+ },
{
"token": "MQTT_NOTE",
"en": "Send Inverter data in a fixed interval, even if there is no change. A value of '0' disables the fixed interval. The data is published once it was successfully received from inverter. (default: 0)",
diff --git a/src/web/web.h b/src/web/web.h
index 9c8750fc..2d017969 100644
--- a/src/web/web.h
+++ b/src/web/web.h
@@ -582,6 +582,7 @@ class Web {
if (request->arg("mqttPwd") != "{PWD}")
request->arg("mqttPwd").toCharArray(mConfig->mqtt.pwd, MQTT_PWD_LEN);
request->arg("mqttTopic").toCharArray(mConfig->mqtt.topic, MQTT_TOPIC_LEN);
+ mConfig->mqtt.json = (request->arg("mqttJson") == "on");
mConfig->mqtt.port = request->arg("mqttPort").toInt();
mConfig->mqtt.interval = request->arg("mqttInterval").toInt();
mConfig->mqtt.enableRetain = (request->arg("retain") == "on");
diff --git a/tools/NodeRED/flows-mqtt-json-example.json b/tools/NodeRED/flows-mqtt-json-example.json
new file mode 100644
index 00000000..5e2e09a1
--- /dev/null
+++ b/tools/NodeRED/flows-mqtt-json-example.json
@@ -0,0 +1,466 @@
+[
+ {
+ "id": "67bced2c4e728783",
+ "type": "mqtt in",
+ "z": "5de5756d190f9086",
+ "name": "",
+ "topic": "hoymiles/+",
+ "qos": "0",
+ "datatype": "auto-detect",
+ "broker": "319864a4e0fd913f",
+ "nl": false,
+ "rap": true,
+ "rh": 0,
+ "inputs": 0,
+ "x": 80,
+ "y": 2100,
+ "wires": [
+ [
+ "a55632ad0dff0b69"
+ ]
+ ]
+ },
+ {
+ "id": "a7f0d307d7cf77e2",
+ "type": "mqtt in",
+ "z": "5de5756d190f9086",
+ "name": "",
+ "topic": "hoymiles/X/#",
+ "qos": "0",
+ "datatype": "auto-detect",
+ "broker": "319864a4e0fd913f",
+ "nl": false,
+ "rap": true,
+ "rh": 0,
+ "inputs": 0,
+ "x": 90,
+ "y": 2260,
+ "wires": [
+ [
+ "7e17e5a3f4df3011",
+ "1a8cca488d53394a"
+ ]
+ ]
+ },
+ {
+ "id": "7e17e5a3f4df3011",
+ "type": "debug",
+ "z": "5de5756d190f9086",
+ "name": "Inverter X",
+ "active": false,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 340,
+ "y": 2260,
+ "wires": []
+ },
+ {
+ "id": "fb7357db50501627",
+ "type": "change",
+ "z": "5de5756d190f9086",
+ "name": "Tags setzen",
+ "rules": [
+ {
+ "t": "set",
+ "p": "payload",
+ "pt": "msg",
+ "to": "(\t $a := $split(topic, '/');\t [\t payload,\t {\t \"device\":$a[0],\t \"name\":$a[1],\t \"channel\":$a[2]\t }\t ]\t)\t",
+ "tot": "jsonata"
+ },
+ {
+ "t": "delete",
+ "p": "topic",
+ "pt": "msg"
+ }
+ ],
+ "action": "",
+ "property": "",
+ "from": "",
+ "to": "",
+ "reg": false,
+ "x": 610,
+ "y": 2360,
+ "wires": [
+ [
+ "91a4607dfda84b67"
+ ]
+ ]
+ },
+ {
+ "id": "670eb9fbb5c31b2c",
+ "type": "debug",
+ "z": "5de5756d190f9086",
+ "name": "InfluxDB",
+ "active": false,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 940,
+ "y": 2360,
+ "wires": []
+ },
+ {
+ "id": "1a8cca488d53394a",
+ "type": "switch",
+ "z": "5de5756d190f9086",
+ "name": "",
+ "property": "$split(topic, '/')[2]",
+ "propertyType": "jsonata",
+ "rules": [
+ {
+ "t": "eq",
+ "v": "available",
+ "vt": "str"
+ },
+ {
+ "t": "eq",
+ "v": "last_success",
+ "vt": "str"
+ },
+ {
+ "t": "regex",
+ "v": "(ch[0-6])\\b",
+ "vt": "str",
+ "case": false
+ },
+ {
+ "t": "eq",
+ "v": "radio_stat",
+ "vt": "str"
+ },
+ {
+ "t": "eq",
+ "v": "firmware",
+ "vt": "str"
+ },
+ {
+ "t": "eq",
+ "v": "hardware",
+ "vt": "str"
+ },
+ {
+ "t": "eq",
+ "v": "alarm",
+ "vt": "str"
+ }
+ ],
+ "checkall": "true",
+ "repair": false,
+ "outputs": 7,
+ "x": 330,
+ "y": 2380,
+ "wires": [
+ [
+ "845aeb93e39092c5"
+ ],
+ [
+ "241a8e70e9fde93c"
+ ],
+ [
+ "fb7357db50501627"
+ ],
+ [
+ "9d38f021308664c1"
+ ],
+ [
+ "a508355f0cc87966"
+ ],
+ [
+ "d2c9aa1a8978aca6"
+ ],
+ [
+ "b27032beb597d5a7"
+ ]
+ ]
+ },
+ {
+ "id": "845aeb93e39092c5",
+ "type": "debug",
+ "z": "5de5756d190f9086",
+ "name": "available",
+ "active": true,
+ "tosidebar": false,
+ "console": false,
+ "tostatus": true,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "payload",
+ "statusType": "auto",
+ "x": 600,
+ "y": 2240,
+ "wires": []
+ },
+ {
+ "id": "241a8e70e9fde93c",
+ "type": "debug",
+ "z": "5de5756d190f9086",
+ "name": "last_success",
+ "active": true,
+ "tosidebar": false,
+ "console": false,
+ "tostatus": true,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "payload",
+ "statusType": "auto",
+ "x": 610,
+ "y": 2300,
+ "wires": []
+ },
+ {
+ "id": "9d38f021308664c1",
+ "type": "debug",
+ "z": "5de5756d190f9086",
+ "name": "radio_stat",
+ "active": false,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 600,
+ "y": 2400,
+ "wires": []
+ },
+ {
+ "id": "a508355f0cc87966",
+ "type": "debug",
+ "z": "5de5756d190f9086",
+ "name": "firmware",
+ "active": false,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 600,
+ "y": 2440,
+ "wires": []
+ },
+ {
+ "id": "d2c9aa1a8978aca6",
+ "type": "debug",
+ "z": "5de5756d190f9086",
+ "name": "hardware",
+ "active": false,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 600,
+ "y": 2480,
+ "wires": []
+ },
+ {
+ "id": "b27032beb597d5a7",
+ "type": "debug",
+ "z": "5de5756d190f9086",
+ "name": "alarm",
+ "active": false,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 590,
+ "y": 2520,
+ "wires": []
+ },
+ {
+ "id": "d814738cf55ad663",
+ "type": "debug",
+ "z": "5de5756d190f9086",
+ "name": "total",
+ "active": false,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 590,
+ "y": 2160,
+ "wires": []
+ },
+ {
+ "id": "a55632ad0dff0b69",
+ "type": "switch",
+ "z": "5de5756d190f9086",
+ "name": "",
+ "property": "$split(topic, '/')[1]",
+ "propertyType": "jsonata",
+ "rules": [
+ {
+ "t": "eq",
+ "v": "uptime",
+ "vt": "str"
+ },
+ {
+ "t": "eq",
+ "v": "wifi_rssi",
+ "vt": "str"
+ },
+ {
+ "t": "eq",
+ "v": "status",
+ "vt": "str"
+ },
+ {
+ "t": "eq",
+ "v": "total",
+ "vt": "str"
+ }
+ ],
+ "checkall": "true",
+ "repair": false,
+ "outputs": 4,
+ "x": 330,
+ "y": 2100,
+ "wires": [
+ [
+ "1fbb0674d2576ee7"
+ ],
+ [
+ "e6be1c98ac55f511"
+ ],
+ [
+ "f9c2d3b30e34fdda"
+ ],
+ [
+ "d814738cf55ad663"
+ ]
+ ]
+ },
+ {
+ "id": "f9c2d3b30e34fdda",
+ "type": "debug",
+ "z": "5de5756d190f9086",
+ "name": "status",
+ "active": false,
+ "tosidebar": false,
+ "console": false,
+ "tostatus": true,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "payload",
+ "statusType": "auto",
+ "x": 590,
+ "y": 2100,
+ "wires": []
+ },
+ {
+ "id": "e6be1c98ac55f511",
+ "type": "debug",
+ "z": "5de5756d190f9086",
+ "name": "wifi_rssi",
+ "active": false,
+ "tosidebar": false,
+ "console": false,
+ "tostatus": true,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "payload",
+ "statusType": "auto",
+ "x": 600,
+ "y": 2040,
+ "wires": []
+ },
+ {
+ "id": "1fbb0674d2576ee7",
+ "type": "debug",
+ "z": "5de5756d190f9086",
+ "name": "uptime",
+ "active": false,
+ "tosidebar": false,
+ "console": false,
+ "tostatus": true,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "payload",
+ "statusType": "auto",
+ "x": 590,
+ "y": 1980,
+ "wires": []
+ },
+ {
+ "id": "91a4607dfda84b67",
+ "type": "change",
+ "z": "5de5756d190f9086",
+ "name": "Lösche",
+ "rules": [
+ {
+ "t": "delete",
+ "p": "payload[0].YieldDay",
+ "pt": "msg"
+ },
+ {
+ "t": "delete",
+ "p": "payload[0].MaxPower",
+ "pt": "msg"
+ },
+ {
+ "t": "delete",
+ "p": "payload[0].ALARM_MES_ID",
+ "pt": "msg"
+ }
+ ],
+ "action": "",
+ "property": "",
+ "from": "",
+ "to": "",
+ "reg": false,
+ "x": 780,
+ "y": 2360,
+ "wires": [
+ [
+ "670eb9fbb5c31b2c"
+ ]
+ ]
+ },
+ {
+ "id": "319864a4e0fd913f",
+ "type": "mqtt-broker",
+ "name": "broker",
+ "broker": "localhost",
+ "port": "1883",
+ "clientid": "",
+ "autoConnect": true,
+ "usetls": false,
+ "protocolVersion": "4",
+ "keepalive": "60",
+ "cleansession": true,
+ "birthTopic": "",
+ "birthQos": "0",
+ "birthPayload": "",
+ "birthMsg": {},
+ "closeTopic": "",
+ "closeQos": "0",
+ "closePayload": "",
+ "closeMsg": {},
+ "willTopic": "",
+ "willQos": "0",
+ "willPayload": "",
+ "willMsg": {},
+ "userProps": "",
+ "sessionExpiry": ""
+ }
+]
\ No newline at end of file