mirror of
https://github.com/lumapu/ahoy.git
synced 2025-06-01 10:11:37 +02:00
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
This commit is contained in:
parent
faf918c018
commit
c8c8b99957
12 changed files with 126 additions and 95 deletions
|
@ -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
|
||||
|
|
70
src/app.cpp
70
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(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++;
|
||||
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)) + ")");
|
||||
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 {
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//-------------------------------------
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 5
|
||||
#define VERSION_PATCH 52
|
||||
#define VERSION_PATCH 53
|
||||
|
||||
//-------------------------------------
|
||||
typedef struct {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"]));
|
||||
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);
|
||||
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
|
||||
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";
|
||||
|
||||
ts.innerHTML = ageInfo;
|
||||
|
||||
main.appendChild(ts);
|
||||
ivHtml.push(main);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
main.appendChild(ts);
|
||||
ivHtml.push(main);
|
||||
}
|
||||
|
||||
// total
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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…
Add table
Add a link
Reference in a new issue