<!doctype html> <html> <head> <title>Setup</title> <link rel="stylesheet" type="text/css" href="style.css"/> <meta name="viewport" content="width=device-width, initial-scale=1"> <script type="text/javascript" src="api.js"></script> <script type="text/javascript"> function load() { for(it of document.getElementsByClassName("s_collapsible")) { it.addEventListener("click", function() { this.classList.toggle("active"); var content = this.nextElementSibling; content.style.display = (content.style.display === "block") ? "none" : "block"; }); } } </script> </head> <body onload="load()"> <h1>Setup</h1> <div id="setup" class="content"> <div id="content"> <a class="erase" href="/erase">ERASE SETTINGS (not WiFi)</a> <form method="post" action="/save"> <fieldset> <legend class="des">Device Host Name</legend> <label for="device">Device Name</label> <input type="text" name="device" class="text"/> <input type="hidden" name="disclaimer" value="false" id="disclaimer"> </fieldset> <button type="button" class="s_collapsible">WiFi</button> <div class="s_content"> <fieldset> <legend class="des">WiFi</legend> <p>Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information.</p> <label for="ssid">SSID</label> <input type="text" name="ssid" class="text"/> <label for="pwd">Password</label> <input type="password" class="text" name="pwd" value="{PWD}"/> </fieldset> </div> <button type="button" class="s_collapsible">Inverter</button> <div class="s_content"> <fieldset> <legend class="des">Inverter</legend> <div id="inverter"></div><br/> <input type="button" id="btnAdd" value="Add Inverter"/> <p class="subdes">General</p> <label for="invInterval">Interval [s]</label> <input type="text" class="text" name="invInterval"/> <label for="invRetry">Max retries per Payload</label> <input type="text" class="text" name="invRetry"/> </fieldset> </div> <button type="button" class="s_collapsible">NTP Server</button> <div class="s_content"> <fieldset> <legend class="des">NTP Server</legend> <label for="ntpAddr">NTP Server / IP</label> <input type="text" class="text" name="ntpAddr"/> <label for="ntpPort">NTP Port</label> <input type="text" class="text" name="ntpPort"/> <label for="ntpBtn">set system time</label> <input type="button" name="ntpBtn" id="ntpBtn" class="btn" value="from browser" onclick="setTime()"/> <input type="button" name="ntpSync" id="ntpSync" class="btn" value="sync NTP" onclick="syncTime()"/> <span id="apiResultNtp"></span> </fieldset> </div> <button type="button" class="s_collapsible">Sunrise & Sunset</button> <div class="s_content"> <fieldset> <legend class="des">Sunrise & Sunset</legend> <label for="sunLat">Latitude (decimal)</label> <input type="text" class="text" name="sunLat"/> <label for="sunLon">Longitude (decimal)</label> <input type="text" class="text" name="sunLon"/> <br> <label for="sunDisNightCom">disable night communication</label> <input type="checkbox" class="cb" name="sunDisNightCom"/><br/> </fieldset> </div> <button type="button" class="s_collapsible">MQTT</button> <div class="s_content"> <fieldset> <legend class="des">MQTT</legend> <label for="mqttAddr">Broker / Server IP</label> <input type="text" class="text" name="mqttAddr" maxlength="32" /> <label for="mqttPort">Port</label> <input type="text" class="text" name="mqttPort"/> <label for="mqttUser">Username (optional)</label> <input type="text" class="text" name="mqttUser"/> <label for="mqttPwd">Password (optional)</label> <input type="password" class="text" name="mqttPwd"/> <label for="mqttTopic">Topic</label> <input type="text" class="text" name="mqttTopic"/> <label for="mqttBtn">Discovery Config (homeassistant)</label> <input type="button" name="mqttDiscovery" id="mqttDiscovery" class="btn" value="send" onclick="sendDiscoveryConfig()"/> <span id="apiResultMqtt"></span> </fieldset> </div> <button type="button" class="s_collapsible">System Config</button> <div class="s_content"> <fieldset> <legend class="des">System Config</legend> <p class="des">Pinout (Wemos)</p> <div id="pinout"></div> <p class="des">Radio (NRF24L01+)</p> <div id="rf24"></div> <p class="des">Serial Console</p> <label for="serEn">print inverter data</label> <input type="checkbox" class="cb" name="serEn"/><br/> <label for="serDbg">Serial Debug</label> <input type="checkbox" class="cb" name="serDbg"/><br/> <label for="serIntvl">Interval [s]</label> <input type="text" class="text" name="serIntvl"/> </fieldset> </div> <label for="reboot">Reboot device after successful save</label> <input type="checkbox" class="cb" name="reboot"/> <input type="submit" value="save" class="btn right"/><br/> <br/> <a href="/get_setup" target="_blank">Download your settings (JSON file)</a> (only saved values) </form> </div> </div> <div id="footer"> <p class="left"><a href="/">Home</a></p> <p class="left"><a href="/update">Update Firmware</a></p> <p class="right" id="version"></p> <p class="right"><a href="/factory">Factory Reset</a></p> <p class="right"><a href="/reboot">Reboot</a></p> </div> <script type="text/javascript"> var highestId = 0; var maxInv = 0; const re = /11[2,4,6]1.*/; 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); }); function apiCbNtp(obj) { var e = document.getElementById("apiResultNtp"); if(obj["success"]) e.innerHTML = "command excuted"; else e.innerHTML = "Error: " + obj["error"]; } function apiCbMqtt(obj) { var e = document.getElementById("apiResultMqtt"); if(obj["success"]) e.innerHTML = "command excuted"; else e.innerHTML = "Error: " + obj["error"]; } function setTime() { var date = new Date(); var obj = new Object(); obj.cmd = "set_time"; obj.ts = parseInt(date.getTime() / 1000); getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj)); } function syncTime() { var obj = new Object(); obj.cmd = "sync_ntp"; getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj)); } function sendDiscoveryConfig() { var obj = new Object(); obj.cmd = "discovery_cfg"; getAjax("/api/setup", apiCbMqtt, "POST", JSON.stringify(obj)); } function delIv() { var id = this.id.substring(0,4); var e = document.getElementsByName(id + "Addr")[0]; e.value = ""; e.dispatchEvent(new Event("keyup")); document.getElementsByName(id + "Name")[0].value = ""; } function ivHtml(obj, id) { highestId = id; if(highestId == (maxInv - 1)) toggle("btnAdd", true); iv = document.getElementById("inverter"); iv.appendChild(des("Inverter " + id)); id = "inv" + id; iv.appendChild(lbl(id + "Addr", "Address*")); var addr = inp(id + "Addr", obj["serial"], 12) iv.appendChild(addr); addr.addEventListener("keyup", (e) => { var serial = addr.value.substring(0,4); var max = 0; for(var i=0;i<4;i++) { toggle(id+"ModPwr"+i, true); toggle(id+"ModName"+i, true); } toggle("lbl"+id+"ModPwr", true); toggle("lbl"+id+"ModName", true); if(serial == "1161") max = 4; else if(serial == "1141") max = 2; else if(serial == "1121") max = 1; for(var i=0;i<max;i++) { toggle(id+"ModPwr"+i, false); toggle(id+"ModName"+i, false); } if(max != 0) { toggle("lbl"+id+"ModPwr", false); toggle("lbl"+id+"ModName", false); } }); for(var i of [["Name", "name", "Name*", 32]]) { iv.appendChild(lbl(id + i[0], i[2])); iv.appendChild(inp(id + i[0], obj[i[1]], i[3])); } for(var j of [["ModPwr", "ch_max_power", "Max Module Power (Wp)", 4], ["ModName", "ch_name", "Module Name", 16]]) { var cl = (re.test(obj["serial"])) ? null : ["hide"]; iv.appendChild(lbl(null, j[2], cl, "lbl" + id + j[0])); d = div([j[0]]); i = 0; cl = (re.test(obj["serial"])) ? ["text", "sh"] : ["text", "sh", "hide"]; for(it of obj[j[1]]) { d.appendChild(inp(id + j[0] + i, it, j[3], cl, id + j[0] + i)); i++; } iv.appendChild(d); } iv.appendChild(br()); iv.appendChild(lbl(id + "lbldel", "Delete")); var del = inp(id+"del", "X", 0, ["btn", "btnDel"], id+"del", "button"); iv.appendChild(del); del.addEventListener("click", delIv); } function ivGlob(obj) { for(var i of [["invInterval", "interval"], ["invRetry", "retries"]]) document.getElementsByName(i[0])[0].value = obj[i[1]]; } function parseSys(obj) { for(var i of [["device", "device_name"], ["ssid", "ssid"]]) document.getElementsByName(i[0])[0].value = obj[i[1]]; document.getElementById("version").innerHTML = "Git SHA: " + obj["build"] + " :: " + obj["version"]; } function parseIv(obj) { for(var i = 0; i < obj.inverter.length; i++) ivHtml(obj.inverter[i], i); ivGlob(obj); maxInv = obj["max_num_inverters"]; } function parseMqtt(obj) { for(var i of [["Addr", "broker"], ["Port", "port"], ["User", "user"], ["Pwd", "pwd"], ["Topic", "topic"]]) document.getElementsByName("mqtt"+i[0])[0].value = obj[i[1]]; } function parseNtp(obj) { for(var i of [["ntpAddr", "addr"], ["ntpPort", "port"]]) document.getElementsByName(i[0])[0].value = obj[i[1]]; } function parseSun(obj) { document.getElementsByName("sunLat")[0].value = obj["lat"]; document.getElementsByName("sunLon")[0].value = obj["lon"]; document.getElementsByName("sunDisNightCom")[0].checked = obj["disnightcom"]; } function parsePinout(obj, type) { var e = document.getElementById("pinout"); pins = [['cs', 'pinCs'], ['ce', 'pinCe'], ['irq', 'pinIrq']]; for(p of pins) { e.appendChild(lbl(p[1], p[0].toUpperCase())); if("ESP8266" == type) { e.appendChild(sel(p[1], [ [0, "D3 (GPIO0)"], [1, "TX (GPIO1)"], [2, "D4 (GPIO2)"], [3, "RX (GPIO3)"], [4, "D2 (GPIO4)"], [5, "D1 (GPIO5)"], [6, "GPIO6"], [7, "GPIO7"], [8, "GPIO8"], [9, "GPIO9"], [10, "GPIO10"], [11, "GPIO11"], [12, "D6 (GPIO12)"], [13, "D7 (GPIO13)"], [14, "D5 (GPIO14)"], [15, "D8 (GPIO15)"], [16, "D0 (GPIO16 - no IRQ!)"] ], obj[p[0]])); } else { e.appendChild(sel(p[1], [ [0, "GPIO0"], [1, "TX (GPIO1)"], [2, "GPIO2 (LED)"], [3, "RX (GPIO3)"], [4, "GPIO4"], [5, "GPIO5"], [12, "GPIO12"], [13, "GPIO13"], [14, "GPIO14"], [15, "GPIO15"], [16, "GPIO16"], [17, "GPIO17"], [18, "GPIO18"], [19, "GPIO19"], [21, "GPIO21"], [22, "GPIO22"], [23, "GPIO23"], [25, "GPIO25"], [26, "GPIO26"], [27, "GPIO27"], [32, "GPIO32"], [33, "GPIO33"], [34, "GPIO34"], [35, "GPIO35"], [36, "VP (GPIO36)"], [39, "VN (GPIO39)"] ], obj[p[0]])); } } } function parseRadio(obj) { var e = document.getElementById("rf24"); e.appendChild(lbl("rf24Power", "Amplifier Power Level")); e.appendChild(sel("rf24Power", [ [0, "MIN"], [1, "LOW"], [2, "HIGH"], [3, "MAX"] ], obj["power_level"])); } function parseSerial(obj) { for(var i of [["serEn", "show_live_data"], ["serDbg", "debug"]]) document.getElementsByName(i[0])[0].checked = obj[i[1]]; document.getElementsByName("serIntvl")[0].value = obj["interval"]; } function parse(root) { if(null != root) { parseSys(root["system"]); parseIv(root["inverter"]); parseMqtt(root["mqtt"]); parseNtp(root["ntp"]); parseSun(root["sun"]); parsePinout(root["pinout"], root["system"]["esp_type"]); parseRadio(root["radio"]); parseSerial(root["serial"]); } } hiddenInput = document.getElementById("disclaimer") hiddenInput.value = sessionStorage.getItem("gDisclaimer"); getAjax("/api/setup", parse); </script> </body> </html>