Browse Source

Mono-Display: show values in offline mode #498

improved wifi class #483
added communication enable / disable (to test mutliple DTUs with the same inverter)
fix factory reset #495
pull/518/head
lumapu 2 years ago
parent
commit
c8c8b99957
  1. 6
      src/CHANGES.md
  2. 74
      src/app.cpp
  3. 14
      src/config/settings.h
  4. 2
      src/defines.h
  5. 14
      src/publisher/pubMqtt.h
  6. 3
      src/web/RestApi.h
  7. 2
      src/web/html/api.js
  8. 2
      src/web/html/index.html
  9. 10
      src/web/html/setup.html
  10. 86
      src/web/html/visualization.html
  11. 2
      src/web/web.h
  12. 10
      src/wifi/ahoywifi.cpp

6
src/CHANGES.md

@ -1,5 +1,11 @@
# Changelog
## 0.5.53
* Mono-Display: show values in offline mode #498
* improved wifi class #483
* added communication enable / disable (to test mutliple DTUs with the same inverter)
* fix factory reset #495
## 0.5.52
* improved ahoyWifi class
* added interface class for app

74
src/app.cpp

@ -190,46 +190,48 @@ void app::tickSend(void) {
} while ((NULL == iv) && ((maxLoop--) > 0));
if (NULL != iv) {
if (!mPayload.isComplete(iv))
mPayload.process(false, mConfig->nrf.maxRetransPerPyld, &mStat);
if (!mPayload.isComplete(iv)) {
if (0 == mPayload.getMaxPacketId(iv))
mStat.rxFailNoAnser++;
else
mStat.rxFail++;
iv->setQueuedCmdFinished(); // command failed
if (mConfig->serial.debug)
DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout"));
if (mConfig->serial.debug) {
DPRINT(DBG_INFO, F("(#") + String(iv->id) + ") ");
DPRINTLN(DBG_INFO, F("no Payload received! (retransmits: ") + String(mPayload.getRetransmits(iv)) + ")");
if(iv->config->enabled) {
if (!mPayload.isComplete(iv))
mPayload.process(false, mConfig->nrf.maxRetransPerPyld, &mStat);
if (!mPayload.isComplete(iv)) {
if (0 == mPayload.getMaxPacketId(iv))
mStat.rxFailNoAnser++;
else
mStat.rxFail++;
iv->setQueuedCmdFinished(); // command failed
if (mConfig->serial.debug)
DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout"));
if (mConfig->serial.debug) {
DPRINT(DBG_INFO, F("(#") + String(iv->id) + ") ");
DPRINTLN(DBG_INFO, F("no Payload received! (retransmits: ") + String(mPayload.getRetransmits(iv)) + ")");
}
}
}
mPayload.reset(iv, mTimestamp);
mPayload.request(iv);
mPayload.reset(iv, mTimestamp);
mPayload.request(iv);
yield();
if (mConfig->serial.debug) {
DPRINTLN(DBG_DEBUG, F("app:loop WiFi WiFi.status ") + String(WiFi.status()));
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Requesting Inv SN ") + String(iv->config->serial.u64, HEX));
}
yield();
if (mConfig->serial.debug) {
DPRINTLN(DBG_DEBUG, F("app:loop WiFi WiFi.status ") + String(WiFi.status()));
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Requesting Inv SN ") + String(iv->config->serial.u64, HEX));
}
if (iv->devControlRequest) {
if (mConfig->serial.debug)
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Devcontrol request ") + String(iv->devControlCmd) + F(" power limit ") + String(iv->powerLimit[0]));
mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit);
mPayload.setTxCmd(iv, iv->devControlCmd);
iv->clearCmdQueue();
iv->enqueCommand<InfoCommand>(SystemConfigPara); // read back power limit
} else {
uint8_t cmd = iv->getQueuedCmd();
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket"));
mSys->Radio.sendTimePacket(iv->radioId.u64, cmd, mPayload.getTs(iv), iv->alarmMesIndex);
mPayload.setTxCmd(iv, cmd);
mRxTicker = 0;
if (iv->devControlRequest) {
if (mConfig->serial.debug)
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Devcontrol request ") + String(iv->devControlCmd) + F(" power limit ") + String(iv->powerLimit[0]));
mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit);
mPayload.setTxCmd(iv, iv->devControlCmd);
iv->clearCmdQueue();
iv->enqueCommand<InfoCommand>(SystemConfigPara); // read back power limit
} else {
uint8_t cmd = iv->getQueuedCmd();
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket"));
mSys->Radio.sendTimePacket(iv->radioId.u64, cmd, mPayload.getTs(iv), iv->alarmMesIndex);
mPayload.setTxCmd(iv, cmd);
mRxTicker = 0;
}
}
}
} else {

14
src/config/settings.h

@ -267,6 +267,8 @@ class settings {
mCfg.led.led0 = DEF_LED0_PIN;
mCfg.led.led1 = DEF_LED1_PIN;
memset(&mCfg.inst, 0, sizeof(cfgInst_t));
}
void jsonWifi(JsonObject obj, bool set = false) {
@ -374,9 +376,9 @@ class settings {
void jsonInst(JsonObject obj, bool set = false) {
if(set)
obj[F("en")] = mCfg.inst.enabled;
obj[F("en")] = (bool)mCfg.inst.enabled;
else
mCfg.inst.enabled = obj[F("en")];
mCfg.inst.enabled = (bool)obj[F("en")];
JsonArray ivArr;
if(set)
@ -391,15 +393,15 @@ class settings {
void jsonIv(JsonObject obj, cfgIv_t *cfg, bool set = false) {
if(set) {
obj[F("en")] = cfg->enabled;
obj[F("name")] = cfg->name;
obj[F("sn")] = cfg->serial.u64;
obj[F("en")] = (bool)cfg->enabled;
obj[F("name")] = cfg->name;
obj[F("sn")] = cfg->serial.u64;
for(uint8_t i = 0; i < 4; i++) {
obj[F("pwr")][i] = cfg->chMaxPwr[i];
obj[F("chName")][i] = cfg->chName[i];
}
} else {
cfg->enabled = obj[F("en")];
cfg->enabled = (bool)obj[F("en")];
snprintf(cfg->name, MAX_NAME_LENGTH, "%s", obj[F("name")].as<const char*>());
cfg->serial.u64 = obj[F("sn")];
for(uint8_t i = 0; i < 4; i++) {

2
src/defines.h

@ -13,7 +13,7 @@
//-------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 5
#define VERSION_PATCH 52
#define VERSION_PATCH 53
//-------------------------------------
typedef struct {

14
src/publisher/pubMqtt.h

@ -114,7 +114,7 @@ class PubMqtt {
continue; // skip to next inverter
rec = iv->getRecordStruct(RealTimeRunData_Debug);
if (!iv->isAvailable(*mUtcTimestamp, rec)) {
if ((!iv->isAvailable(*mUtcTimestamp, rec)) || (!iv->config->enabled)) {
snprintf(topic, MQTT_TOPIC_LEN + 15, "%s/available_text", iv->config->name);
snprintf(val, 32, "not available and not producing");
publish(topic, val, true);
@ -263,7 +263,7 @@ class PubMqtt {
subscribe("ctrl/#");
subscribe("setup/#");
subscribe("status/#");
//subscribe("status/#");
}
void onDisconnect(espMqttClientTypes::DisconnectReason reason) {
@ -293,7 +293,7 @@ class PubMqtt {
}
void onMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total) {
DPRINTLN(DBG_VERBOSE, F("MQTT got topic: ") + String(topic));
DPRINTLN(DBG_INFO, F("MQTT got topic: ") + String(topic));
if(NULL == mSubscriptionCb)
return;
@ -394,10 +394,12 @@ class PubMqtt {
// inverter status
uint8_t status = MQTT_STATUS_AVAIL_PROD;
if (!iv->isAvailable(*mUtcTimestamp, rec)) {
if ((!iv->isAvailable(*mUtcTimestamp, rec)) || (!iv->config->enabled)) {
status = MQTT_STATUS_NOT_AVAIL_NOT_PROD;
totalIncomplete = true;
allAvail = false;
if(iv->config->enabled) { // only change all-avail if inverter is enabled!
totalIncomplete = true;
allAvail = false;
}
}
else if (!iv->isProducing(*mUtcTimestamp, rec)) {
mIvAvail = true;

3
src/web/RestApi.h

@ -246,6 +246,7 @@ class RestApi {
iv = mSys->getInverterByPos(i);
if(NULL != iv) {
JsonObject obj2 = invArr.createNestedObject();
obj2[F("enabled")] = (bool)iv->config->enabled;
obj2[F("id")] = i;
obj2[F("name")] = String(iv->config->name);
obj2[F("serial")] = String(iv->config->serial.u64, HEX);
@ -353,6 +354,7 @@ class RestApi {
if(NULL != iv) {
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
JsonObject invObj = inv.createNestedObject();
invObj[F("enabled")] = (bool)iv->config->enabled;
invObj[F("id")] = i;
invObj[F("name")] = String(iv->config->name);
invObj[F("version")] = String(iv->fwVersion);
@ -412,6 +414,7 @@ class RestApi {
if(NULL != iv) {
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
JsonObject obj2 = invArr.createNestedObject();
obj2[F("enabled")] = (bool)iv->config->enabled;
obj2[F("name")] = String(iv->config->name);
obj2[F("channels")] = iv->channels;
obj2[F("power_limit_read")] = ah::round3(iv->actPowerLimit);

2
src/web/html/api.js

@ -92,7 +92,7 @@ function inp(name, val, max=32, cl=["text"], id=null, type=null) {
e = document.createElement('input');
e.classList.add(...cl);
e.name = name;
e.value = val;
if(null != val) e.value = val;
if(null != max) e.maxLength = max;
if(null != id) e.id = id;
if(null != type) e.type = type;

2
src/web/html/index.html

@ -174,6 +174,8 @@
html += "-> last successful transmission: " + date.toLocaleString('de-DE') + "\n";
}
}
if(false == i["enabled"])
html += "-> disabled\n";
}
document.getElementById("iv").innerHTML = html;

10
src/web/html/setup.html

@ -194,7 +194,7 @@
document.getElementById("btnAdd").addEventListener("click", function() {
if(highestId <= (maxInv-1))
ivHtml(JSON.parse('{"name":"","serial":"","channels":4,"ch_max_power":[0,0,0,0],"ch_name":["","","",""]}'), highestId + 1);
ivHtml(JSON.parse('{"enabled":true,"name":"","serial":"","channels":4,"ch_max_power":[0,0,0,0],"ch_name":["","","",""]}'), highestId + 1);
});
function apiCbWifi(obj) {
@ -266,12 +266,16 @@
iv.appendChild(des("Inverter " + id));
id = "inv" + id;
iv.appendChild(lbl(id + "Enable", "Communication Enable"));
var en = inp(id + "Enable", null, null, ["cb"], id + "Enable", "checkbox");
en.checked = obj["enabled"];
iv.appendChild(en);
iv.appendChild(br());
iv.appendChild(lbl(id + "Addr", "Serial Number (12 digits)*"));
var addr = inp(id + "Addr", obj["serial"], 12)
var addr = inp(id + "Addr", obj["serial"], 12);
iv.appendChild(addr);
['keyup', 'change'].forEach(function(evt) {
addr.addEventListener(evt, (e) => {
var serial = addr.value.substring(0,4);
var max = 0;

86
src/web/html/visualization.html

@ -59,56 +59,58 @@
ivHtml.push(tDiv);
for(var iv of obj) {
main = div(["iv"]);
var ch0 = div(["ch-iv"]);
var limit = iv["power_limit_read"] + "%";
if(limit == "65535%")
limit = "n/a";
ch0.appendChild(span(iv["name"] + " Limit " + limit + " | last Alarm: " + iv["last_alarm"], ["head"]));
for(var j = 0; j < root.ch0_fld_names.length; j++) {
var val = Math.round(iv["ch"][0][j] * 100) / 100;
var sub = div(["subgrp"]);
sub.appendChild(span(val + " " + span(root["ch0_fld_units"][j], ["unit"]).innerHTML, ["value"]));
sub.appendChild(span(root["ch0_fld_names"][j], ["info"]));
ch0.appendChild(sub);
switch(j) {
case 2: total[j] += val; break; // P_AC
case 6: total[j] += val; break; // YieldTotal
case 7: total[j] += val; break; // YieldDay
case 8: total[j] += val; break; // P_DC
case 10: total[j] += val; break; // Q_AC
if(iv["enabled"]) {
main = div(["iv"]);
var ch0 = div(["ch-iv"]);
var limit = iv["power_limit_read"] + "%";
if(limit == "65535%")
limit = "n/a";
ch0.appendChild(span(iv["name"] + " Limit " + limit + " | last Alarm: " + iv["last_alarm"], ["head"]));
for(var j = 0; j < root.ch0_fld_names.length; j++) {
var val = Math.round(iv["ch"][0][j] * 100) / 100;
var sub = div(["subgrp"]);
sub.appendChild(span(val + " " + span(root["ch0_fld_units"][j], ["unit"]).innerHTML, ["value"]));
sub.appendChild(span(root["ch0_fld_names"][j], ["info"]));
ch0.appendChild(sub);
switch(j) {
case 2: total[j] += val; break; // P_AC
case 6: total[j] += val; break; // YieldTotal
case 7: total[j] += val; break; // YieldDay
case 8: total[j] += val; break; // P_DC
case 10: total[j] += val; break; // Q_AC
}
}
}
main.appendChild(ch0);
main.appendChild(ch0);
for(var i = 1; i < (iv["channels"] + 1); i++) {
var ch = div(["ch"]);
ch.appendChild(span(("" == iv["ch_names"][i]) ? ("CHANNEL " + i) : iv["ch_names"][i], ["head"]));
for(var i = 1; i < (iv["channels"] + 1); i++) {
var ch = div(["ch"]);
ch.appendChild(span(("" == iv["ch_names"][i]) ? ("CHANNEL " + i) : iv["ch_names"][i], ["head"]));
for(var j = 0; j < root.fld_names.length; j++) {
var val = Math.round(iv["ch"][i][j] * 100) / 100;
ch.appendChild(span(val + " " + span(root["fld_units"][j], ["unit"]).innerHTML, ["value"]));
ch.appendChild(span(root["fld_names"][j], ["info"]));
for(var j = 0; j < root.fld_names.length; j++) {
var val = Math.round(iv["ch"][i][j] * 100) / 100;
ch.appendChild(span(val + " " + span(root["fld_units"][j], ["unit"]).innerHTML, ["value"]));
ch.appendChild(span(root["fld_names"][j], ["info"]));
}
main.appendChild(ch);
}
main.appendChild(ch);
}
var ts = div(["ts"]);
var ageInfo = "Last received data requested at: ";
if(iv["ts_last_success"] > 0) {
var date = new Date(iv["ts_last_success"] * 1000);
ageInfo += date.toLocaleString('de-DE');
}
else
ageInfo += "nothing received";
var ts = div(["ts"]);
var ageInfo = "Last received data requested at: ";
if(iv["ts_last_success"] > 0) {
var date = new Date(iv["ts_last_success"] * 1000);
ageInfo += date.toLocaleString('de-DE');
}
else
ageInfo += "nothing received";
ts.innerHTML = ageInfo;
ts.innerHTML = ageInfo;
main.appendChild(ts);
ivHtml.push(main);
main.appendChild(ts);
ivHtml.push(main);
}
}
// total

2
src/web/web.h

@ -406,6 +406,8 @@ class Web {
Inverter<> *iv;
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) {
iv = mSys->getInverterByPos(i, false);
// enable communication
iv->config->enabled = (request->arg("inv" + String(i) + "Enable") == "on");
// address
request->arg("inv" + String(i) + "Addr").toCharArray(buf, 20);
if(strlen(buf) == 0)

10
src/wifi/ahoywifi.cpp

@ -31,8 +31,14 @@ void ahoywifi::setup(settings_t *config, uint32_t *utcTimestamp) {
setupAp();
#endif
#if !defined(AP_ONLY)
if(mConfig->valid)
setupStation();
if(mConfig->valid) {
#if !defined(FB_WIFI_OVERRIDDEN)
if(strncmp(mConfig->sys.stationSsid, FB_WIFI_SSID, 14) != 0)
setupStation();
#else
setupStation();
#endif
}
#endif
#if defined(ESP8266)

Loading…
Cancel
Save