From 5294ae3009d858a5459b486d4ca1094b136433ca Mon Sep 17 00:00:00 2001 From: geronet1 Date: Fri, 29 Mar 2024 22:20:47 +0100 Subject: [PATCH 01/11] =?UTF-8?q?MQTT=20JSON=20Payload=20pro=20Kanal=20und?= =?UTF-8?q?=20total,=20ausw=C3=A4hlbar=20NodeRED=20Beispiel=20Bug=20#1522?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/settings.h | 4 + src/publisher/pubMqtt.h | 2 +- src/publisher/pubMqttIvData.h | 63 ++- src/web/RestApi.h | 3 +- src/web/html/setup.html | 5 + src/web/lang.json | 5 + src/web/web.h | 1 + tools/NodeRED/flows-mqtt-json-example.json | 466 +++++++++++++++++++++ 8 files changed, 537 insertions(+), 12 deletions(-) create mode 100644 tools/NodeRED/flows-mqtt-json-example.json diff --git a/src/config/settings.h b/src/config/settings.h index 8f20ba8f..016af2e3 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -151,6 +151,7 @@ typedef struct { char user[MQTT_USER_LEN]; char pwd[MQTT_PWD_LEN]; char topic[MQTT_TOPIC_LEN]; + bool json; uint16_t interval; } cfgMqtt_t; @@ -477,6 +478,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.inst.sendInterval = SEND_INTERVAL; mCfg.inst.rstYieldMidNight = false; @@ -732,11 +734,13 @@ 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; } 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/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 2d393b8b..14445a2b 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -62,7 +62,7 @@ class PubMqtt { mUptime = uptime; mIntervalTimeout = 1; - SendIvData.setup(sys, utcTs, &mSendList); + SendIvData.setup(sys, cfg_mqtt->json, utcTs, &mSendList); SendIvData.setPublishFunc([this](const char *subTopic, const char *payload, bool retained, uint8_t qos) { publish(subTopic, payload, retained, true, qos); }); diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 6ddd63a9..6ac59cca 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -24,8 +24,9 @@ class PubMqttIvData { public: PubMqttIvData() : mTotal{}, mSubTopic{}, mVal{} {} - void setup(HMSYSTEM *sys, uint32_t *utcTs, std::queue *sendList) { + void setup(HMSYSTEM *sys, bool json, uint32_t *utcTs, std::queue *sendList) { mSys = sys; + mJson = json; mUtcTimestamp = utcTs; mSendList = sendList; mState = IDLE; @@ -197,18 +198,43 @@ class PubMqttIvData { static_cast(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))); + 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) { + DynamicJsonDocument doc(300); + std::array buf; + int ch = rec->assign[0].ch; + + for (mPos = 0; mPos <= rec->length; mPos++) { + if (rec->assign[mPos].ch != ch) { + // if next channel.. publish + serializeJson(doc, buf.data(), buf.size()); + doc.clear(); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d", mIv->config->name, ch); + mPublish(mSubTopic.data(), buf.data(), false, QOS_0); + ch = rec->assign[mPos].ch; + } + if (mPos == rec->length) + break; + + doc[fields[rec->assign[mPos].fieldId]] = ah::round3(mIv->getValue(mPos, rec)); + } + } + sendRadioStat(rec->length); rec->mqttSentStatus = MqttSentStatus::DATA_SENT; } @@ -265,11 +291,27 @@ class PubMqttIvData { retained = false; 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 +336,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 8087883e..31104af0 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -80,7 +80,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); @@ -709,6 +709,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); } diff --git a/src/web/html/setup.html b/src/web/html/setup.html index fb1eff97..0e248c08 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -242,6 +242,10 @@
Topic
+
+
{#MQTT_JSON}
+
+

{#MQTT_NOTE}

{#INTERVAL}
@@ -931,6 +935,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"]; } function parseNtp(obj) { diff --git a/src/web/lang.json b/src/web/lang.json index ee942608..70ca2015 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -418,6 +418,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 419d6826..bd806b84 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -574,6 +574,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(); 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 From 59b1fe866f9851e5f865b2ba25516409fba26985 Mon Sep 17 00:00:00 2001 From: geronet1 Date: Sun, 31 Mar 2024 21:20:35 +0200 Subject: [PATCH 02/11] mqtt->rssi nicht in /ch0/, mqtt->json kein YieldDay/YieldTotal einzeln --- .../htmlPreprocessorDefines.cpython-311.pyc | Bin 0 -> 2235 bytes src/publisher/pubMqtt.h | 3 +++ src/publisher/pubMqttIvData.h | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 scripts/__pycache__/htmlPreprocessorDefines.cpython-311.pyc diff --git a/scripts/__pycache__/htmlPreprocessorDefines.cpython-311.pyc b/scripts/__pycache__/htmlPreprocessorDefines.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b8e34409896b76a6d2fa979407131efe3b7e1f0 GIT binary patch literal 2235 zcma)7-EY%Y6u;LWiIWtPEUh46Dk)t>%~pz_v`7PGL53D}{+ zTlUb>(ygV*AWs==io_C%!AOr|3XctXLtc|jZNYc*vy;NtvP5KIS&>#F31K!VN(muy zKbaX5m9)hOa+JhUiY(k$HsW6qDMgY|NtTmjPFjs6B>8+QW3Un-NkTYK%EBuT0m-2T zr`0h&9rkFk)j0bJ~Dy7XGcb) z56Lj=mOV17(iK|=*Wr4-m(K&v-r4PNy|^r=aw6q#Z>#q1*}8QiVq(}1Cd+Q;kM!Gi zgx{ZmKjtmIH+n6q>?+l(0V5SsJdKF+5E4H`;K^@CdU81Gtq6YeVG$&5#n*9G2=6J_hnw959uDK)%3a}b3Am8n=wq~qH@2RR6t++EBdC8!J(ts{Jgm^W$I zLgBeD=I_1!2gYkN?+qHJ1`cfvj)rb7hxp(|OqOGbwO}$OC4#aNQKStip$zdZgWXI^ zX~}ThjIAbbTP#H+!w!`yM&faUj!OxHF=tS-8!07Y&}))n(5bXyRj*--q(G<0I}AFO zNC93}40|e~C=y8+c+;ShY3L;Dl9V!-IF!GE9~)Sb%{mIU1~D_*V59e?=sFn&-rSWX zI0^Iw?%1}w#`)`RQYomKs-F&;Y?=96_YRc&1%LVTns=z~9jYw7@}8}F z&*~m;i7l|&rX_bri`P8Eb&hkXf6RdlJRZsA(?mC`ZBxbmy?Jfrs zvv*m2RRpHDud4WPK6d|HRHR}N?}F@})z?5AWvLzn1qiAa0l7?vw|HS(I5&D@5>i)% ztX21unjigkW^Coc*fnA7-rZ068^SqZd}~~o7KVf|VeJ3m01~eA6fs+~m0LVb0w#aT zB!fU?(^E*r{VZgn$;3l40!!vAUj(xMV;X+4_;fM1*l@ZvT3fCL=4;M{x^p2n+i-a_ zpBAm2`m*K<*InT%6SgAC+sH>CZBR*>c!06$#d5(?|0}XkmeqIM^hQ!l$EE9J6p&^K s%L0%ljWO1dBWFEbOkd7=nhb?qP1Gh_0K1#0O|H`T7KX(BPik5J7Z*a)+W-In literal 0 HcmV?d00001 diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 14445a2b..a9a91974 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -559,6 +559,9 @@ class PubMqtt { } void sendData(Inverter<> *iv, uint8_t curInfoCmd) { + if (cfg_mqtt->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 6ac59cca..6c1e433d 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -115,7 +115,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); } From d664221e5400be354df1eca5b81ef7db3eebfe38 Mon Sep 17 00:00:00 2001 From: geronet1 Date: Sun, 31 Mar 2024 21:32:57 +0200 Subject: [PATCH 03/11] mCfgMqtt statt cfg_mqtt --- src/publisher/pubMqtt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index a9a91974..159c7939 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -559,7 +559,7 @@ class PubMqtt { } void sendData(Inverter<> *iv, uint8_t curInfoCmd) { - if (cfg_mqtt->json) + if (mCfgMqtt->json) return; record_t<> *rec = iv->getRecordStruct(curInfoCmd); From 42ee440e114fa54e6679e6edbe42213ccccce6fa Mon Sep 17 00:00:00 2001 From: geronet1 Date: Mon, 1 Apr 2024 15:55:09 +0200 Subject: [PATCH 04/11] MaxTemp Berechnung und Anzeige --- src/hm/hmDefines.h | 17 ++++++++++------- src/hm/hmInverter.h | 29 ++++++++++++++++++++++++++++- src/hms/hmsDefines.h | 12 ++++++++---- src/web/RestApi.h | 5 +++-- src/web/html/visualization.html | 4 +++- 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 6ba92774..c6ca7066 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -24,20 +24,20 @@ enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT, FLD_IRR, FLD_Q, FLD_EVT, FLD_FW_VERSION, FLD_FW_BUILD_YEAR, FLD_FW_BUILD_MONTH_DAY, FLD_FW_BUILD_HOUR_MINUTE, FLD_BOOTLOADER_VER, FLD_ACT_ACTIVE_PWR_LIMIT, FLD_PART_NUM, FLD_HW_VERSION, FLD_GRID_PROFILE_CODE, - FLD_GRID_PROFILE_VERSION, /*FLD_ACT_REACTIVE_PWR_LIMIT, FLD_ACT_PF,*/ FLD_LAST_ALARM_CODE, FLD_MP}; + 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", "ALARM_MES_ID","FWVersion","FWBuildYear","FWBuildMonthDay","FWBuildHourMinute","BootloaderVersion", "active_PowerLimit", "HWPartNumber", "HWVersion", "GridProfileCode", - "GridProfileVersion", /*"reactivePowerLimit","Powerfactor",*/ "LastAlarmCode", "MaxPower"}; + "GridProfileVersion", /*"reactivePowerLimit","Powerfactor",*/ "LastAlarmCode", "MaxPower", "MaxTemp"}; 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}; @@ -68,7 +68,7 @@ const byteAssign_fieldDeviceClass deviceFieldAssignment[] = { #define DEVICE_CLS_ASSIGN_LIST_LEN (sizeof(deviceFieldAssignment) / sizeof(byteAssign_fieldDeviceClass)) // indices to calculation functions, defined in hmInverter.h -enum {CALC_YT_CH0 = 0, CALC_YD_CH0, CALC_UDC_CH, CALC_PDC_CH0, CALC_EFF_CH0, CALC_IRR_CH, CALC_MPAC_CH0, CALC_MPDC_CH}; +enum {CALC_YT_CH0 = 0, CALC_YD_CH0, CALC_UDC_CH, CALC_PDC_CH0, CALC_EFF_CH0, CALC_IRR_CH, CALC_MPAC_CH0, CALC_MPDC_CH, CALC_MT_CH0}; enum {CMD_CALC = 0xffff}; @@ -173,7 +173,8 @@ const byteAssign_t hm1chAssignment[] = { { 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_MP, UNIT_W, CH0, CALC_MPAC_CH0, 0, CMD_CALC }, + { FLD_MT, UNIT_C, CH0, CALC_MT_CH0, 0, CMD_CALC } }; #define HM1CH_LIST_LEN (sizeof(hm1chAssignment) / sizeof(byteAssign_t)) #define HM1CH_PAYLOAD_LEN 30 @@ -211,7 +212,8 @@ const byteAssign_t hm2chAssignment[] = { { 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_MP, UNIT_W, CH0, CALC_MPAC_CH0, 0, CMD_CALC }, + { FLD_MT, UNIT_C, CH0, CALC_MT_CH0, 0, CMD_CALC } }; #define HM2CH_LIST_LEN (sizeof(hm2chAssignment) / sizeof(byteAssign_t)) @@ -266,7 +268,8 @@ const byteAssign_t hm4chAssignment[] = { { 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_MP, UNIT_W, CH0, CALC_MPAC_CH0, 0, CMD_CALC }, + { FLD_MT, UNIT_C, CH0, CALC_MT_CH0, 0, CMD_CALC } }; #define HM4CH_LIST_LEN (sizeof(hm4chAssignment) / sizeof(byteAssign_t)) #define HM4CH_PAYLOAD_LEN 62 diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 1d7e6620..6754fd45 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -53,6 +53,9 @@ static T calcIrradiation(Inverter<> *iv, uint8_t arg0); template static T calcMaxPowerAcCh0(Inverter<> *iv, uint8_t arg0); +template +static T calcMaxTempCh0(Inverter<> *iv, uint8_t arg0); + template static T calcMaxPowerDc(Inverter<> *iv, uint8_t arg0); @@ -107,7 +110,8 @@ const calcFunc_t calcFunctions[] = { { CALC_EFF_CH0, &calcEffiencyCh0 }, { CALC_IRR_CH, &calcIrradiation }, { CALC_MPAC_CH0, &calcMaxPowerAcCh0 }, - { CALC_MPDC_CH, &calcMaxPowerDc } + { CALC_MPDC_CH, &calcMaxPowerDc }, + { CALC_MT_CH0, &calcMaxTempCh0 } }; template @@ -147,6 +151,7 @@ class Inverter { HeuristicInv heuristics; // heuristic information / logic uint8_t curCmtFreq = 0; // current used CMT frequency, used to check if freq. was changed during runtime uint32_t tsMaxAcPower = 0; // holds the timestamp when the MaxAC power was seen + uint32_t tsMaxTemp = 0; // holds the timestamp when the max temp was seen bool commEnabled = true; // 'pause night communication' sets this field to false public: @@ -951,6 +956,28 @@ static T calcMaxPowerAcCh0(Inverter<> *iv, uint8_t arg0) { return acMaxPower; } +template +static 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->tsMaxTemp = *iv->timestamp; + return Temp; + } + } + return maxTemp; +} + + template static 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 61275dc1..c71aa796 100644 --- a/src/hms/hmsDefines.h +++ b/src/hms/hmsDefines.h @@ -33,7 +33,8 @@ const byteAssign_t hms1chAssignment[] = { { 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_MP, UNIT_W, CH0, CALC_MPAC_CH0, 0, CMD_CALC }, + { FLD_MT, UNIT_C, CH0, CALC_MT_CH0, 0, CMD_CALC } }; #define HMS1CH_LIST_LEN (sizeof(hms1chAssignment) / sizeof(byteAssign_t)) #define HMS1CH_PAYLOAD_LEN 30 @@ -70,7 +71,8 @@ const byteAssign_t hms2chAssignment[] = { { 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_MP, UNIT_W, CH0, CALC_MPAC_CH0, 0, CMD_CALC }, + { FLD_MT, UNIT_C, CH0, CALC_MT_CH0, 0, CMD_CALC } }; #define HMS2CH_LIST_LEN (sizeof(hms2chAssignment) / sizeof(byteAssign_t)) #define HMS2CH_PAYLOAD_LEN 42 @@ -123,7 +125,8 @@ const byteAssign_t hms4chAssignment[] = { { 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_MP, UNIT_W, CH0, CALC_MPAC_CH0, 0, CMD_CALC }, + { FLD_MT, UNIT_C, CH0, CALC_MT_CH0, 0, CMD_CALC } }; #define HMS4CH_LIST_LEN (sizeof(hms4chAssignment) / sizeof(byteAssign_t)) #define HMS4CH_PAYLOAD_LEN 66 @@ -199,7 +202,8 @@ const byteAssign_t hmt6chAssignment[] = { { 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_MP, UNIT_W, CH0, CALC_MPAC_CH0, 0, CMD_CALC }, + { FLD_MT, UNIT_C, CH0, CALC_MT_CH0, 0, CMD_CALC } }; #define HMT6CH_LIST_LEN (sizeof(hmt6chAssignment) / sizeof(byteAssign_t)) #define HMT6CH_PAYLOAD_LEN 98 diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 31104af0..3a578add 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -602,6 +602,7 @@ class RestApi { obj[F("alarm_cnt")] = iv->alarmCnt; obj[F("rssi")] = iv->rssi; obj[F("ts_max_ac_pwr")] = iv->tsMaxAcPower; + obj[F("ts_max_temp")] = iv->tsMaxTemp; JsonArray ch = obj.createNestedArray("ch"); @@ -1110,9 +1111,9 @@ class RestApi { private: constexpr static uint8_t acList[] = {FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_PF, FLD_T, FLD_YT, - FLD_YD, FLD_PDC, FLD_EFF, FLD_Q, FLD_MP}; + FLD_YD, FLD_PDC, FLD_EFF, FLD_Q, FLD_MP, FLD_MT}; constexpr static uint8_t acListHmt[] = {FLD_UAC_1N, FLD_IAC_1, FLD_PAC, FLD_F, FLD_PF, FLD_T, - FLD_YT, FLD_YD, FLD_PDC, FLD_EFF, FLD_Q, FLD_MP}; + FLD_YT, FLD_YD, FLD_PDC, FLD_EFF, FLD_Q, FLD_MP, FLD_MT}; constexpr static uint8_t dcList[] = {FLD_UDC, FLD_IDC, FLD_PDC, FLD_YD, FLD_YT, FLD_IRR, FLD_MP}; private: diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index cfc84e72..6c3bb67f 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -120,6 +120,7 @@ } var maxAcPwr = toIsoDateStr(new Date(obj.ts_max_ac_pwr * 1000)); + var maxTemp = toIsoDateStr(new Date(obj.ts_max_temp * 1000)); return ml("div", {class: "row mt-2"}, ml("div", {class: "col"}, [ ml("div", {class: "p-2 " + clh}, @@ -134,7 +135,8 @@ ml("div", {class: "col a-c"}, ml("span", { class: "pointer", onclick: function() { getAjax("/api/inverter/alarm/" + obj.id, parseIvAlarm); }}, ("{#ALARMS}: " + obj.alarm_cnt))), - ml("div", {class: "col a-r mx-2 mx-md-1"}, String(obj.ch[0][5].toFixed(1)) + t.innerText) + ml("div", {class: "col a-r mx-2 mx-md-1 tooltip", data: maxTemp}, String(obj.ch[0][5].toFixed(1)) + t.innerText + "
" + + "Max:" + String(obj.ch[0][12].toFixed(1)) + t.innerText) ]) ), ml("div", {class: "p-2 " + clbg}, [ From 1a9da99f74b418183ffd671d14727cddb11cde1e Mon Sep 17 00:00:00 2001 From: geronet1 Date: Fri, 12 Apr 2024 11:46:46 +0200 Subject: [PATCH 05/11] =?UTF-8?q?Total=20Summe=20in=20=C3=9Cbersicht?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/web/html/index.html | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/web/html/index.html b/src/web/html/index.html index 954ee012..a811dd2a 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,12 @@ } } document.getElementById("iv").replaceChildren(p); + + if (count > 1) { + p.append(svg(iconInfo, 30, 30, "icon icon-info"), span("Total: " + total + " W"), br()); + document.getElementById("total").replaceChildren(p); + document.getElementById("total").appendChild(div(["class=\"hr\""])); + } } function parseWarn(warn) { @@ -165,7 +176,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()); } From d373fbb49de1b09b9d8c04d7eaba459d5d22d0fe Mon Sep 17 00:00:00 2001 From: geronet1 Date: Fri, 19 Apr 2024 14:00:21 +0200 Subject: [PATCH 06/11] fix mqtt json output --- src/publisher/pubMqttIvData.h | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 00595972..7412ce15 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -212,24 +212,28 @@ class PubMqttIvData { mPos++; } else { if (MqttSentStatus::LAST_SUCCESS_SENT == rec->mqttSentStatus) { - if (mJson) { + if (mJson && RealTimeRunData_Debug == mCmd) { DynamicJsonDocument doc(300); std::array buf; - int ch = rec->assign[0].ch; - for (mPos = 0; mPos <= rec->length; mPos++) { - if (rec->assign[mPos].ch != ch) { - // if next channel.. publish + 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()); doc.clear(); - snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d", mIv->config->name, ch); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d", mIv->config->name, rec->assign[mPos].ch); mPublish(mSubTopic.data(), buf.data(), false, QOS_0); - ch = rec->assign[mPos].ch; } - if (mPos == rec->length) - break; - - doc[fields[rec->assign[mPos].fieldId]] = ah::round3(mIv->getValue(mPos, rec)); } } From 9857c4e5a6d8d452e701d0c23d6d824bc6453d01 Mon Sep 17 00:00:00 2001 From: geronet1 Date: Fri, 19 Apr 2024 15:11:13 +0200 Subject: [PATCH 07/11] fix total info --- src/web/html/index.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/web/html/index.html b/src/web/html/index.html index 82bf36d4..864dc762 100644 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -156,9 +156,10 @@ document.getElementById("iv").replaceChildren(p); if (count > 1) { - p.append(svg(iconInfo, 30, 30, "icon icon-info"), span("Total: " + total + " W"), br()); - document.getElementById("total").replaceChildren(p); - document.getElementById("total").appendChild(div(["class=\"hr\""])); + 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"])); } } From ce1de81e42e5501b995584b69adf94008ec2dda8 Mon Sep 17 00:00:00 2001 From: geronet1 Date: Sat, 18 May 2024 21:51:37 +0200 Subject: [PATCH 08/11] don't publish zero channels over mqtt --- src/publisher/pubMqttIvData.h | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 7412ce15..be6ac2c0 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -215,9 +215,13 @@ class PubMqttIvData { if (mJson && RealTimeRunData_Debug == mCmd) { DynamicJsonDocument doc(300); std::array buf; + bool zero = true; for (mPos = 0; mPos < rec->length; mPos++) { - doc[fields[rec->assign[mPos].fieldId]] = ah::round3(mIv->getValue(mPos, rec)); + double value = ah::round3(mIv->getValue(mPos, rec)); + if (value != 0) + zero = false; + doc[fields[rec->assign[mPos].fieldId]] = value; bool publish = false; if (mPos != rec->length - 1) { // not last one @@ -228,11 +232,15 @@ class PubMqttIvData { if (publish) { publish = false; - // if next channel or end->publish - serializeJson(doc, buf.data(), buf.size()); + // if next channel or end->publish but not if values are all zero + if (!zero) + { + 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); + } + zero = true; doc.clear(); - snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d", mIv->config->name, rec->assign[mPos].ch); - mPublish(mSubTopic.data(), buf.data(), false, QOS_0); } } } From 07dfb5fcd3a27afb20c4b4554d0c53af91a095b2 Mon Sep 17 00:00:00 2001 From: geronet1 Date: Tue, 21 May 2024 09:54:02 +0200 Subject: [PATCH 09/11] HMT-1600/1800/2000 support --- src/app.h | 8 +++++ src/appInterface.h | 1 + src/hm/hmDefines.h | 11 ++++--- src/hm/hmInverter.h | 6 +++- src/hms/hmsDefines.h | 61 +++++++++++++++++++++++++++++++++++ src/publisher/pubMqtt.h | 4 +++ src/publisher/pubMqttIvData.h | 20 ++++-------- 7 files changed, 92 insertions(+), 19 deletions(-) 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/hm/hmDefines.h b/src/hm/hmDefines.h index 06d0aad0..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"}; @@ -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 34d04491..860cf51d 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -541,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; } @@ -985,7 +989,7 @@ T calcMaxTempCh0(Inverter<> *iv, uint8_t arg0) { } } if(Temp > maxTemp) { - iv->tsMaxTemp = *iv->timestamp; + iv->tsMaxTemperature = *iv->Timestamp; return Temp; } } diff --git a/src/hms/hmsDefines.h b/src/hms/hmsDefines.h index c71aa796..5d6647bb 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 // FIXME + //------------------------------------- // HMT-1800, HMT-2250 //------------------------------------- diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 71f53f7b..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; diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 984578ff..afd6165b 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -27,7 +27,7 @@ class PubMqttIvData { void setup(IApp *app, HMSYSTEM *sys, uint32_t *utcTs, std::queue *sendList) { mApp = app; mSys = sys; - mJson = json; + mJson = app->getMqttJsonEnabled(); mUtcTimestamp = utcTs; mSendList = sendList; mState = IDLE; @@ -213,13 +213,9 @@ class PubMqttIvData { if (mJson && RealTimeRunData_Debug == mCmd) { DynamicJsonDocument doc(300); std::array buf; - bool zero = true; for (mPos = 0; mPos < rec->length; mPos++) { - double value = ah::round3(mIv->getValue(mPos, rec)); - if (value != 0) - zero = false; - doc[fields[rec->assign[mPos].fieldId]] = value; + doc[fields[rec->assign[mPos].fieldId]] = ah::round3(mIv->getValue(mPos, rec)); bool publish = false; if (mPos != rec->length - 1) { // not last one @@ -230,14 +226,10 @@ class PubMqttIvData { if (publish) { publish = false; - // if next channel or end->publish but not if values are all zero - if (!zero) - { - 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); - } - zero = true; + // 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(); } } From 44a864fd57c5a057b97ae214d3235f52a1095da6 Mon Sep 17 00:00:00 2001 From: geronet1 Date: Sat, 25 May 2024 09:06:45 +0200 Subject: [PATCH 10/11] HMT4CH_PAYLOAD_LEN --- src/hms/hmsDefines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hms/hmsDefines.h b/src/hms/hmsDefines.h index 5d6647bb..07aec682 100644 --- a/src/hms/hmsDefines.h +++ b/src/hms/hmsDefines.h @@ -190,7 +190,7 @@ const byteAssign_t hmt4chAssignment[] = { { 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 // FIXME +#define HMT4CH_PAYLOAD_LEN 98 //------------------------------------- // HMT-1800, HMT-2250 From 940cd71582b20953d46b10b495c70644204b6aab Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 30 May 2024 22:37:17 +0200 Subject: [PATCH 11/11] reviewed PR #1541 --- .../htmlPreprocessorDefines.cpython-311.pyc | Bin 2235 -> 2175 bytes src/app.h | 8 ------ src/appInterface.h | 1 - src/config/settings.h | 2 +- src/hm/hmInverter.h | 25 ----------------- src/publisher/pubMqtt.h | 6 +--- src/publisher/pubMqttIvData.h | 26 ++++++++---------- 7 files changed, 14 insertions(+), 54 deletions(-) diff --git a/scripts/__pycache__/htmlPreprocessorDefines.cpython-311.pyc b/scripts/__pycache__/htmlPreprocessorDefines.cpython-311.pyc index 8b8e34409896b76a6d2fa979407131efe3b7e1f0..6dca7de6a79130b4cda26f55fab17c7adff71d33 100644 GIT binary patch delta 75 zcmdlj_+Nl`IWI340}yjL8rYbMSb*v#SFjrk a837p$40l;LJCqx}TD%&(?oQsseii@-b0!l2 diff --git a/src/app.h b/src/app.h index 12d03d0b..634696f2 100644 --- a/src/app.h +++ b/src/app.h @@ -239,14 +239,6 @@ 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 92fade46..f2292ec8 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -52,7 +52,6 @@ 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 d10f641b..02beedce 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -486,7 +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.json = false; // off mCfg.mqtt.enableRetain = true; mCfg.inst.sendInterval = SEND_INTERVAL; diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 860cf51d..b72ec5ab 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -53,9 +53,6 @@ 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); @@ -975,28 +972,6 @@ 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/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index f422fad7..f092a159 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -62,7 +62,7 @@ class PubMqtt { mUptime = uptime; mIntervalTimeout = 1; - SendIvData.setup(app, sys, utcTs, &mSendList); + SendIvData.setup(app, sys, cfg_mqtt, utcTs, &mSendList); SendIvData.setPublishFunc([this](const char *subTopic, const char *payload, bool retained, uint8_t qos) { publish(subTopic, payload, retained, true, qos); }); @@ -235,10 +235,6 @@ class PubMqtt { return mRxCnt; } - inline bool isJson() { - return mCfgMqtt->json; - } - void sendDiscoveryConfig(void) { DPRINTLN(DBG_VERBOSE, F("sendMqttDiscoveryConfig")); mDiscovery.running = true; diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index afd6165b..d2ac2fae 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -24,10 +24,10 @@ class PubMqttIvData { public: PubMqttIvData() : mTotal{}, mSubTopic{}, mVal{} {} - void setup(IApp *app, HMSYSTEM *sys, uint32_t *utcTs, std::queue *sendList) { + void setup(IApp *app, HMSYSTEM *sys, cfgMqtt_t *cfg_mqtt, uint32_t *utcTs, std::queue *sendList) { mApp = app; mSys = sys; - mJson = app->getMqttJsonEnabled(); + mCfg = cfg_mqtt; mUtcTimestamp = utcTs; mSendList = sendList; mState = IDLE; @@ -194,13 +194,13 @@ class PubMqttIvData { static_cast(mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec)), static_cast(mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_VERSION, rec))); } else { - if (!mJson) { + if (!mCfg->json) { 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 (InverterDevInform_All == mCmd || InverterDevInform_Simple == mCmd || !mJson) { + if ((InverterDevInform_All == mCmd) || (InverterDevInform_Simple == mCmd) || !mCfg->json) { 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)) @@ -210,26 +210,24 @@ class PubMqttIvData { mPos++; } else { if (MqttSentStatus::LAST_SUCCESS_SENT == rec->mqttSentStatus) { - if (mJson && RealTimeRunData_Debug == mCmd) { + if (mCfg->json && (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 (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()); + serializeJson(doc, mVal.data(), mVal.size()); snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d", mIv->config->name, rec->assign[mPos].ch); - mPublish(mSubTopic.data(), buf.data(), false, QOS_0); + mPublish(mSubTopic.data(), mVal.data(), false, QOS_0); doc.clear(); } } @@ -292,14 +290,14 @@ class PubMqttIvData { mTotal[4] = mApp->getTotalMaxPower(); break; } - if (!mJson) { + if (!mCfg->json) { 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) { + if (mCfg->json) { int type[5] = {FLD_PAC, FLD_YT, FLD_YD, FLD_PDC, FLD_MP}; snprintf(mVal.data(), mVal.size(), "{"); @@ -321,6 +319,7 @@ class PubMqttIvData { private: IApp *mApp = nullptr; + cfgMqtt_t *mCfg = nullptr; HMSYSTEM *mSys = nullptr; uint32_t *mUtcTimestamp = nullptr; @@ -339,8 +338,7 @@ class PubMqttIvData { bool mRTRDataHasBeenSent = false; std::array mSubTopic; - std::array mVal; - bool mJson; + std::array mVal; std::queue *mSendList = nullptr; };