<!doctype html>
<html>
    <head>
        <title>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> 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(5).fill(0);

            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) {
                return ml("div", {class: "col-6 col-sm-4 col-md-3 mb-2"}, [
                    ml("div", {class: "row"},
                        ml("div", {class: "col"}, [
                            ml("span", {class: "fs-6"}, 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 < 5; 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", "DC Power"),
                                numMid(total[4], "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[3] += obj.ch[0][8]; // P_DC
                    total[4] += obj.ch[0][10]; // Q_AC
                }
                total[1] += obj.ch[0][7]; // YieldDay
                total[2] += obj.ch[0][6]; // YieldTotal

                var t = span("&nbsp;&deg;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 + "&nbsp;%";
                    if(0 != obj.max_pwr)
                        pwrLimit += ", " + (obj.max_pwr * obj.power_limit_read / 100) + "W";
                }

                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"}, "Active Power Control: " + 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]) + 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"),
                                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(ts, gen, rssi) {
                var ageInfo = "Last received data requested at: ";
                if(ts > 0) {
                    var date = new Date(ts * 1000);
                    ageInfo += toIsoDateStr(date);
                }
                else
                    ageInfo += "nothing received";

                if(rssi > -127) {
                    if(gen < 2)
                        ageInfo += " (RSSI: " + ((rssi == -64) ? ">=" : "<") + " -64dBm)";
                    else
                        ageInfo += " (RSSI: " + 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: "col mx-2"}, 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.ts_last_success, obj.generation, obj.rssi)
                    ])
                );


                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", {}, "String")),
                        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 of inverter #" + obj.iv_id, 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", {}, [
                        ml("tr", {}, [
                            ml("th", {}, "Model"),
                            ml("td", {}, model)
                        ]),
                        ml("tr", {}, [
                            ml("th", {}, "Firmware Version / Build"),
                            ml("td", {}, String(obj.fw_ver) + " (build: " + String(obj.fw_date) + " " + String(obj.fw_time) + ")")
                        ]),
                        ml("tr", {}, [
                            ml("th", {}, "Hardware Version / Build"),
                            ml("td", {}, (obj.hw_ver/100).toFixed(2) + " (build: " + String(obj.prod_cw) + "/" + String(obj.prod_year) + ")")
                        ]),
                        ml("tr", {}, [
                            ml("th", {}, "Hardware Number"),
                            ml("td", {}, obj.part_num.toString(16))
                        ]),
                        ml("tr", {}, [
                            ml("th", {}, "Bootloader Version"),
                            ml("td", {}, (obj.boot_ver/100).toFixed(2))
                        ])
                    ])
                ]);
                modal("Info for inverter " + obj.name, ml("div", {}, html));
            }

            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>