mirror of https://github.com/lumapu/ahoy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
541 lines
25 KiB
541 lines
25 KiB
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<title>{#NAV_LIVE}</title>
|
|
{#HTML_HEADER}
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
</head>
|
|
<body>
|
|
{#HTML_NAV}
|
|
<div id="wrapper">
|
|
<div id="content">
|
|
<div id="live"></div>
|
|
<p>{#EVERY} <span id="refresh"></span> {#UPDATE_SECS}</p>
|
|
<div id="zero_export"></div>
|
|
<p>Every <span id="refresh"></span> seconds the values are updated</p>
|
|
</div>
|
|
</div>
|
|
{#HTML_FOOTER}
|
|
<script type="text/javascript">
|
|
var exeOnce = true;
|
|
var units, ivEn;
|
|
var mIvHtml = [];
|
|
var mNum = 0;
|
|
var total = Array(6).fill(0);
|
|
var tPwrAck;
|
|
|
|
function getErrStr(code) {
|
|
if("ERR_AUTH") return "{#ERR_AUTH}"
|
|
if("ERR_INDEX") return "{#ERR_INDEX}"
|
|
if("ERR_UNKNOWN_CMD") return "{#ERR_UNKNOWN_CMD}"
|
|
if("ERR_LIMIT_NOT_ACCEPT") return "{#ERR_LIMIT_NOT_ACCEPT}"
|
|
if("ERR_UNKNOWN_CMD") return "{#ERR_AUTH}"
|
|
return "n/a"
|
|
}
|
|
|
|
function parseGeneric(obj) {
|
|
if(true == exeOnce){
|
|
parseNav(obj);
|
|
parseESP(obj);
|
|
}
|
|
parseRssi(obj);
|
|
}
|
|
|
|
function numBig(val, unit, des) {
|
|
return ml("div", {class: "col-6 col-sm-4 a-c"}, [
|
|
ml("div", {class: "row"},
|
|
ml("div", {class: "col"}, [
|
|
ml("span", {class: "fs-5 fs-md-4"}, String(Math.round(val * 100) / 100)),
|
|
ml("span", {class: "fs-6 fs-md-7 mx-1"}, unit)
|
|
])),
|
|
ml("div", {class: "row"},
|
|
ml("div", {class: "col"},
|
|
ml("span", {class: "fs-9 px-1"}, des)
|
|
)
|
|
)
|
|
]);
|
|
}
|
|
|
|
function numMid(val, unit, des, opt={class: "fs-6"}) {
|
|
return ml("div", {class: "col-6 col-sm-4 col-md-3 mb-2"}, [
|
|
ml("div", {class: "row"},
|
|
ml("div", {class: "col"}, [
|
|
ml("span", opt, String(Math.round(val * 100) / 100)),
|
|
ml("span", {class: "fs-8 mx-1"}, unit)
|
|
])
|
|
),
|
|
ml("div", {class: "row"},
|
|
ml("div", {class: "col"},
|
|
ml("span", {class: "fs-9"}, des)
|
|
)
|
|
)
|
|
]);
|
|
}
|
|
|
|
function totals() {
|
|
for(var i = 0; i < 6; i++) {
|
|
total[i] = Math.round(total[i] * 100) / 100;
|
|
}
|
|
|
|
return ml("div", {class: "row mt-3 mb-5"},
|
|
ml("div", {class: "col"}, [
|
|
ml("div", {class: "p-2 total-h"},
|
|
ml("div", {class: "row"},
|
|
ml("div", {class: "col mx-2 mx-md-1"}, "{#TOTAL}")
|
|
),
|
|
),
|
|
ml("div", {class: "p-2 total-bg"}, [
|
|
ml("div", {class: "row"}, [
|
|
numBig(total[0], "W", "{#AC_POWER}"),
|
|
numBig(total[1], "Wh", "{#YIELD_DAY}"),
|
|
numBig(total[2], "kWh", "{#YIELD_TOTAL}")
|
|
]),
|
|
ml("div", {class: "hr"}),
|
|
ml("div", {class: "row"}, [
|
|
numMid(total[3], "W", "{#MAX_POWER}"),
|
|
numMid(total[4], "W", "{#DC_POWER}"),
|
|
numMid(total[5], "var", "{#REACTIVE_POWER}")
|
|
])
|
|
])
|
|
])
|
|
);
|
|
}
|
|
function ivHead(obj) {
|
|
if(0 != obj.status) { // only add totals if inverter is online
|
|
total[0] += obj.ch[0][2]; // P_AC
|
|
total[4] += obj.ch[0][8]; // P_DC
|
|
total[5] += obj.ch[0][10]; // Q_AC
|
|
}
|
|
total[3] += obj.ch[0][11]; // MAX P_AC
|
|
total[1] += obj.ch[0][7]; // YieldDay
|
|
total[2] += obj.ch[0][6]; // YieldTotal
|
|
|
|
var t = span(" °C");
|
|
var clh = (0 == obj.status) ? "iv-h-dis" : "iv-h";
|
|
var clbg = (0 == obj.status) ? "iv-bg-dis" : "iv-bg";
|
|
var pwrLimit = "n/a";
|
|
|
|
if(65535 != obj.power_limit_read) {
|
|
pwrLimit = obj.power_limit_read + " %";
|
|
if(0 != obj.max_pwr)
|
|
pwrLimit += ", " + Math.round(obj.max_pwr * obj.power_limit_read / 100) + " W";
|
|
}
|
|
|
|
var maxAcPwr = toIsoDateStr(new Date(obj.ts_max_ac_pwr * 1000));
|
|
return ml("div", {class: "row mt-2"},
|
|
ml("div", {class: "col"}, [
|
|
ml("div", {class: "p-2 " + clh},
|
|
ml("div", {class: "row"}, [
|
|
ml("div", {class: "col mx-2 mx-md-1"}, ml("span", { class: "pointer", onclick: function() {
|
|
getAjax("/api/inverter/version/" + obj.id, parseIvVersion);
|
|
}}, obj.name)),
|
|
ml("div", {class: "col a-c", onclick: function() {limitModal(obj)}}, [
|
|
ml("span", {class: "d-none d-sm-block pointer"}, "{#ACTIVE_POWER_CONTROL}: " + pwrLimit),
|
|
ml("span", {class: "d-block d-sm-none pointer"}, "{#APC}: " + pwrLimit)
|
|
]),
|
|
ml("div", {class: "col a-c"}, ml("span", { class: "pointer", onclick: function() {
|
|
getAjax("/api/inverter/alarm/" + obj.id, parseIvAlarm);
|
|
}}, ("{#ALARMS}: " + obj.alarm_cnt))),
|
|
ml("div", {class: "col a-r mx-2 mx-md-1"}, String(obj.ch[0][5].toFixed(1)) + t.innerText)
|
|
])
|
|
),
|
|
ml("div", {class: "p-2 " + clbg}, [
|
|
ml("div", {class: "row"},[
|
|
numBig(obj.ch[0][2], "W", "{#AC_POWER}"),
|
|
numBig(obj.ch[0][7], "Wh", "{#YIELD_DAY}"),
|
|
numBig(obj.ch[0][6], "kWh", "{#YIELD_TOTAL}")
|
|
]),
|
|
ml("div", {class: "hr"}),
|
|
ml("div", {class: "row mt-2"},[
|
|
numMid(obj.ch[0][11], "W", "{#MAX_AC_POWER}", {class: "fs-6 tooltip", data: maxAcPwr}),
|
|
numMid(obj.ch[0][8], "W", "{#DC_POWER}"),
|
|
numMid(obj.ch[0][0], "V", "{#AC_VOLTAGE}"),
|
|
numMid(obj.ch[0][1], "A", "{#AC_CURRENT}"),
|
|
numMid(obj.ch[0][3], "Hz", "{#FREQUENCY}"),
|
|
numMid(obj.ch[0][9], "%", "{#EFFICIENCY}"),
|
|
numMid(obj.ch[0][10], "var", "{#REACTIVE_POWER}"),
|
|
numMid(obj.ch[0][4], "", "{#POWER_FACTOR}")
|
|
])
|
|
])
|
|
])
|
|
);
|
|
}
|
|
|
|
function numCh(val, unit, des) {
|
|
return ml("div", {class: "col-12 col-sm-6 col-md-12 mb-2"}, [
|
|
ml("div", {class: "row"},
|
|
ml("div", {class: "col"}, [
|
|
ml("span", {class: "fs-6 fs-md-7"}, String(Math.round(val * 100) / 100)),
|
|
ml("span", {class: "fs-8 mx-2"}, unit)
|
|
])),
|
|
ml("div", {class: "row"},
|
|
ml("div", {class: "col"},
|
|
ml("span", {class: "fs-9"}, des)
|
|
)
|
|
)
|
|
]);
|
|
}
|
|
|
|
function ch(status, name, vals) {
|
|
var clh = (0 == status) ? "iv-h-dis" : "ch-h";
|
|
var clbg = (0 == status) ? "iv-bg-dis" : "ch-bg";
|
|
return ml("div", {class: "col-6 col-md-3 mt-2"}, [
|
|
ml("div", {class: "p-2 a-c " + clh}, name),
|
|
ml("div", {class: "p-2 " + clbg}, [
|
|
ml("div", {class: "row"}, [
|
|
numCh(vals[2], units[2], "{#DC_POWER}"),
|
|
numCh(vals[6], units[2], "{#MAX_POWER}"),
|
|
numCh(vals[5], units[5], "{#IRRADIATION}"),
|
|
numCh(vals[3], units[3], "{#YIELD_DAY}"),
|
|
numCh(vals[4], units[4], "{#YIELD_TOTAL}"),
|
|
numCh(vals[0], units[0], "{#DC_VOLTAGE}"),
|
|
numCh(vals[1], units[1], "{#DC_CURRENT}")
|
|
])
|
|
])
|
|
]);
|
|
}
|
|
|
|
function tsInfo(obj) {
|
|
var ageInfo = "{#LAST_RECEIVED}: ";
|
|
if(obj.ts_last_success > 0) {
|
|
var date = new Date(obj.ts_last_success * 1000);
|
|
ageInfo += toIsoDateStr(date);
|
|
}
|
|
else
|
|
ageInfo += "{#NOTHING_RECEIVED}";
|
|
|
|
if(obj.rssi > -127) {
|
|
if(obj.generation < 2)
|
|
ageInfo += " (RSSI: " + ((obj.rssi == -64) ? ">=" : "<") + " -64 dBm)";
|
|
else
|
|
ageInfo += " (RSSI: " + obj.rssi + " dBm)";
|
|
}
|
|
|
|
return ml("div", {class: "mb-5"}, [
|
|
ml("div", {class: "row p-1 ts-h mx-2"},
|
|
ml("div", {class: "col"}, "")
|
|
),
|
|
ml("div", {class: "row p-2 ts-bg mx-2"},
|
|
ml("div", { class: "pointer col mx-2", onclick: function() {
|
|
getAjax("/api/inverter/radiostat/" + obj.id, parseIvRadioStats);
|
|
}}, ageInfo)
|
|
)
|
|
]);
|
|
}
|
|
|
|
function parseIv(obj) {
|
|
mNum++;
|
|
|
|
var chn = [];
|
|
for(var i = 1; i < obj.ch.length; i++) {
|
|
var name = obj.ch_name[i];
|
|
if(name.length == 0)
|
|
name = "CHANNEL " + i;
|
|
if(obj.ch_max_pwr[i] > 0) // show channel only if max mod pwr
|
|
chn.push(ch(obj.status, name, obj.ch[i]));
|
|
}
|
|
mIvHtml.push(
|
|
ml("div", {}, [
|
|
ivHead(obj),
|
|
ml("div", {class: "row mb-2"}, chn),
|
|
tsInfo(obj)
|
|
])
|
|
);
|
|
|
|
|
|
var last = true;
|
|
for(var i = obj.id + 1; i < ivEn.length; i++) {
|
|
if((i != ivEn.length) && ivEn[i]) {
|
|
last = false;
|
|
getAjax("/api/inverter/id/" + i, parseIv);
|
|
break;
|
|
}
|
|
}
|
|
if(last) {
|
|
if(mNum > 1)
|
|
mIvHtml.unshift(totals());
|
|
document.getElementById("live").replaceChildren(...mIvHtml);
|
|
}
|
|
}
|
|
|
|
function parseIvAlarm(obj) {
|
|
var html = [];
|
|
var offs = new Date().getTimezoneOffset() * -60;
|
|
html.push(
|
|
ml("div", {class: "row"}, [
|
|
ml("div", {class: "col"}, ml("strong", {}, "{#EVENT}")),
|
|
ml("div", {class: "col"}, ml("strong", {}, "ID")),
|
|
ml("div", {class: "col"}, ml("strong", {}, "Start")),
|
|
ml("div", {class: "col"}, ml("strong", {}, "{#END}"))
|
|
])
|
|
);
|
|
|
|
for(a of obj.alarm) {
|
|
if(a.code != 0) {
|
|
html.push(
|
|
ml("div", {class: "row"}, [
|
|
ml("div", {class: "col mt-3"}, String(a.str)),
|
|
ml("div", {class: "col mt-3"}, String(a.code)),
|
|
ml("div", {class: "col mt-3"}, String(toIsoTimeStr(new Date((a.start + offs) * 1000)))),
|
|
ml("div", {class: "col mt-3"}, String(toIsoTimeStr(new Date((a.end + offs) * 1000))))
|
|
])
|
|
);
|
|
}
|
|
}
|
|
modal("{#ALARMS_MODAL}: " + obj.iv_name, ml("div", {}, html));
|
|
}
|
|
|
|
function parseIvVersion(obj) {
|
|
var model;
|
|
switch(obj.generation) {
|
|
case 0: model = "MI-"; break;
|
|
case 1: model = "HM-"; break;
|
|
case 2: model = "HMS-"; break;
|
|
case 3: model = "HMT-"; break;
|
|
default: model = "???-"; break;
|
|
}
|
|
model += String(obj.max_pwr) + " ({#SERIAL}: " + obj.serial + ")";
|
|
|
|
|
|
var html = ml("table", {class: "table"}, [
|
|
ml("tbody", {}, [
|
|
tr("Model", model),
|
|
tr("Firmware Version / Build", String(obj.fw_ver) + " (build: " + String(obj.fw_date) + " " + String(obj.fw_time) + ")"),
|
|
tr("Hardware Version / Build", (obj.hw_ver/100).toFixed(2) + " (build: " + String(obj.prod_cw) + "/" + String(obj.prod_year) + ")"),
|
|
tr("{#HW_NUMBER}", obj.part_num.toString(16)),
|
|
tr("Bootloader Version", (obj.boot_ver/100).toFixed(2)),
|
|
tr("Grid Profile", ml("input", {type: "button", value: "{#BTN_SHOW}", class: "btn", onclick: function() {
|
|
modalClose();
|
|
getAjax("/api/inverter/grid/" + obj.id, showGridProfile);
|
|
}}, null))
|
|
])
|
|
])
|
|
modal("{#INV_INFO}: " + obj.name, ml("div", {}, html))
|
|
}
|
|
|
|
function getGridValue(g) {
|
|
var val = (parseInt(g.grid.substring(g.offs*3, g.offs*3+2), 16) * 256)
|
|
+ parseInt(g.grid.substring(g.offs*3+3, g.offs*3+5), 16)
|
|
g.offs += 2
|
|
return val
|
|
}
|
|
|
|
function getGridIdentifier(g) {
|
|
return "0x" + getGridValue(g).toString(16).padStart(4, '0')
|
|
}
|
|
|
|
function getGridType(t, id) {
|
|
for(e of t) {
|
|
if(undefined !== e[id])
|
|
return e[id]
|
|
}
|
|
return null
|
|
}
|
|
|
|
function parseGridGroup(g) {
|
|
var id = getGridIdentifier(g)
|
|
var type = getGridType(g.info.grp_codes, id.substring(0, 4))
|
|
var content = []
|
|
content.push(ml("div", {class: "row"},
|
|
ml("div", {class: "col head p-2 mt-3"},
|
|
ml("div", {class: "col a-c"}, type + " (Code " + id + ")")
|
|
)
|
|
))
|
|
content.push(ml("div", {class: "row my-2"}, [
|
|
ml("div", {class: "col-4"}, ml("b", {}, "Name")),
|
|
ml("div", {class: "col-3"}, ml("b", {}, "{#VALUE}")),
|
|
ml("div", {class: "col-3"}, ml("b", {}, "{#RANGE}")),
|
|
ml("div", {class: "col-2"}, ml("b", {}, "{#DEFAULT}"))
|
|
]))
|
|
for(e of g.info.group) {
|
|
if(Array.isArray(e[id])) {
|
|
for(e of e[id]) {
|
|
var v = String(getGridValue(g) / e.div);
|
|
var vt = (v !== String(e.def)) ? "b" : "span";
|
|
content.push(ml("div", {class: "row mt-2"}, [
|
|
ml("div", {class: "col-4"}, e.name),
|
|
ml("div", {class: "col-3"}, ml(vt, {}, v + ((undefined !== e.unit) ? " [" + e.unit + "]" : ""))),
|
|
ml("div", {class: "col-3"}, (undefined !== e.min) ? (e.min + " - " + e.max) : "n/a"),
|
|
ml("div", {class: "col-2"}, String(e.def))
|
|
]))
|
|
}
|
|
}
|
|
}
|
|
|
|
return ml("div", {class: "col"}, [...content])
|
|
}
|
|
|
|
function showGridProfile(obj) {
|
|
getJSON("/grid_info.json").then(data => {
|
|
var glob = {offs:0, grid:obj.grid, info: data}
|
|
var content = [];
|
|
var g = getGridType(glob.info.type, getGridIdentifier(glob))
|
|
var v = getGridValue(glob);
|
|
if(null === g) {
|
|
if(0 == obj.grid.length) {
|
|
content.push(ml("div", {class: "row"}, ml("div", {class: "col"}, ml("p", {}, "{#PROFILE_NOT_READ}"))))
|
|
} else {
|
|
content.push(ml("div", {class: "row"}, ml("div", {class: "col"}, ml("h5", {}, "{#UNKNOWN_PROFILE}"))))
|
|
content.push(ml("div", {class: "row"}, ml("div", {class: "col"}, ml("p", {}, "{#OPEN_ISSUE}."))))
|
|
}
|
|
} else {
|
|
content.push(ml("div", {class: "row"},
|
|
ml("div", {class: "col my-3"}, ml("h5", {}, g + " (Version " + (Math.round(v / 0x1000)) + "." + (Math.round((v & 0x0ff0) / 0x10)) + "." + (v & 0x0F) + ")"))
|
|
))
|
|
|
|
while((glob.offs*3) < glob.grid.length) {
|
|
content.push(parseGridGroup(glob))
|
|
}
|
|
}
|
|
if(0 != obj.grid.length)
|
|
content.push(ml("div", {class: "row"}, ml("div", {class: "col my-2"}, ml("pre", {}, obj.grid))))
|
|
|
|
modal("{#PROFILE_MODAL}: " + obj.name, ml("div", {}, ml("div", {class: "col mb-2"}, [...content])))
|
|
})
|
|
}
|
|
|
|
|
|
function parseIvRadioStats(obj) {
|
|
var html = ml("table", {class: "table"}, [
|
|
ml("tbody", {}, [
|
|
tr2(["{#TX_COUNT}", obj.tx_cnt, ""]),
|
|
tr2(["{#RX_SUCCESS}", obj.rx_success, String(Math.round(obj.rx_success / obj.tx_cnt * 10000) / 100) + " %"]),
|
|
tr2(["{#RX_FAIL}", obj.rx_fail, String(Math.round(obj.rx_fail / obj.tx_cnt * 10000) / 100) + " %"]),
|
|
tr2(["{#RX_NO_ANSWER}", obj.rx_fail_answer, String(Math.round(obj.rx_fail_answer / obj.tx_cnt * 10000) / 100) + " %"]),
|
|
tr2(["{#RX_FRAGMENTS}", obj.frame_cnt, ""]),
|
|
tr2(["{#TX_RETRANSMITS}", obj.retransmits, ""]),
|
|
tr2(["{#INV_LOSS_RATE}", "{#LOST_1} " + obj.ivLoss + " {#LOST_2} " + obj.ivSent + " {#LOST_3}", String(Math.round(obj.ivLoss / obj.ivSent * 10000) / 100) + " %"]),
|
|
tr2(["{#DTU_LOSS_RATE}", "{#LOST_1} " + obj.dtuLoss + " {#LOST_2} " + obj.dtuSent + " {#LOST_3}", String(Math.round(obj.dtuLoss / obj.dtuSent * 10000) / 100) + " %"])
|
|
])
|
|
])
|
|
modal("{#RADIO_STAT_MODAL}: " + obj.name, ml("div", {}, html))
|
|
}
|
|
|
|
function limitModal(obj) {
|
|
var opt = [["pct", "%"], ["watt", "W"]];
|
|
var html = ml("div", {}, [
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-12 col-sm-5 my-2"}, "{#LIMIT_VALUE}"),
|
|
ml("div", {class: "col-8 col-sm-5"}, ml("input", {name: "limit", type: "number", step: "0.1", min: 1}, "")),
|
|
ml("div", {class: "col-4 col-sm-2"}, sel("type", opt, "pct"))
|
|
]),
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-8 col-sm-5"}, "{#KEEP_LIMIT}"),
|
|
ml("div", {class: "col-4 col-sm-7"}, ml("input", {type: "checkbox", name: "keep"}))
|
|
]),
|
|
ml("div", {class: "row my-3"},
|
|
ml("div", {class: "col a-r"}, ml("input", {type: "button", value: "{#BTN_APPLY}", class: "btn", onclick: function() {
|
|
applyLimit(obj.id);
|
|
}}, null))
|
|
),
|
|
ml("div", {class: "row my-4"}, [
|
|
ml("div", {class: "col-12 col-sm-5 my-2"}, "{#CONTROL}"),
|
|
ml("div", {class: "col col-sm-7 a-r"}, [
|
|
ml("input", {type: "button", value: "{#RESTART}", class: "btn", onclick: function() {
|
|
applyCtrl(obj.id, "restart");
|
|
}}, null),
|
|
ml("input", {type: "button", value: "{#TURN_OFF}", class: "btn mx-1", onclick: function() {
|
|
applyCtrl(obj.id, "power", 0);
|
|
}}, null),
|
|
ml("input", {type: "button", value: "{#TURN_ON}", class: "btn", onclick: function() {
|
|
applyCtrl(obj.id, "power", 1);
|
|
}}, null)
|
|
])
|
|
]),
|
|
ml("div", {class: "row mt-1"}, [
|
|
ml("div", {class: "col-12 col-sm-5 my-2"}, "{#RESULT}"),
|
|
ml("div", {class: "col-sm-7 my-2"}, ml("span", {name: "pwrres"}, "-"))
|
|
])
|
|
]);
|
|
modal("{#POWER_LIMIT_MODAL}: " + obj.name, html);
|
|
}
|
|
|
|
function applyLimit(id) {
|
|
var cmd = "limit_";
|
|
if(!document.getElementsByName("keep")[0].checked)
|
|
cmd += "non";
|
|
cmd += "persistent_";
|
|
if(document.getElementsByName("type")[0].value == "pct")
|
|
cmd += "relative";
|
|
else
|
|
cmd += "absolute";
|
|
|
|
var val = document.getElementsByName("limit")[0].value;
|
|
if(isNaN(val))
|
|
val = 100;
|
|
|
|
var obj = new Object();
|
|
obj.id = id
|
|
obj.token = "*"
|
|
obj.cmd = cmd
|
|
obj.val = val
|
|
getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj))
|
|
}
|
|
|
|
function applyCtrl(id, cmd, val=0) {
|
|
var obj = new Object();
|
|
obj.id = id
|
|
obj.token = "*"
|
|
obj.cmd = cmd
|
|
obj.val = val
|
|
getAjax("/api/ctrl", ctrlCb2, "POST", JSON.stringify(obj))
|
|
}
|
|
|
|
function ctrlCb(obj) {
|
|
var e = document.getElementsByName("pwrres")[0];
|
|
if(obj.success) {
|
|
e.innerHTML = "{#CMD_RECEIVED_WAIT_ACK}";
|
|
tPwrAck = window.setInterval("getAjax('/api/inverter/pwrack/" + obj.id + "', updatePwrAck)", 1000);
|
|
}
|
|
else
|
|
e.innerHTML = "{#ERROR}: " + getErrStr(obj.error);
|
|
}
|
|
|
|
function ctrlCb2(obj) {
|
|
var e = document.getElementsByName("pwrres")[0];
|
|
if(obj.success)
|
|
e.innerHTML = "{#COMMAND_RECEIVED}";
|
|
else
|
|
e.innerHTML = "{#ERROR}: " + getErrStr(obj.error);
|
|
}
|
|
|
|
function updatePwrAck(obj) {
|
|
if(!obj.ack)
|
|
return;
|
|
var e = document.getElementsByName("pwrres")[0];
|
|
clearInterval(tPwrAck);
|
|
if(null == e)
|
|
return;
|
|
e.innerHTML = "{#INV_ACK}";
|
|
}
|
|
|
|
function parse(obj) {
|
|
if(null != obj) {
|
|
parseGeneric(obj["generic"]);
|
|
units = Object.assign({}, obj["fld_units"]);
|
|
ivEn = Object.values(Object.assign({}, obj["iv"]));
|
|
mIvHtml = [];
|
|
mNum = 0;
|
|
total.fill(0);
|
|
for(var i = 0; i < obj.iv.length; i++) {
|
|
if(obj.iv[i]) {
|
|
getAjax("/api/inverter/id/" + i, parseIv);
|
|
break;
|
|
}
|
|
}
|
|
if(obj.refresh < 5)
|
|
obj.refresh = 5;
|
|
document.getElementById("refresh").innerHTML = obj.refresh;
|
|
if(true == exeOnce) {
|
|
window.setInterval("getAjax('/api/live', parse)", obj.refresh * 1000);
|
|
exeOnce = false;
|
|
}
|
|
}
|
|
else
|
|
document.getElementById("refresh").innerHTML = "n/a";
|
|
}
|
|
|
|
getAjax("/api/live", parse);
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|