mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-29 08:46:11 +02:00
0.8.2
* beautified inverter settings in `setup` (preperation for future, settings become more inverter dependent)
This commit is contained in:
parent
e550111f95
commit
975f6923d3
12 changed files with 223 additions and 166 deletions
|
@ -1,5 +1,8 @@
|
|||
# Development Changes
|
||||
|
||||
## 0.8.2 - 2023-11-08
|
||||
* beautified inverter settings in `setup` (preperation for future, settings become more inverter dependent)
|
||||
|
||||
## 0.8.1 - 2023-11-05
|
||||
* added tx channel heuristics (per inverter)
|
||||
* fix statistics counter
|
||||
|
|
|
@ -158,7 +158,7 @@
|
|||
#define MAX_RF_PAYLOAD_SIZE 32
|
||||
|
||||
// maximum total payload buffers (must be greater than the number of received frame fragments)
|
||||
#define MAX_PAYLOAD_ENTRIES 10
|
||||
#define MAX_PAYLOAD_ENTRIES 20
|
||||
|
||||
// number of seconds since last successful response, before inverter is marked inactive
|
||||
#define INVERTER_INACT_THRES_SEC 5*60
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//-------------------------------------
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 8
|
||||
#define VERSION_PATCH 1
|
||||
#define VERSION_PATCH 2
|
||||
|
||||
//-------------------------------------
|
||||
typedef struct {
|
||||
|
|
|
@ -118,7 +118,6 @@ class Inverter {
|
|||
record_t<REC_TYP> recordHwInfo; // structure for simple (hardware) info values
|
||||
record_t<REC_TYP> recordConfig; // structure for system config values
|
||||
record_t<REC_TYP> recordAlarm; // structure for alarm values
|
||||
bool initialized; // needed to check if the inverter was correctly added (ESP32 specific - union types are never null)
|
||||
bool isConnected; // shows if inverter was successfully identified (fw version and hardware info)
|
||||
InverterStatus status; // indicates the current inverter status
|
||||
std::array<alarm_t, 10> lastAlarm; // holds last 10 alarms
|
||||
|
@ -142,7 +141,6 @@ class Inverter {
|
|||
actPowerLimit = 0xffff; // init feedback from inverter to -1
|
||||
mDevControlRequest = false;
|
||||
devControlCmd = InitDataState;
|
||||
initialized = false;
|
||||
alarmMesIndex = 0;
|
||||
isConnected = false;
|
||||
status = InverterStatus::OFF;
|
||||
|
@ -193,7 +191,6 @@ class Inverter {
|
|||
initAssignment(&recordConfig, SystemConfigPara);
|
||||
initAssignment(&recordAlarm, AlarmData);
|
||||
toRadioId();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
uint8_t getPosByChFld(uint8_t channel, uint8_t fieldId, record_t<> *rec) {
|
||||
|
|
|
@ -114,7 +114,7 @@ class HmSystem {
|
|||
DPRINTLN(DBG_VERBOSE, F("hmSystem.h:getInverterByPos"));
|
||||
if(pos >= MAX_INVERTER)
|
||||
return NULL;
|
||||
else if((mInverter[pos].initialized && mInverter[pos].config->serial.u64 != 0ULL) || false == check)
|
||||
else if((mInverter[pos].config->serial.u64 != 0ULL) || (false == check))
|
||||
return &mInverter[pos];
|
||||
else
|
||||
return NULL;
|
||||
|
|
|
@ -124,7 +124,7 @@ class RestApi {
|
|||
|
||||
void onApiPostBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
|
||||
DPRINTLN(DBG_VERBOSE, "onApiPostBody");
|
||||
DynamicJsonDocument json(200);
|
||||
DynamicJsonDocument json(800);
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, 200);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
|
@ -708,8 +708,35 @@ class RestApi {
|
|||
mApp->setTimestamp(0); // 0: update ntp flag
|
||||
else if(F("serial_utc_offset") == jsonIn[F("cmd")])
|
||||
mTimezoneOffset = jsonIn[F("val")];
|
||||
else if(F("discovery_cfg") == jsonIn[F("cmd")]) {
|
||||
else if(F("discovery_cfg") == jsonIn[F("cmd")])
|
||||
mApp->setMqttDiscoveryFlag(); // for homeassistant
|
||||
else if(F("save_iv") == jsonIn[F("cmd")]) {
|
||||
Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")], false);
|
||||
iv->config->enabled = jsonIn[F("en")];
|
||||
iv->config->serial.u64 = jsonIn[F("ser")];
|
||||
snprintf(iv->config->name, MAX_NAME_LENGTH, "%s", jsonIn[F("name")].as<const char*>());
|
||||
|
||||
for(uint8_t i = 0; i < 6; i++) {
|
||||
iv->config->chMaxPwr[i] = jsonIn[F("ch")][i][F("pwr")];
|
||||
iv->config->yieldCor[i] = jsonIn[F("ch")][i][F("yld")];
|
||||
snprintf(iv->config->chName[i], MAX_NAME_LENGTH, "%s", jsonIn[F("ch")][i][F("name")].as<const char*>());
|
||||
}
|
||||
|
||||
switch(iv->config->serial.b[4]) {
|
||||
case 0x24:
|
||||
case 0x22:
|
||||
case 0x21: iv->type = INV_TYPE_1CH; iv->channels = 1; break;
|
||||
|
||||
case 0x44:
|
||||
case 0x42:
|
||||
case 0x41: iv->type = INV_TYPE_2CH; iv->channels = 2; break;
|
||||
|
||||
case 0x64:
|
||||
case 0x62:
|
||||
case 0x61: iv->type = INV_TYPE_4CH; iv->channels = 4; break;
|
||||
default: break;
|
||||
}
|
||||
mApp->saveSettings(false); // without reboot
|
||||
} else {
|
||||
jsonOut[F("error")] = F("unknown cmd");
|
||||
return false;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/**
|
||||
* SVG ICONS
|
||||
*/
|
||||
/* SVG ICONS - https://icons.getbootstrap.com */
|
||||
|
||||
iconWifi1 = [
|
||||
"M11.046 10.454c.226-.226.185-.605-.1-.75A6.473 6.473 0 0 0 8 9c-1.06 0-2.062.254-2.946.704-.285.145-.326.524-.1.75l.015.015c.16.16.407.19.611.09A5.478 5.478 0 0 1 8 10c.868 0 1.69.201 2.42.56.203.1.45.07.611-.091l.015-.015zM9.06 12.44c.196-.196.198-.52-.04-.66A1.99 1.99 0 0 0 8 11.5a1.99 1.99 0 0 0-1.02.28c-.238.14-.236.464-.04.66l.706.706a.5.5 0 0 0 .707 0l.708-.707z"
|
||||
|
@ -34,6 +32,15 @@ iconSuccessFull = [
|
|||
"M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"
|
||||
];
|
||||
|
||||
iconGear = [
|
||||
"M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z"
|
||||
];
|
||||
|
||||
iconDel = [
|
||||
"M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z",
|
||||
"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"
|
||||
];
|
||||
|
||||
/**
|
||||
* GENERIC FUNCTIONS
|
||||
*/
|
||||
|
@ -119,7 +126,7 @@ function parseRssi(obj) {
|
|||
icon = iconWifi1;
|
||||
else if(obj["wifi_rssi"] <= -70)
|
||||
icon = iconWifi2;
|
||||
document.getElementById("wifiicon").replaceChildren(svg(icon, 32, 32, "wifi", obj["wifi_rssi"]));
|
||||
document.getElementById("wifiicon").replaceChildren(svg(icon, 32, 32, "icon-fg", obj["wifi_rssi"]));
|
||||
}
|
||||
|
||||
function toIsoDateStr(d) {
|
||||
|
@ -181,6 +188,10 @@ function tr(val1, val2) {
|
|||
]);
|
||||
}
|
||||
|
||||
function badge(success, text, second="error") {
|
||||
return ml("span", {class: "badge badge-" + ((success) ? "success" : second)}, text);
|
||||
}
|
||||
|
||||
function des(val) {
|
||||
e = document.createElement('p');
|
||||
e.classList.add("subdes");
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
--secondary: #0072c8;
|
||||
--nav-active: #555;
|
||||
--footer-bg: #282828;
|
||||
--modal-bg: #666;
|
||||
--modal-bg: #282828;
|
||||
|
||||
--invalid-bg: #400;
|
||||
|
||||
|
|
|
@ -140,14 +140,7 @@
|
|||
<fieldset class="mb-4">
|
||||
<legend class="des">Inverter</legend>
|
||||
<div id="inverter"></div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-12 col-sm-3"></div>
|
||||
<div class="col-12 col-sm-9"><input type="button" id="btnAdd" class="btn" value="Add Inverter"/></div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-12 col-sm-3"><p class="subdes">Note</p></div>
|
||||
<div class="col-12 col-sm-9"><p>A 'max module power' value of '0' disables the channel in 'live' view</p></div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-2">
|
||||
<div class="col-12 col-sm-3"><p class="subdes">General</p></div>
|
||||
<div class="col-12 col-sm-9"></div>
|
||||
|
@ -451,8 +444,6 @@
|
|||
[1, "high active"],
|
||||
];
|
||||
|
||||
const re = /1[0,1,3][2,4,6,8][1,2,4].*/;
|
||||
|
||||
window.onload = function() {
|
||||
for(it of document.getElementsByClassName("s_collapsible")) {
|
||||
it.addEventListener("click", function() {
|
||||
|
@ -471,10 +462,6 @@
|
|||
});
|
||||
}
|
||||
|
||||
document.getElementById("btnAdd").addEventListener("click", function() {
|
||||
ivHtml(JSON.parse('{"enabled":true,"name":"","serial":"","channels":6,"ch_max_pwr":[0,0,0,0,0,0],"ch_name":["","","","","",""],"ch_yield_cor":[0,0,0,0,0,0]}'));
|
||||
});
|
||||
|
||||
function apiCbWifi(obj) {
|
||||
var e = document.getElementById("networks");
|
||||
selDelAllOpt(e);
|
||||
|
@ -573,98 +560,6 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
function ivHtml(obj) {
|
||||
var id = getFreeId();
|
||||
if(null == id) {
|
||||
setHide("btnAdd", true);
|
||||
return;
|
||||
}
|
||||
|
||||
var iv = ml("div", {id: "inv" + id}, null);
|
||||
document.getElementById("inverter").appendChild(iv);
|
||||
iv.appendChild(des("Inverter " + id));
|
||||
id = "inv" + id;
|
||||
|
||||
var addr = ml("input", {name: id + "Addr", class: "text", type: "number", max: 138999999999, value: obj["serial"]}, null);
|
||||
|
||||
iv.append(
|
||||
mlCb(id + "Enable", "Communication Enable", obj["enabled"]),
|
||||
mlE("Serial Number (12 digits)*", addr)
|
||||
);
|
||||
|
||||
['keyup', 'change'].forEach(function(evt) {
|
||||
addr.addEventListener(evt, (e) => {
|
||||
var serial = addr.value.substring(0,4);
|
||||
var max = 0;
|
||||
for(var i=0;i<6;i++) {
|
||||
setHide(id+"ModPwr"+i, true);
|
||||
setHide(id+"ModName"+i, true);
|
||||
setHide(id+"YieldCor"+i, true);
|
||||
}
|
||||
setHide("row"+id+"ModPwr", true);
|
||||
setHide("row"+id+"ModName", true);
|
||||
setHide("row"+id+"YieldCor", true);
|
||||
|
||||
if(serial.charAt(0) == 1) {
|
||||
if((serial.charAt(1) == 0) || (serial.charAt(1) == 1) || (serial.charAt(1) == 3)) {
|
||||
if((serial.charAt(3) == 1) || (serial.charAt(3) == 2) || (serial.charAt(3) == 4)) {
|
||||
switch(serial.charAt(2)) {
|
||||
default:
|
||||
case "2": max = 1; break;
|
||||
case "4": max = 2; break;
|
||||
case "6": max = 4; break;
|
||||
case "8": max = 6; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(max != 0) {
|
||||
for(var i=0;i<max;i++) {
|
||||
setHide(id+"ModPwr"+i, false);
|
||||
setHide(id+"ModName"+i, false);
|
||||
setHide(id+"YieldCor"+i, false);
|
||||
}
|
||||
setHide("row"+id+"ModPwr", false);
|
||||
setHide("row"+id+"ModName", false);
|
||||
setHide("row"+id+"YieldCor", false);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
iv.append(mlE("Name*", inp(id + "Name", obj["name"], 15, ["text"], null, "text", "[\\-\\+A-Za-z0-9.\\/#$%&=_]+", "Invalid input")));
|
||||
|
||||
for(var j of [
|
||||
["ModPwr", "ch_max_pwr", "Max Module Power (Wp)", 4, "[0-9]+"],
|
||||
["ModName", "ch_name", "Module Name", 15, null],
|
||||
["YieldCor", "ch_yield_cor", "Yield Total Correction [kWh]", 8, "[\\-0-9\.]+"]]) {
|
||||
|
||||
var cl = (re.test(obj["serial"])) ? "" : " hide";
|
||||
|
||||
i = 0;
|
||||
arrIn = [];
|
||||
for(it of obj[j[1]]) {
|
||||
arrIn.push(ml("div", {class: "col-3 "},
|
||||
inp(id + j[0] + i, it, j[3], [], id + j[0] + i, "text", j[4], "Invalid input")
|
||||
));
|
||||
i++;
|
||||
}
|
||||
|
||||
iv.append(
|
||||
ml("div", {class: "row mb-2 mb-sm-3" + cl, id: "row" + id + j[0]}, [
|
||||
ml("div", {class: "col-12 col-sm-3 my-2"}, j[2]),
|
||||
ml("div", {class: "col-12 col-sm-9"},
|
||||
ml("div", {class: "row"}, arrIn)
|
||||
)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
var del = ml("input", {class: "btn btnDel", type: "button", id: id+"del", value: "X"}, null);
|
||||
del.addEventListener("click", delIv);
|
||||
iv.append(mlE("Delete", del));
|
||||
}
|
||||
|
||||
function ivGlob(obj) {
|
||||
for(var i of [["invInterval", "interval"], ["invRetry", "retries"], ["yldEff", "yldEff"]])
|
||||
document.getElementsByName(i[0])[0].value = obj[i[1]];
|
||||
|
@ -709,11 +604,177 @@
|
|||
|
||||
function parseIv(obj) {
|
||||
maxInv = obj["max_num_inverters"];
|
||||
for(var i = 0; i < obj.inverter.length; i++)
|
||||
ivHtml(obj.inverter[i]);
|
||||
var lines = [];
|
||||
lines.push(ml("tr", {}, [
|
||||
ml("th", {style: "width: 10%; text-align: center;"}, ""),
|
||||
ml("th", {}, "Name"),
|
||||
ml("th", {}, "Serial"),
|
||||
ml("th", {style: "width: 10%; text-align: center;"}, "Edit"),
|
||||
ml("th", {style: "width: 10%; text-align: center;"}, "Delete")
|
||||
]));
|
||||
|
||||
for(let i = 0; i < obj.inverter.length; i++) {
|
||||
lines.push(ml("tr", {}, [
|
||||
ml("td", {}, badge(obj.inverter[i].enabled, (obj.inverter[i].enabled) ? "enabled" : "disabled")),
|
||||
ml("td", {}, obj.inverter[i].name),
|
||||
ml("td", {}, String(obj.inverter[i].serial)),
|
||||
ml("td", {style: "text-align: center;", onclick: function() {ivModal(obj.inverter[i]);}}, svg(iconGear, 25, 25, "icon icon-fg pointer")),
|
||||
ml("td", {style: "text-align: center; ", onclick: function() {ivDel(obj.inverter[i]);}}, svg(iconDel, 25, 25, "icon icon-fg pointer"))
|
||||
]));
|
||||
}
|
||||
|
||||
var add = new Object();
|
||||
add.id = obj.inverter.length;
|
||||
add.name = "";
|
||||
add.enabled = true;
|
||||
add.ch_max_pwr = [];
|
||||
add.ch_name = [];
|
||||
add.ch_yield_cor = [];
|
||||
|
||||
var e = document.getElementById("inverter");
|
||||
e.innerHTML = ""; // remove all childs
|
||||
e.append(ml("table", {class: "table"}, ml("tbody", {}, lines)));
|
||||
e.append(ml("div", {class: "row my-3"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", value: "add Inverter", class: "btn", onclick: function() { ivModal(add); }}, null))));
|
||||
|
||||
ivGlob(obj);
|
||||
}
|
||||
|
||||
function ivModal(obj) {
|
||||
var lines = [];
|
||||
lines.push(ml("tr", {}, [
|
||||
ml("th", {style: "width: 10%;"}, "Input"),
|
||||
ml("th", {}, "Max Module Power [Wp]"),
|
||||
ml("th", {}, "Name (optional)"),
|
||||
ml("th", {}, "Yield Correction [kWh] (optional)")
|
||||
]));
|
||||
for(let i = 0; i < 6; i++) {
|
||||
lines.push(ml("tr", {id: "ch"+i}, [
|
||||
ml("td", {}, String(i+1)),
|
||||
ml("td", {}, ml("input", {name: "ch_p"+i, class: "text", type: "number", max: 999, value: obj.ch_max_pwr[i]}, null)),
|
||||
ml("td", {}, ml("input", {name: "ch_n"+i, class: "text", type: "text", maxlength: 15, value: (undefined === obj.ch_name[i]) ? "" : obj.ch_name[i]}, null)),
|
||||
ml("td", {}, ml("input", {name: "yld_c"+i, class: "text", type: "number", max: 999999, value: obj.ch_yield_cor[i]}, null))
|
||||
]));
|
||||
}
|
||||
var cbEn = ml("input", {name: "enable", type: "checkbox"}, null);
|
||||
if(obj.enabled)
|
||||
cbEn.checked = true;
|
||||
var ser = ml("input", {name: "ser", class: "text", type: "number", max: 138999999999, value: obj.serial}, null);
|
||||
var html = ml("div", {}, [
|
||||
ml("div", {class: "row mb-3"}, [
|
||||
ml("div", {class: "col-4"}, "Serial"),
|
||||
ml("div", {class: "col-8"}, ser)
|
||||
]),
|
||||
ml("div", {class: "row mb-3"}, [
|
||||
ml("div", {class: "col-4"}, "Name"),
|
||||
ml("div", {class: "col-8"}, ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null))
|
||||
]),
|
||||
ml("div", {class: "row mb-3"}, [
|
||||
ml("div", {class: "col-4"}, "Enable"),
|
||||
ml("div", {class: "col-8"}, cbEn)
|
||||
]),
|
||||
ml("div", {class: "row mb-3"},
|
||||
ml("table", {class: "table"},
|
||||
ml("tbody", {}, lines)
|
||||
)
|
||||
),
|
||||
ml("div", {class: "row mb-3"}, [
|
||||
ml("div", {class: "col-8", id: "res"}, ""),
|
||||
ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "save", class: "btn", onclick: function() { ivSave(); }}, null))
|
||||
])
|
||||
]);
|
||||
|
||||
['keyup', 'change'].forEach(function(evt) {
|
||||
ser.addEventListener(evt, (e) => {
|
||||
var serial = ser.value.substring(0,4);
|
||||
var max = 1;
|
||||
for(var i = 0; i < 6; i++) {
|
||||
setHide("ch"+i, true);
|
||||
}
|
||||
|
||||
if(serial.charAt(0) == 1) {
|
||||
if((serial.charAt(1) == 0) || (serial.charAt(1) == 1) || (serial.charAt(1) == 3)) {
|
||||
if((serial.charAt(3) == 1) || (serial.charAt(3) == 2) || (serial.charAt(3) == 4)) {
|
||||
switch(serial.charAt(2)) {
|
||||
default:
|
||||
case "2": max = 1; break;
|
||||
case "4": max = 2; break;
|
||||
case "6": max = 4; break;
|
||||
case "8": max = 6; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(var i = 0; i < max; i++) {
|
||||
setHide("ch"+i, false);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
modal("Edit inverter", html);
|
||||
ser.dispatchEvent(new Event('change'));
|
||||
|
||||
function ivSave() {
|
||||
var o = new Object();
|
||||
o.cmd = "save_iv";
|
||||
o.id = obj.id;
|
||||
o.ser = parseInt(document.getElementsByName("ser")[0].value, 16);
|
||||
o.name = document.getElementsByName("name")[0].value;
|
||||
o.en = document.getElementsByName("enable")[0].checked;
|
||||
o.ch = [];
|
||||
for(let i = 0; i < 6; i++) {
|
||||
var q = new Object();
|
||||
q.pwr = document.getElementsByName("ch_p"+i)[0].value;
|
||||
q.name = document.getElementsByName("ch_n"+i)[0].value;
|
||||
q.yld = document.getElementsByName("yld_c"+i)[0].value;
|
||||
o.ch.push(q);
|
||||
}
|
||||
getAjax("/api/setup", cb, "POST", JSON.stringify(o));
|
||||
}
|
||||
|
||||
function cb(obj) {
|
||||
var e = document.getElementById("res");
|
||||
if(!obj.success)
|
||||
e.innerHTML = "error while saving";
|
||||
else {
|
||||
modalClose();
|
||||
getAjax("/api/inverter/list", parseIv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ivDel(obj) {
|
||||
var html = ml("div", {class: "row"}, [
|
||||
ml("div", {class: "col-9"}, "do you realy want to delete inverter " + obj.name + "?"),
|
||||
ml("div", {class: "col-3 a-r"}, ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "yes", class: "btn", onclick: function() { del(); }}, null)))
|
||||
]);
|
||||
modal("Delete inverter " + obj.name, html);
|
||||
|
||||
function del() {
|
||||
var o = new Object();
|
||||
o.cmd = "save_iv";
|
||||
o.id = obj.id;
|
||||
o.ser = 0;
|
||||
o.name = "";
|
||||
o.en = false;
|
||||
o.ch = [];
|
||||
for(let i = 0; i < 6; i++) {
|
||||
var q = new Object();
|
||||
q.pwr = 0;
|
||||
q.name = "";
|
||||
q.yld = 0;
|
||||
o.ch.push(q);
|
||||
}
|
||||
getAjax("/api/setup", cb, "POST", JSON.stringify(o));
|
||||
}
|
||||
|
||||
function cb(obj) {
|
||||
if(obj.success) {
|
||||
modalClose();
|
||||
getAjax("/api/inverter/list", parseIv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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]];
|
||||
|
|
|
@ -94,8 +94,8 @@ svg.icon {
|
|||
fill: var(--success);
|
||||
}
|
||||
|
||||
.wifi {
|
||||
fill: var(--fg2);
|
||||
.icon-fg {
|
||||
fill: var(--fg);
|
||||
}
|
||||
|
||||
.title {
|
||||
|
@ -708,7 +708,7 @@ div.hr {
|
|||
width: 100%;
|
||||
background-color: var(--modal-bg);
|
||||
background-clip: padding-box;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
border: 1px solid var(--fg);
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,10 +40,6 @@
|
|||
);
|
||||
}
|
||||
|
||||
function badge(success, text, second="error") {
|
||||
return ml("span", {class: "badge badge-" + ((success) ? "success" : second)}, text);
|
||||
}
|
||||
|
||||
function headline(text) {
|
||||
return ml("div", {class: "head p-2 mt-3"}, ml("div", {class: "row"}, ml("div", {class: "col a-c"}, text)))
|
||||
}
|
||||
|
|
|
@ -487,44 +487,6 @@ class Web {
|
|||
request->arg("ipGateway").toCharArray(buf, 20);
|
||||
ah::ip2Arr(mConfig->sys.ip.gateway, buf);
|
||||
|
||||
// inverter
|
||||
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)
|
||||
memset(buf, 0, 20);
|
||||
iv->config->serial.u64 = ah::Serial2u64(buf);
|
||||
switch(iv->config->serial.b[4]) {
|
||||
case 0x24:
|
||||
case 0x22:
|
||||
case 0x21: iv->type = INV_TYPE_1CH; iv->channels = 1; break;
|
||||
|
||||
case 0x44:
|
||||
case 0x42:
|
||||
case 0x41: iv->type = INV_TYPE_2CH; iv->channels = 2; break;
|
||||
|
||||
case 0x64:
|
||||
case 0x62:
|
||||
case 0x61: iv->type = INV_TYPE_4CH; iv->channels = 4; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// name
|
||||
request->arg("inv" + String(i) + "Name").toCharArray(iv->config->name, MAX_NAME_LENGTH);
|
||||
|
||||
// max channel power / name
|
||||
for (uint8_t j = 0; j < 6; j++) {
|
||||
iv->config->yieldCor[j] = request->arg("inv" + String(i) + "YieldCor" + String(j)).toDouble();
|
||||
iv->config->chMaxPwr[j] = request->arg("inv" + String(i) + "ModPwr" + String(j)).toInt() & 0xffff;
|
||||
request->arg("inv" + String(i) + "ModName" + String(j)).toCharArray(iv->config->chName[j], MAX_NAME_LENGTH);
|
||||
}
|
||||
iv->initialized = true;
|
||||
}
|
||||
|
||||
if (request->arg("invInterval") != "")
|
||||
mConfig->nrf.sendInterval = request->arg("invInterval").toInt();
|
||||
mConfig->inst.rstYieldMidNight = (request->arg("invRstMid") == "on");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue