From c8c8b9995783dff7dbb3c519f179357518354482 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 15 Dec 2022 23:19:24 +0100 Subject: [PATCH] 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 --- src/CHANGES.md | 6 +++ src/app.cpp | 74 ++++++++++++++-------------- src/config/settings.h | 14 +++--- src/defines.h | 2 +- src/publisher/pubMqtt.h | 14 +++--- src/web/RestApi.h | 3 ++ src/web/html/api.js | 2 +- src/web/html/index.html | 2 + src/web/html/setup.html | 10 ++-- src/web/html/visualization.html | 86 +++++++++++++++++---------------- src/web/web.h | 2 + src/wifi/ahoywifi.cpp | 10 +++- 12 files changed, 128 insertions(+), 97 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index ce80ed95..0fec9ed9 100644 --- a/src/CHANGES.md +++ b/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 diff --git a/src/app.cpp b/src/app.cpp index 24b5fceb..6a679e1a 100644 --- a/src/app.cpp +++ b/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(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(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 { diff --git a/src/config/settings.h b/src/config/settings.h index 01d2b8c1..f6b3a661 100644 --- a/src/config/settings.h +++ b/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()); cfg->serial.u64 = obj[F("sn")]; for(uint8_t i = 0; i < 4; i++) { diff --git a/src/defines.h b/src/defines.h index ac80b7a8..04a8dd88 100644 --- a/src/defines.h +++ b/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 { diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index f94d2206..dfea49a1 100644 --- a/src/publisher/pubMqtt.h +++ b/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; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index e2a7714c..ef87281f 100644 --- a/src/web/RestApi.h +++ b/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); diff --git a/src/web/html/api.js b/src/web/html/api.js index 508a671d..bdd0b6df 100644 --- a/src/web/html/api.js +++ b/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; diff --git a/src/web/html/index.html b/src/web/html/index.html index 54f99e48..5ae212f5 100644 --- a/src/web/html/index.html +++ b/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; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 682d0973..3a83c5ee 100644 --- a/src/web/html/setup.html +++ b/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; diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index a911f79a..f154c815 100644 --- a/src/web/html/visualization.html +++ b/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 diff --git a/src/web/web.h b/src/web/web.h index d5b10014..ccf33ea7 100644 --- a/src/web/web.h +++ b/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) diff --git a/src/wifi/ahoywifi.cpp b/src/wifi/ahoywifi.cpp index eb7cb1e5..203df285 100644 --- a/src/wifi/ahoywifi.cpp +++ b/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)