Skip to content

Commit

Permalink
MQTT JSON Payload pro Kanal und total, auswählbar
Browse files Browse the repository at this point in the history
NodeRED Beispiel
Bug #1522
  • Loading branch information
geronet1 committed Mar 29, 2024
1 parent 2a4c836 commit 5294ae3
Show file tree
Hide file tree
Showing 8 changed files with 537 additions and 12 deletions.
4 changes: 4 additions & 0 deletions src/config/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<uint16_t>(obj, F("port"), &mCfg.mqtt.port);
getVal<uint16_t>(obj, F("intvl"), &mCfg.mqtt.interval);
getVal<bool>(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);
Expand Down
2 changes: 1 addition & 1 deletion src/publisher/pubMqtt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
Expand Down
63 changes: 53 additions & 10 deletions src/publisher/pubMqttIvData.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ class PubMqttIvData {
public:
PubMqttIvData() : mTotal{}, mSubTopic{}, mVal{} {}

void setup(HMSYSTEM *sys, uint32_t *utcTs, std::queue<sendListCmdIv> *sendList) {
void setup(HMSYSTEM *sys, bool json, uint32_t *utcTs, std::queue<sendListCmdIv> *sendList) {
mSys = sys;
mJson = json;
mUtcTimestamp = utcTs;
mSendList = sendList;
mState = IDLE;
Expand Down Expand Up @@ -197,18 +198,43 @@ class PubMqttIvData {
static_cast<int>(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<char, 300> 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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -294,6 +336,7 @@ class PubMqttIvData {

std::array<char, (32 + MAX_NAME_LENGTH + 1)> mSubTopic;
std::array<char, 160> mVal;
bool mJson;

std::queue<sendListCmdIv> *mSendList = nullptr;
};
Expand Down
3 changes: 2 additions & 1 deletion src/web/RestApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down
5 changes: 5 additions & 0 deletions src/web/html/setup.html
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@
<div class="col-12 col-sm-3 my-2">Topic</div>
<div class="col-12 col-sm-9"><input type="text" name="mqttTopic" pattern="[\-\+A-Za-z0-9\.\/#\$%&=_]+" title="Invalid input" /></div>
</div>
<div class="row mb-3">
<div class="col-12 col-sm-3 my-2">{#MQTT_JSON}</div>
<div class="col-12 col-sm-9"><input type="checkbox" name="mqttJson" /></div>
</div>
<p class="des">{#MQTT_NOTE}</p>
<div class="row mb-3">
<div class="col-12 col-sm-3 my-2">{#INTERVAL}</div>
Expand Down Expand Up @@ -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) {
Expand Down
5 changes: 5 additions & 0 deletions src/web/lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
1 change: 1 addition & 0 deletions src/web/web.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
Loading

0 comments on commit 5294ae3

Please sign in to comment.