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.
1858 lines
92 KiB
1858 lines
92 KiB
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<title>{#SETTINGS}</title>
|
|
{#HTML_HEADER}
|
|
</head>
|
|
<body>
|
|
{#HTML_NAV}
|
|
<div id="wrapper">
|
|
<div id="content">
|
|
<form method="post" action="/save" id="settings">
|
|
<button type="button" class="s_collapsible mt-4">{#SYSTEM_CONFIG}</button>
|
|
<div class="s_content">
|
|
<fieldset class="mb-2">
|
|
<legend class="des">{#SYSTEM_CONFIG}</legend>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3">{#DEVICE_NAME}</div>
|
|
<div class="col-12 col-sm-9"><input type="text" name="device"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-8 col-sm-3">{#REBOOT_AT_MIDNIGHT}</div>
|
|
<div class="col-4 col-sm-9"><input type="checkbox" name="schedReboot"/></div>
|
|
</div>
|
|
<div class="row mb-5">
|
|
<div class="col-8 col-sm-3">{#DARK_MODE}</div>
|
|
<div class="col-4 col-sm-9"><input type="checkbox" name="darkMode"/></div>
|
|
<div class="col-12">{#DARK_MODE_NOTE}</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-8 col-sm-3">{#REGION}</div>
|
|
<div class="col-4 col-sm-9" id="region"></div>
|
|
</div>
|
|
<div class="row mb-5">
|
|
<div class="col-8 col-sm-3">{#TIMEZONE}</div>
|
|
<div class="col-4 col-sm-9" id="timezone"></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-8 col-sm-3">{#CUSTOM_LINK}</div>
|
|
<div class="col-4 col-sm-9"><input type="text" name="cstLnk"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-8 col-sm-3">{#CUSTOM_LINK_TEXT}</div>
|
|
<div class="col-4 col-sm-9"><input type="text" name="cstLnkTxt"/></div>
|
|
</div>
|
|
</fieldset>
|
|
<fieldset class="mb-4" id="serialCb">
|
|
<legend class="des">{#SERIAL_CONSOLE}</legend>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<button type="button" class="s_collapsible">{#NETWORK}</button>
|
|
<div class="s_content">
|
|
<fieldset class="mb-2">
|
|
<legend class="des">WiFi</legend>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#AP_PWD}</div>
|
|
<div class="col-12 col-sm-9"><input type="text" name="ap_pwd" minlength="8" /></div>
|
|
</div>
|
|
<div class="row mb-2 mb-sm-3">
|
|
<div class="col-12 col-sm-3 my-2">SSID</div>
|
|
<div class="col-12 col-sm-9"><input type="text" name="ssid"/><br/><a href="/wizard">{#SCAN_WIFI}</a></div>
|
|
</div>
|
|
<div class="row mb-2 mb-sm-3">
|
|
<div class="col-12 col-sm-3">{#SSID_HIDDEN}</div>
|
|
<div class="col-12 col-sm-9"><input type="checkbox" name="hidd"/></div>
|
|
</div>
|
|
<div class="row mb-2 mb-sm-3">
|
|
<div class="col-12 col-sm-3 my-2">{#PASSWORD}</div>
|
|
<div class="col-12 col-sm-9"><input type="password" name="pwd" value="{PWD}"/></div>
|
|
</div>
|
|
</fieldset>
|
|
<fieldset class="mb-4">
|
|
<legend class="des">{#STATIC_IP}</legend>
|
|
<p>
|
|
{#NETWORK_HINT_BLANK}
|
|
</p>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#IP_ADDRESS}</div>
|
|
<div class="col-12 col-sm-9"><input type="text" name="ipAddr" maxlength="15" /></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#SUBMASK}</div>
|
|
<div class="col-12 col-sm-9"><input type="text" name="ipMask" maxlength="15" /></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">DNS 1</div>
|
|
<div class="col-12 col-sm-9"><input type="text" name="ipDns1" maxlength="15" /></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">DNS 2</div>
|
|
<div class="col-12 col-sm-9"><input type="text" name="ipDns2" maxlength="15" /></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">Gateway</div>
|
|
<div class="col-12 col-sm-9"><input type="text" name="ipGateway" maxlength="15" /></div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<button type="button" class="s_collapsible">{#PROTECTION}</button>
|
|
<div class="s_content">
|
|
<fieldset class="mb-4">
|
|
<legend class="des mx-2">{#PROTECTION}</legend>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 mb-2 mt-2">{#ADMIN_PASSWORD}</div>
|
|
<div class="col-12 col-sm-9"><input type="password" name="adminpwd" value="{PWD}"/></div>
|
|
</div>
|
|
<p>{#PROTECTION_NOTE}</p>
|
|
<div id="prot_mask"></div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<button type="button" class="s_collapsible">{#INVERTER}</button>
|
|
<div class="s_content">
|
|
<fieldset class="mb-4">
|
|
<legend class="des">{#INVERTER}</legend>
|
|
<div id="inverter"></div>
|
|
<div class="row mb-3">
|
|
<div class="col-8 my-2">{#INTERVAL} [s]</div>
|
|
<div class="col-4"><input type="number" name="invInterval" title="Invalid input"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-8 mb-2">{#INV_RESET_MIDNIGHT}</div>
|
|
<div class="col-4"><input type="checkbox" name="invRstMid"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-8 mb-2">{#INV_PAUSE_SUNSET}</div>
|
|
<div class="col-4"><input type="checkbox" name="invRstComStop"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-8">{#INV_RESET_NOT_AVAIL}</div>
|
|
<div class="col-4"><input type="checkbox" name="invRstNotAvail"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-8">{#INV_RESET_MAX_MIDNIGHT}</div>
|
|
<div class="col-4"><input type="checkbox" name="invRstMaxMid"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-8">{#INV_START_WITHOUT_TIME}</div>
|
|
<div class="col-4"><input type="checkbox" name="strtWthtTm"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-8">{#INV_READ_GRID_PROFILE}</div>
|
|
<div class="col-4"><input type="checkbox" name="rdGrid"/></div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<!-- NTP Server -->
|
|
<button type="button" class="s_collapsible">NTP Server</button>
|
|
<div class="s_content">
|
|
<fieldset class="mb-4">
|
|
<legend class="des">NTP Server</legend>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">NTP Server / IP</div>
|
|
<div class="col-12 col-sm-9"><input type="text" name="ntpAddr"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">NTP Port</div>
|
|
<div class="col-12 col-sm-9"><input type="number" name="ntpPort"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#NTP_INTERVAL}</div>
|
|
<div class="col-12 col-sm-9"><input type="number" name="ntpIntvl"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#NTP_SET_SYS_TIME}</div>
|
|
<div class="col-12 col-sm-9">
|
|
<input type="button" name="ntpBtn" id="ntpBtn" class="btn" value="{#BTN_FROM_BROWSER}" onclick="setTime()"/>
|
|
<input type="button" name="ntpSync" id="ntpSync" class="btn" value="{#BTN_SYNC_NTP}" onclick="syncTime()"/><br/>
|
|
<span id="apiResultNtp"></span>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#NTP_SYS_TIME}</div>
|
|
<div class="col-12 col-sm-9 my-2"><span id="date"></span></div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<button type="button" class="s_collapsible">{#SUNRISE_SUNSET}</button>
|
|
<div class="s_content">
|
|
<fieldset class="mb-4">
|
|
<legend class="des">{#SUNRISE_SUNSET}</legend>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#LATITUDE}</div>
|
|
<div class="col-12 col-sm-9"><input type="number" name="sunLat" step="any"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#LONGITUDE}</div>
|
|
<div class="col-12 col-sm-9"><input type="number" name="sunLon" step="any"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#OFFSET_SUNRISE}</div>
|
|
<div class="col-12 col-sm-9"><select name="sunOffsSr"></select></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#OFFSET_SUNSET}</div>
|
|
<div class="col-12 col-sm-9"><select name="sunOffsSs"></select></div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<!-- MQTT -->
|
|
<button type="button" class="s_collapsible">MQTT</button>
|
|
<div class="s_content">
|
|
<fieldset class="mb-4">
|
|
<legend class="des">MQTT</legend>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">Broker / Server IP</div>
|
|
<div class="col-12 col-sm-9"><input type="text" name="mqttAddr"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">Port</div>
|
|
<div class="col-12 col-sm-9"><input type="number" name="mqttPort"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">Client Id (optional)</div>
|
|
<div class="col-12 col-sm-9"><input type="text" name="mqttClientId"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#MQTT_USER}</div>
|
|
<div class="col-12 col-sm-9"><input type="text" name="mqttUser"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#MQTT_PASSWORD}</div>
|
|
<div class="col-12 col-sm-9"><input type="password" name="mqttPwd"/></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">Topic</div>
|
|
<div class="col-12 col-sm-9"><input type="text" name="mqttTopic" pattern="[\-\+A-Za-z0-9\.\/#\$%&=_]+" title="Invalid input" /></div>
|
|
</div>
|
|
<p class="des">{#MQTT_NOTE}</p>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#INTERVAL}</div>
|
|
<div class="col-12 col-sm-9"><input tyCMT2300Ape="number" name="mqttInterval" title="Invalid input" /></div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">Discovery Config (homeassistant)</div>
|
|
<div class="col-12 col-sm-9">
|
|
<input type="button" name="mqttDiscovery" id="mqttDiscovery" class="btn" value="{#BTN_SEND}" onclick="sendDiscoveryConfig()"/>
|
|
<span id="apiResultMqtt"></span>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<button type="button" class="s_collapsible">{#PINOUT_CONFIG}</button>
|
|
<div class="s_content">
|
|
<fieldset class="mb-4">
|
|
<legend class="des">{#PINOUT_CONFIG}</legend>
|
|
<p class="des">Status LEDs</p>
|
|
<div id="pinout"></div>
|
|
|
|
<p class="des">{#RADIO} (NRF24L01+)</p>
|
|
<div id="rf24"></div>
|
|
<!--IF_ESP32-->
|
|
<p class="des">{#RADIO} (CMT2300A)</p>
|
|
<div id="cmt"></div>
|
|
<!--ENDIF_ESP32-->
|
|
<!--IF_ETHERNET-->
|
|
<p class="des">Ethernet</p>
|
|
<div id="eth"></div>
|
|
<!--ENDIF_ETHERNET-->
|
|
</fieldset>
|
|
</div>
|
|
<!--IF_PLUGIN_DISPLAY-->
|
|
<button type="button" class="s_collapsible">{#DISPLAY_CONFIG}</button>
|
|
<div class="s_content">
|
|
<fieldset class="mb-4">
|
|
<legend class="des">{#DISPLAY_CONFIG}</legend>
|
|
<div id="dispType"></div>
|
|
<div id="dispRot"></div>
|
|
<div class="row mb-3">
|
|
<div class="col-8 col-sm-3">{#DISP_OFF_INV}</div>
|
|
<div class="col-4 col-sm-9"><input type="checkbox" name="disp_pwr"/></div>
|
|
</div>
|
|
<div id="screenSaver"></div>
|
|
<div class="row mb-3" id="luminanceOption">
|
|
<div class="col-12 col-sm-3 my-2">{#DISP_LUMINANCE}</div>
|
|
<div class="col-12 col-sm-9"><input type="number" name="disp_cont" min="0" max="255"></select></div>
|
|
</div>
|
|
<p class="des">{#DISP_PINOUT}</p>
|
|
<div id="dispPins"></div>
|
|
<div id="pirPin"></div>
|
|
<div id="graphOptions">
|
|
<p class="des">{#GRAPH_OPTIONS}</p>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#GRAPH_SHOW_RATIO}</div>
|
|
<div class="col-12 col-sm-9"><input type="number" name="disp_graph_ratio" min="0" max="100"></select></div>
|
|
</div>
|
|
<div id="graphSize"></div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<!--ENDIF_PLUGIN_DISPLAY-->
|
|
|
|
<button type="button" class="s_collapsible" id="zeroExport_button">{#ZE}</button>
|
|
<!--IF_PLUGIN_ZEROEXPORT-->
|
|
<div class="s_content" id="zeroExport">
|
|
<fieldset class="mb-4">
|
|
<legend class="des">{#ZE}</legend>
|
|
<div id="zeroType"></div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 col-sm-3 my-2">{#ZE_ENABLED}</div>
|
|
<div class="col-12 col-sm-9"><input type="checkbox" name="ze_enabled"/></div>
|
|
<div class="col-12 col-sm-3 my-2">{#ZE_LOG_OVER_WEBSERIAL}</div>
|
|
<div class="col-12 col-sm-9"><input type="checkbox" name="ze_log_over_webserial"/></div>
|
|
<div class="col-12 col-sm-3 my-2">{#ZE_LOG_OVER_MQTT}</div>
|
|
<div class="col-12 col-sm-9"><input type="checkbox" name="ze_log_over_mqtt"/></div>
|
|
<div class="col-12 col-sm-3 my-2">{#ZE_DEBUG}</div>
|
|
<div class="col-12 col-sm-9"><input type="checkbox" name="ze_debug"/></div>
|
|
</div>
|
|
<div id="ze_groups"></div>
|
|
</fieldset>
|
|
</div>
|
|
<!--ENDIF_PLUGIN_ZEROEXPORT-->
|
|
|
|
<div class="row mb-4 mt-4">
|
|
<div class="col-8 col-sm-3">{#BTN_REBOOT_SUCCESSFUL_SAVE}</div>
|
|
<div class="col-4 col-sm-9">
|
|
<input type="checkbox" name="reboot" checked />
|
|
<input type="submit" value="{#BTN_SAVE}" class="btn right"/>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
<div class="hr mb-3 mt-3"></div>
|
|
<div class="mb-4 mt-4">
|
|
<a class="btn" href="/erase">{#BTN_ERASE}</a>
|
|
<fieldset class="mb-4">
|
|
<legend class="des">{#IM_EXPORT}</legend>
|
|
<div class="row mb-4 mt-4">
|
|
<div class="col-12 col-sm-3">{#IMPORT}</div>
|
|
<div class="col-12 col-sm-9">
|
|
<form id="form" method="POST" action="/upload" enctype="multipart/form-data" accept-charset="utf-8">
|
|
<div class="row">
|
|
<div class="col-12 col-sm-8 my-2"><input type="file" name="upload"></div>
|
|
<div class="col-12 col-sm-4 my-2"><input type="button" class="btn" value="Import" onclick="hide()"></div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-4 mt-4">
|
|
<div class="col-12 col-sm-3 my-2">{#EXPORT}</div>
|
|
<div class="col-12 col-sm-9">
|
|
<a class="btn" href="/get_setup" target="_blank">{#BTN_EXPORT}</a><span> {#EXPORT_NOTE}</span>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{#HTML_FOOTER}
|
|
<script type="text/javascript">
|
|
var maxInv = 0;
|
|
var ts = 0;
|
|
|
|
/*IF_ESP8266*/
|
|
var esp8266pins = [
|
|
[255, "{#PIN_OFF}"],
|
|
[0, "D3 (GPIO0)"],
|
|
[1, "TX (GPIO1)"],
|
|
[2, "D4 (GPIO2)"],
|
|
[3, "RX (GPIO3)"],
|
|
[4, "D2 (GPIO4, SDA)"],
|
|
[5, "D1 (GPIO5, SCL)"],
|
|
[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 - {#PIN_NO_IRQ})"]
|
|
];
|
|
/*ENDIF_ESP8266*/
|
|
|
|
/*IF_ESP32*/
|
|
var esp32pins = [
|
|
[255, "{#PIN_OFF}"],
|
|
[0, "GPIO0"],
|
|
[1, "TX (GPIO1)"],
|
|
[2, "GPIO2 (LED)"],
|
|
[3, "RX (GPIO3)"],
|
|
[4, "GPIO4"],
|
|
[5, "GPIO5"],
|
|
[12, "GPIO12 (HSPI MISO)"],
|
|
[13, "GPIO13 (HSPI MOSI)"],
|
|
[14, "GPIO14 (HSPI SCLK)"],
|
|
[15, "GPIO15"],
|
|
[16, "GPIO16"],
|
|
[17, "GPIO17"],
|
|
[18, "GPIO18 (VSPI SCLK)"],
|
|
[19, "GPIO19 (VSPI MISO)"],
|
|
[21, "GPIO21 (SDA)"],
|
|
[22, "GPIO22 (SCL)"],
|
|
[23, "GPIO23 (VSPI MOSI)"],
|
|
[25, "GPIO25"],
|
|
[26, "GPIO26"],
|
|
[27, "GPIO27"],
|
|
[32, "GPIO32"],
|
|
[33, "GPIO33"],
|
|
[34, "GPIO34 ({#PIN_INPUT_ONLY})"],
|
|
[35, "GPIO35 ({#PIN_INPUT_ONLY})"],
|
|
[36, "VP (GPIO36, {#PIN_INPUT_ONLY})"],
|
|
[39, "VN (GPIO39, {#PIN_INPUT_ONLY})"]
|
|
];
|
|
/*IF_ESP32-S2*/
|
|
var esp32sXpins = [
|
|
[255, "off / default"],
|
|
[0, "GPIO0 ({#PIN_DONT_USE} - BOOT)"],
|
|
[1, "GPIO1"],
|
|
[2, "GPIO2"],
|
|
[3, "GPIO3"],
|
|
[4, "GPIO4"],
|
|
[5, "GPIO5"],
|
|
[6, "GPIO6"],
|
|
[7, "GPIO7"],
|
|
[8, "GPIO8"],
|
|
[9, "GPIO9"],
|
|
[10, "GPIO10"],
|
|
[11, "GPIO11"],
|
|
[12, "GPIO12"],
|
|
[13, "GPIO13"],
|
|
[14, "GPIO14"],
|
|
[15, "GPIO15"],
|
|
[16, "GPIO16"],
|
|
[17, "GPIO17"],
|
|
[18, "GPIO18"],
|
|
[19, "GPIO19 ({#PIN_DONT_USE} - USB-)"],
|
|
[20, "GPIO20 ({#PIN_DONT_USE} - USB+)"],
|
|
[21, "GPIO21"],
|
|
[26, "GPIO26 (PSRAM - {#PIN_NOT_AVAIL})"],
|
|
[27, "GPIO27 (FLASH - {#PIN_NOT_AVAIL})"],
|
|
[28, "GPIO28 (FLASH - {#PIN_NOT_AVAIL})"],
|
|
[29, "GPIO29 (FLASH - {#PIN_NOT_AVAIL})"],
|
|
[30, "GPIO30 (FLASH - {#PIN_NOT_AVAIL})"],
|
|
[31, "GPIO31 (FLASH - {#PIN_NOT_AVAIL})"],
|
|
[32, "GPIO32 (FLASH - {#PIN_NOT_AVAIL})"],
|
|
[33, "GPIO33 (not exposed on S3-WROOM modules)"],
|
|
[34, "GPIO34 (not exposed on S3-WROOM modules)"],
|
|
[35, "GPIO35"],
|
|
[36, "GPIO36"],
|
|
[37, "GPIO37"],
|
|
[38, "GPIO38"],
|
|
[39, "GPIO39"],
|
|
[40, "GPIO40"],
|
|
[41, "GPIO41"],
|
|
[42, "GPIO42"],
|
|
[43, "GPIO43"],
|
|
[44, "GPIO44"],
|
|
[45, "GPIO45 ({#PIN_DONT_USE} - STRAPPING PIN)"],
|
|
[46, "GPIO46 ({#PIN_DONT_USE} - STRAPPING PIN)"],
|
|
[47, "GPIO47"],
|
|
[48, "GPIO48"],
|
|
];
|
|
/*ENDIF_ESP32-S2*/
|
|
/*IF_ESP32-S3*/
|
|
var esp32sXpins = [
|
|
[255, "off / default"],
|
|
[0, "GPIO0 ({#PIN_DONT_USE} - BOOT)"],
|
|
[1, "GPIO1"],
|
|
[2, "GPIO2"],
|
|
[3, "GPIO3"],
|
|
[4, "GPIO4"],
|
|
[5, "GPIO5"],
|
|
[6, "GPIO6"],
|
|
[7, "GPIO7"],
|
|
[8, "GPIO8"],
|
|
[9, "GPIO9"],
|
|
[10, "GPIO10"],
|
|
[11, "GPIO11"],
|
|
[12, "GPIO12"],
|
|
[13, "GPIO13"],
|
|
[14, "GPIO14"],
|
|
[15, "GPIO15"],
|
|
[16, "GPIO16"],
|
|
[17, "GPIO17"],
|
|
[18, "GPIO18"],
|
|
[19, "GPIO19 ({#PIN_DONT_USE} - USB-)"],
|
|
[20, "GPIO20 ({#PIN_DONT_USE} - USB+)"],
|
|
[21, "GPIO21"],
|
|
[26, "GPIO26 (PSRAM - {#PIN_NOT_AVAIL})"],
|
|
[27, "GPIO27 (FLASH - {#PIN_NOT_AVAIL})"],
|
|
[28, "GPIO28 (FLASH - {#PIN_NOT_AVAIL})"],
|
|
[29, "GPIO29 (FLASH - {#PIN_NOT_AVAIL})"],
|
|
[30, "GPIO30 (FLASH - {#PIN_NOT_AVAIL})"],
|
|
[31, "GPIO31 (FLASH - {#PIN_NOT_AVAIL})"],
|
|
[32, "GPIO32 (FLASH - {#PIN_NOT_AVAIL})"],
|
|
[33, "GPIO33 (not exposed on S3-WROOM modules)"],
|
|
[34, "GPIO34 (not exposed on S3-WROOM modules)"],
|
|
[35, "GPIO35"],
|
|
[36, "GPIO36"],
|
|
[37, "GPIO37"],
|
|
[38, "GPIO38"],
|
|
[39, "GPIO39"],
|
|
[40, "GPIO40"],
|
|
[41, "GPIO41"],
|
|
[42, "GPIO42"],
|
|
[43, "GPIO43"],
|
|
[44, "GPIO44"],
|
|
[45, "GPIO45 ({#PIN_DONT_USE} - STRAPPING PIN)"],
|
|
[46, "GPIO46 ({#PIN_DONT_USE} - STRAPPING PIN)"],
|
|
[47, "GPIO47"],
|
|
[48, "GPIO48"],
|
|
];
|
|
/*ENDIF_ESP32-S3*/
|
|
/*IF_ESP32-C3*/
|
|
var esp32c3pins = [
|
|
[255, "off / default"],
|
|
[0, "GPIO0"],
|
|
[1, "GPIO1"],
|
|
[2, "GPIO2"],
|
|
[3, "GPIO3"],
|
|
[4, "GPIO4"],
|
|
[5, "GPIO5"],
|
|
[6, "GPIO6"],
|
|
[7, "GPIO7"],
|
|
[8, "GPIO8"],
|
|
[9, "GPIO9"],
|
|
[10, "GPIO10"],
|
|
[11, "GPIO11"],
|
|
[12, "GPIO12 (PSRAM/FLASH)"],
|
|
[13, "GPIO13 (PSRAM/FLASH)"],
|
|
[14, "GPIO14 (PSRAM/FLASH)"],
|
|
[15, "GPIO15 (PSRAM/FLASH)"],
|
|
[16, "GPIO16 (PSRAM/FLASH)"],
|
|
[17, "GPIO17 (PSRAM/FLASH)"],
|
|
[18, "GPIO18 ({#PIN_DONT_USE} - USB-)"],
|
|
[19, "GPIO19 ({#PIN_DONT_USE} - USB+)"],
|
|
[20, "GPIO20 (RX)"],
|
|
[21, "GPIO21 (TX)"],
|
|
];
|
|
/*ENDIF_ESP32-C3*/
|
|
/*ENDIF_ESP32*/
|
|
var nrfPa = [
|
|
[0, "MIN ({#PIN_RECOMMENDED})"],
|
|
[1, "LOW"],
|
|
[2, "HIGH"],
|
|
[3, "MAX ({#PIN_EXPERIMENTAL})"]
|
|
];
|
|
var esp32cmtPa = [];
|
|
var esp32cmtFreq = [];
|
|
|
|
/*IF_ESP32*/
|
|
var freqFmt = new Intl.NumberFormat('en-US', {
|
|
minimumIntegerDigits: 3,
|
|
minimumFractionDigits: 2
|
|
});
|
|
for(var i = 0; i < 31; i++) {
|
|
esp32cmtPa.push([i, String(i-10) + " dBm"]);
|
|
}
|
|
/*ENDIF_ESP32*/
|
|
var led_high_active = [
|
|
[0, "{#PIN_LOW_ACTIVE}"],
|
|
[1, "{#PIN_HIGH_ACTIVE}"],
|
|
];
|
|
|
|
window.onload = function() {
|
|
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";
|
|
});
|
|
}
|
|
|
|
document.getElementById("settings").addEventListener("submit", function() {
|
|
var inputs = document.querySelectorAll("input[type='number']");
|
|
for (var i = 0; i < inputs.length; i++) {
|
|
if (inputs[i].value.indexOf(",") != -1)
|
|
inputs[i].value = inputs[i].value.replace(",", ".");
|
|
}
|
|
});
|
|
}
|
|
|
|
function apiCbWifi(obj) {
|
|
var e = document.getElementById("networks");
|
|
selDelAllOpt(e);
|
|
if(obj["success"])
|
|
e.appendChild(opt("-1", "{#NETWORK_SCANNING}"))
|
|
else
|
|
e.appendChild(opt("-1", "{#ERROR} " + obj["error"]));
|
|
}
|
|
|
|
function apiCbNtp(obj) {
|
|
var e = document.getElementById("apiResultNtp");
|
|
if(obj["success"])
|
|
e.innerHTML = "{#NTP_COMMAND_EXE}";
|
|
else
|
|
e.innerHTML = "{#ERROR} " + obj["error"];
|
|
}
|
|
|
|
function apiCbNtp2(obj) {
|
|
var e = document.getElementById("apiResultNtp");
|
|
var date = new Date(obj["ts_now"] * 1000);
|
|
e.innerHTML = "{#NTP_SYNCED_AT}: " + toIsoDateStr(date) + ", {#NTP_DIFF}: " + (ts - obj["ts_now"]) + "ms";
|
|
}
|
|
|
|
function apiCbMqtt(obj) {
|
|
var e = document.getElementById("apiResultMqtt");
|
|
if(obj["success"])
|
|
e.innerHTML = "{#MQTT_EXE}";
|
|
else
|
|
e.innerHTML = "{#ERROR} " + obj["error"];
|
|
}
|
|
|
|
function setTime() {
|
|
var date = new Date()
|
|
var obj = {cmd: "set_time", token: "*", val: parseInt(date.getTime() / 1000)}
|
|
getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj))
|
|
setTimeout(function() {getAjax('/api/index', apiCbNtp2)}, 2000)
|
|
}
|
|
|
|
function syncTime() {
|
|
var obj = {cmd: "sync_ntp", token: "*"}
|
|
getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj))
|
|
setTimeout(function() {getAjax('/api/index', apiCbNtp2)}, 2000)
|
|
}
|
|
|
|
function sendDiscoveryConfig() {
|
|
var obj = {cmd: "discovery_cfg", token: "*"}
|
|
getAjax("/api/setup", apiCbMqtt, "POST", JSON.stringify(obj));
|
|
}
|
|
|
|
function hide() {
|
|
document.getElementById("form").submit();
|
|
var e = document.getElementById("content");
|
|
e.replaceChildren(span("{#IMPORT_UPLOAD_STARTED}"));
|
|
}
|
|
|
|
function delIv() {
|
|
var id = this.id.substring(0, this.id.length-3);
|
|
document.getElementById(id).remove();
|
|
}
|
|
|
|
function mlCb(id, des, chk=false) {
|
|
var cb = ml("input", {type: "checkbox", id: id, name: id}, "");
|
|
if(chk)
|
|
cb.checked = true;
|
|
return ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-8 col-sm-3"}, des),
|
|
ml("div", {class: "col-4 col-sm-9"}, cb)
|
|
]);
|
|
}
|
|
|
|
function mlE(des, e) {
|
|
return ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-12 col-sm-3 my-2"}, des),
|
|
ml("div", {class: "col-12 col-sm-9"}, e)
|
|
]);
|
|
}
|
|
|
|
function getFreeId() {
|
|
var id = 0;
|
|
while(id < maxInv) {
|
|
if(null == document.getElementById("inv" + id))
|
|
return id;
|
|
id++;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function ivGlob(obj) {
|
|
for(var i of [["invInterval", "interval"]])
|
|
document.getElementsByName(i[0])[0].value = obj[i[1]];
|
|
for(var i of ["Mid", "ComStop", "NotAvail", "MaxMid"])
|
|
document.getElementsByName("invRst"+i)[0].checked = obj["rst" + i];
|
|
document.getElementsByName("strtWthtTm")[0].checked = obj["strtWthtTm"];
|
|
document.getElementsByName("rdGrid")[0].checked = obj["rdGrid"];
|
|
}
|
|
|
|
function parseSys(obj) {
|
|
for(var i of [["device", "device_name"], ["ssid", "ssid"], ["ap_pwd", "ap_pwd"]])
|
|
document.getElementsByName(i[0])[0].value = obj[i[1]];
|
|
document.getElementsByName("hidd")[0].checked = obj["hidd"];
|
|
document.getElementsByName("darkMode")[0].checked = obj["dark_mode"];
|
|
document.getElementsByName("schedReboot")[0].checked = obj["sched_reboot"];
|
|
e = document.getElementsByName("adminpwd")[0];
|
|
if(!obj["pwd_set"])
|
|
e.value = "";
|
|
var d = document.getElementById("prot_mask");
|
|
var a = ["Index", "{#NAV_LIVE}", "{#NAV_WEBSERIAL}", "{#NAV_SETTINGS}", "Update", "System", "{#NAV_HISTORY}"];
|
|
var el = [];
|
|
for(var i = 0; i < 7; i++) {
|
|
var chk = ((obj["prot_mask"] & (1 << i)) == (1 << i));
|
|
el.push(mlCb("protMask" + i, a[i], chk))
|
|
}
|
|
d.append(...el);
|
|
|
|
var tz = []
|
|
for(i = 0; i < 24; i += 0.5)
|
|
tz.push([i, ((i-12 > 0) ? "+" : "") + String(i-12)]);
|
|
document.getElementById("timezone").append(sel("timezone", tz, obj.timezone + 12))
|
|
var region = [[0, "Europe (860 - 870 MHz)"], [1, "USA, Indonesia (905 - 925 MHz)"], [2, "Brazil (915 - 928 MHz)"]]
|
|
document.getElementById("region").append(sel("region", region, obj.region))
|
|
|
|
}
|
|
|
|
function parseGeneric(obj) {
|
|
parseNav(obj);
|
|
parseESP(obj);
|
|
parseRssi(obj);
|
|
|
|
if(0 != obj.cst_lnk.length) {
|
|
document.getElementsByName("cstLnk")[0].value = obj.cst_lnk
|
|
document.getElementsByName("cstLnkTxt")[0].value = obj.cst_lnk_txt
|
|
}
|
|
|
|
ts = obj["ts_now"];
|
|
window.setInterval("tick()", 1000);
|
|
}
|
|
|
|
function parseStaticIp(obj) {
|
|
for(var i of [["ipAddr", "ip"], ["ipMask", "mask"], ["ipDns1", "dns1"], ["ipDns2", "dns2"], ["ipGateway", "gateway"]])
|
|
if(null != obj[i[1]])
|
|
document.getElementsByName(i[0])[0].value = obj[i[1]];
|
|
}
|
|
|
|
function parseIv(obj) {
|
|
maxInv = obj["max_num_inverters"];
|
|
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;"}, "{#INV_EDIT}"),
|
|
ml("th", {style: "width: 10%; text-align: center;"}, "{#INV_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 = [400,400,400,400,400,400];
|
|
add.ch_name = [];
|
|
add.ch_yield_cor = [];
|
|
add.freq = 12;
|
|
add.pa = 30;
|
|
|
|
var e = document.getElementById("inverter");
|
|
e.innerHTML = ""; // remove all childs
|
|
e.append(ml("table", {class: "table"}, ml("tbody", {}, lines)));
|
|
if(obj.max_num_inverters > obj.inverter.length)
|
|
e.append(ml("div", {class: "row my-3"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", value: "{#BTN_INV_ADD}", class: "btn", onclick: function() { ivModal(add); }}, null))));
|
|
|
|
ivGlob(obj);
|
|
}
|
|
|
|
function divRow(item0, item1) {
|
|
return ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-3 mt-2"}, item0),
|
|
ml("div", {class: "col-9"}, item1)
|
|
])
|
|
}
|
|
|
|
function ivModal(obj) {
|
|
var lines = [];
|
|
lines.push(ml("tr", {}, [
|
|
ml("th", {style: "width: 10%;"}, "{#INV_INPUT}"),
|
|
ml("th", {}, "{#INV_MAX_MODULE_POWER} [Wp]"),
|
|
ml("th", {}, "Name (optional)"),
|
|
ml("th", {}, "{#INV_YIELD_CORR} [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], step: "0.001"}, null))
|
|
]));
|
|
}
|
|
|
|
var cbEn = ml("input", {name: "enable", type: "checkbox"}, null);
|
|
var cbDisNightCom = ml("input", {name: "disnightcom", type: "checkbox"}, null);
|
|
cbEn.checked = (obj.enabled);
|
|
cbDisNightCom.checked = (obj.disnightcom);
|
|
|
|
var ser = ml("input", {name: "ser", class: "text", type: "text", pattern: "[0-9a-fA-F]{12}", value: obj.serial}, null);
|
|
var html = ml("div", {}, [
|
|
tabs(["{#TAB_GENERAL}", "{#TAB_INPUTS}", "{#TAB_RADIO}", "{#TAB_ADVANCED}"]),
|
|
ml("div", {id: "div{#TAB_GENERAL}", class: "tab-content"}, [
|
|
divRow("{#INV_ENABLE}", cbEn),
|
|
divRow("{#INV_SERIAL}", ser),
|
|
divRow("Name", ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null))
|
|
]),
|
|
ml("div", {id: "div{#TAB_INPUTS}", class: "tab-content hide"}, [
|
|
ml("div", {class: "row mb-3"},
|
|
ml("table", {class: "table"}, ml("tbody", {}, lines))
|
|
)
|
|
]),
|
|
ml("div", {id: "div{#TAB_RADIO}", class: "tab-content hide"}, [
|
|
ml("input", {type: "hidden", name: "isnrf"}, null),
|
|
ml("div", {id: "setcmt"}, [
|
|
divRow("{#INV_FREQUENCY}", sel("freq", esp32cmtFreq, obj.freq)),
|
|
divRow("{#INV_POWER_LEVEL}", sel("cmtpa", esp32cmtPa, obj.pa))
|
|
]),
|
|
ml("div", {id: "setnrf"},
|
|
divRow("{#INV_POWER_LEVEL}", sel("nrfpa", nrfPa, obj.pa))
|
|
),
|
|
]),
|
|
ml("div", {id: "div{#TAB_ADVANCED}", class: "tab-content hide"}, [
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-10"}, "{#INV_PAUSE_DURING_NIGHT}"),
|
|
ml("div", {class: "col-2"}, cbDisNightCom)
|
|
])
|
|
]),
|
|
ml("div", {class: "row mt-5"}, [
|
|
ml("div", {class: "col-8", id: "res"}, ""),
|
|
ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "{#BTN_SAVE}", class: "btn", onclick: function() { ivSave(); }}, null))
|
|
])
|
|
]);
|
|
|
|
['keyup', 'change'].forEach(function(evt) {
|
|
ser.addEventListener(evt, (e) => {
|
|
var sn = parseInt(ser.value, 16);
|
|
sn = Math.floor(sn / Math.pow(2, 32));
|
|
|
|
var max = 1;
|
|
switch(sn & 0x00f0) {
|
|
case 0x0010: max = 1; break;
|
|
case 0x0040: max = 2; break;
|
|
case 0x0060: max = 4; break;
|
|
case 0x0080: max = 6; break;
|
|
}
|
|
for(var i = 0; i < 6; i++) {
|
|
setHide("ch"+i, (i >= max));
|
|
}
|
|
|
|
var nrf = true;
|
|
switch(sn & 0xff00) {
|
|
case 0x1000: nrf = true; break;
|
|
case 0x1100:
|
|
switch(sn & 0x000f) {
|
|
case 0x0004:
|
|
case 0x0005: nrf = false; break;
|
|
default: nrf = true; break;
|
|
}
|
|
break;
|
|
case 0x1300: nrf = false; break;
|
|
}
|
|
setHide("setcmt", nrf);
|
|
setHide("setnrf", !nrf);
|
|
document.getElementsByName("isnrf")[0].value = nrf;
|
|
})
|
|
});
|
|
|
|
modal("{#INV_EDIT_MODAL}: " + obj.name, html);
|
|
ser.dispatchEvent(new Event('change'));
|
|
|
|
function ivSave() {
|
|
var o = new Object();
|
|
o.cmd = "save_iv"
|
|
o.token = "*"
|
|
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);
|
|
}
|
|
if("true" == document.getElementsByName("isnrf")[0].value)
|
|
o.pa = document.getElementsByName("nrfpa")[0].value;
|
|
else
|
|
o.pa = document.getElementsByName("cmtpa")[0].value;
|
|
o.freq = document.getElementsByName("freq")[0].value;
|
|
o.disnightcom = document.getElementsByName("disnightcom")[0].checked;
|
|
getAjax("/api/setup", cb, "POST", JSON.stringify(o));
|
|
}
|
|
|
|
function cb(obj2) {
|
|
var e = document.getElementById("res");
|
|
if(!obj2.success)
|
|
e.innerHTML = "{#ERROR}" + obj2.error;
|
|
else {
|
|
modalClose();
|
|
getAjax("/api/inverter/list", parseIv);
|
|
}
|
|
}
|
|
}
|
|
|
|
function ivDel(obj) {
|
|
var html = ml("div", {class: "row"}, [
|
|
ml("div", {class: "col-9"}, "{#INV_DELETE_SURE} (" + obj.name + ")"),
|
|
ml("div", {class: "col-3 a-r"}, ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "{#BTN_YES}", class: "btn", onclick: function() { del(); }}, null)))
|
|
]);
|
|
modal("{#INV_DELETE_MODAL}: " + 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]];
|
|
}
|
|
|
|
function parseNtp(obj) {
|
|
for(var i of [["ntpAddr", "addr"], ["ntpPort", "port"], ["ntpIntvl", "interval"]])
|
|
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"];
|
|
for(p of [["sunOffsSr", "offsSr"], ["sunOffsSs", "offsSs"]]) {
|
|
const sel = document.getElementsByName(p[0])[0];
|
|
for(var i = -60; i <= 60; i++) {
|
|
sel.appendChild(opt(i, i + " {#NTP_MINUTES}", (i == (obj[p[1]] / 60))));
|
|
}
|
|
}
|
|
}
|
|
|
|
function parsePinout(obj) {
|
|
var e = document.getElementById("pinout");
|
|
/*IF_ESP32*/
|
|
var pinList = esp32pins;
|
|
/*IF_ESP32-S2*/
|
|
pinList = esp32sXpins;
|
|
/*ENDIF_ESP32-S2*/
|
|
/*IF_ESP32-S3*/
|
|
pinList = esp32sXpins;
|
|
/*ENDIF_ESP32-S3*/
|
|
/*IF_ESP32-C3*/
|
|
pinList = esp32c3pins;
|
|
/*ENDIF_ESP32-C3*/
|
|
/*ELSE*/
|
|
var pinList = esp8266pins;
|
|
/*ENDIF_ESP32*/
|
|
pins = [['led0', 'pinLed0', '{#LED_AT_LEAST_ONE_PRODUCING}'], ['led1', 'pinLed1', '{#LED_MQTT_CONNECTED}'], ['led2', 'pinLed2', '{#LED_NIGHT_TIME}']];
|
|
for(p of pins) {
|
|
e.append(
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-12 col-sm-3 my-2"}, p[2]),
|
|
ml("div", {class: "col-12 col-sm-9"},
|
|
sel(p[1], pinList, obj[p[0]])
|
|
)
|
|
])
|
|
);
|
|
}
|
|
e.append(
|
|
ml("div", { class: "row mb-3" }, [
|
|
ml("div", { class: "col-12 col-sm-3 my-2" }, "{#LED_POLARITY}"),
|
|
ml("div", { class: "col-12 col-sm-9" },
|
|
sel('pinLedHighActive', led_high_active, obj.led_high_active)
|
|
)
|
|
]),
|
|
ml("div", { class: "row mb-3" }, [
|
|
ml("div", { class: "col-12 col-sm-3 my-2" }, "{#LED_LUMINANCE} (0-255)"),
|
|
ml("div", { class: "col-12 col-sm-9" }, ml("input", {class: "text", type: "number", name: "pinLedLum", value: obj.led_lum, min: 0, max: 255}, null))
|
|
])
|
|
)
|
|
}
|
|
|
|
function parseNrfRadio(obj, objPin) {
|
|
var e = document.getElementById("rf24");
|
|
var en = inp("nrfEnable", null, null, ["cb"], "nrfEnable", "checkbox");
|
|
en.checked = obj["en"];
|
|
|
|
/*IF_ESP32*/
|
|
var pinList = esp32pins;
|
|
/*IF_ESP32-S2*/
|
|
pinList = esp32sXpins;
|
|
/*ENDIF_ESP32-S2*/
|
|
/*IF_ESP32-S3*/
|
|
pinList = esp32sXpins;
|
|
/*ENDIF_ESP32-S3*/
|
|
/*IF_ESP32-C3*/
|
|
pinList = esp32c3pins;
|
|
/*ENDIF_ESP32-C3*/
|
|
/*ELSE*/
|
|
var pinList = esp8266pins;
|
|
/*ENDIF_ESP32*/
|
|
|
|
e.replaceChildren (
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-8 col-sm-3 my-2"}, "{#NRF24_ENABLE}"),
|
|
ml("div", {class: "col-4 col-sm-9"}, en)
|
|
])
|
|
);
|
|
|
|
/*IF_ESP32*/
|
|
var pins = [['cs', 'pinCs'], ['ce', 'pinCe'], ['irq', 'pinIrq'], ['sclk', 'pinSclk'], ['mosi', 'pinMosi'], ['miso', 'pinMiso']];
|
|
/*ELSE*/
|
|
var pins = [['cs', 'pinCs'], ['ce', 'pinCe'], ['irq', 'pinIrq']];
|
|
/*ENDIF_ESP32*/
|
|
for(p of pins) {
|
|
e.append(
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()),
|
|
ml("div", {class: "col-12 col-sm-9"},
|
|
sel(p[1], pinList, objPin[p[0]])
|
|
)
|
|
])
|
|
);
|
|
}
|
|
}
|
|
|
|
/*IF_ESP32*/
|
|
function parseCmtRadio(obj) {
|
|
var e = document.getElementById("cmt");
|
|
var en = inp("cmtEnable", null, null, ["cb"], "cmtEnable", "checkbox");
|
|
var pinList = esp32pins;
|
|
/*IF_ESP32-S2*/
|
|
pinList = esp32sXpins;
|
|
/*ENDIF_ESP32-S2*/
|
|
/*IF_ESP32-S3*/
|
|
pinList = esp32sXpins;
|
|
/*ENDIF_ESP32-S3*/
|
|
/*IF_ESP32-C3*/
|
|
pinList = esp32c3pins;
|
|
/*ENDIF_ESP32-C3*/
|
|
|
|
en.checked = obj["en"];
|
|
e.replaceChildren (
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-8 col-sm-3 my-2"}, "{#CMT_ENABLE}"),
|
|
ml("div", {class: "col-4 col-sm-9"}, en)
|
|
])
|
|
);
|
|
pins = [['sclk', 'pinCmtSclk'], ['sdio', 'pinSdio'], ['csb', 'pinCsb'], ['fcsb', 'pinFcsb'], ['gpio3', 'pinGpio3']];
|
|
for(p of pins) {
|
|
e.append(
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()),
|
|
ml("div", {class: "col-12 col-sm-9"},
|
|
sel(p[1], pinList, obj[p[0]])
|
|
)
|
|
])
|
|
);
|
|
}
|
|
|
|
var i = 0
|
|
while(obj.freq_max >= (obj.freq_min + i * 0.25)) {
|
|
esp32cmtFreq.push([i, freqFmt.format(obj.freq_min + i * 0.25) + " MHz"])
|
|
i++
|
|
}
|
|
}
|
|
/*ENDIF_ESP32*/
|
|
|
|
/*IF_ETHERNET*/
|
|
function parseEth(obj) {
|
|
var e = document.getElementById("eth");
|
|
var en = inp("ethEn", null, null, ["cb"], "ethEn", "checkbox");
|
|
var pinList = esp32pins;
|
|
/*IF_ESP32-S2*/
|
|
pinList = esp32sXpins;
|
|
/*ENDIF_ESP32-S2*/
|
|
/*IF_ESP32-S3*/
|
|
pinList = esp32sXpins;
|
|
/*ENDIF_ESP32-S3*/
|
|
/*IF_ESP32-C3*/
|
|
pinList = esp32c3pins;
|
|
/*ENDIF_ESP32-C3*/
|
|
|
|
en.checked = obj["en"];
|
|
e.replaceChildren (
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-8 col-sm-3 my-2"}, "{#ETH_ENABLE}"),
|
|
ml("div", {class: "col-4 col-sm-9"}, en)
|
|
])
|
|
);
|
|
pins = [['cs', 'ethCs'], ['sclk', 'ethSclk'], ['miso', 'ethMiso'], ['mosi', 'ethMosi'], ['irq', 'ethIrq'], ['reset', 'ethRst']];
|
|
for(p of pins) {
|
|
e.append(
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()),
|
|
ml("div", {class: "col-12 col-sm-9"},
|
|
sel(p[1], pinList, obj[p[0]])
|
|
)
|
|
])
|
|
);
|
|
}
|
|
}
|
|
/*ENDIF_ETHERNET*/
|
|
|
|
function parseSerial(obj) {
|
|
var e = document.getElementById("serialCb")
|
|
var l = [["serEn", "show_live_data", "{#LOG_PRINT_INVERTER_DATA}"], ["serDbg", "debug", "{#LOG_SERIAL_DEBUG}"], ["priv", "priv", "{#LOG_PRIVACY_MODE}"], ["wholeTrace", "wholeTrace", "{#LOG_PRINT_TRACES}"], ["log2mqtt", "log2mqtt", "{#LOG_TO_MQTT}"]]
|
|
for(var i of l) {
|
|
var cb = ml("input", {name: i[0], type: "checkbox"}, null)
|
|
cb.checked = obj[i[1]]
|
|
e.appendChild(
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-8 col-sm-3"}, i[2]),
|
|
ml("div", {class: "col-4 col-sm-9"}, cb)
|
|
])
|
|
)
|
|
}
|
|
}
|
|
|
|
/*IF_PLUGIN_DISPLAY*/
|
|
function parseDisplay(obj, type, system) {
|
|
/*IF_ESP32*/
|
|
var pinList = esp32pins;
|
|
/*IF_ESP32-S2*/
|
|
pinList = esp32sXpins;
|
|
/*ENDIF_ESP32-S2*/
|
|
/*IF_ESP32-S3*/
|
|
pinList = esp32sXpins;
|
|
/*ENDIF_ESP32-S3*/
|
|
/*IF_ESP32-C3*/
|
|
pinList = esp32c3pins;
|
|
/*ENDIF_ESP32-C3*/
|
|
/*ELSE*/
|
|
var pinList = esp8266pins;
|
|
/*ENDIF_ESP32*/
|
|
|
|
for(var i of ["disp_pwr"])
|
|
document.getElementsByName(i)[0].checked = obj[i];
|
|
|
|
var dpins_elem = document.getElementById("dispPins");
|
|
//KEEP this order !!!
|
|
var pins = [['clock', 'disp_clk'], ['data', 'disp_data'], ['cs', 'disp_cs'], ['dc', 'disp_dc'], ['reset', 'disp_rst']];
|
|
/*IF_ESP32*/
|
|
pins.push(['busy', 'disp_bsy']);
|
|
/*ENDIF_ESP32*/
|
|
for(p of pins) {
|
|
dpins_elem.append(
|
|
ml("div", {class: "row mb-3", id: "row_" + p[1]}, [
|
|
ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()),
|
|
ml("div", {class: "col-12 col-sm-9"},
|
|
sel(p[1], pinList, obj[p[1]])
|
|
)
|
|
])
|
|
);
|
|
}
|
|
// keep display types grouped
|
|
var opts = [[0, "{#DISP_NONE}"],
|
|
[2, "SH1106 128x64 (1.3\")"],
|
|
[5, "SSD1306 64x48 (0.66\" Wemos OLED Shield)"],
|
|
[4, "SSD1306 128x32 (0.91\")"],
|
|
[1, "SSD1306 128x64 (0.96\", 1.54\")"],
|
|
[6, "SSD1309 128x64 (2.42\")"],
|
|
[3, "PCD8544 84x48 (1.6\" Nokia 5110)"]];
|
|
/*IF_ESP32*/
|
|
opts.push([10, "ePaper"]);
|
|
/*ENDIF_ESP32*/
|
|
var dtype_sel = sel("disp_typ", opts, obj["disp_typ"]);
|
|
document.getElementById("dispType").append(
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-12 col-sm-3 my-2"}, "{#DISP_TYPE}"),
|
|
ml("div", {class: "col-12 col-sm-9"}, dtype_sel)
|
|
])
|
|
);
|
|
opts = [[0, "0°"], [2, "180°"]];
|
|
/*IF_ESP32*/
|
|
opts.push([1, "90°"]);
|
|
opts.push([3, "270°"]);
|
|
/*ENDIF_ESP32*/
|
|
document.getElementById("dispRot").append(
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-12 col-sm-3 my-2"}, "{#DISP_ROTATION}"),
|
|
ml("div", {class: "col-12 col-sm-9"}, sel("disp_rot", opts, obj["disp_rot"]))
|
|
])
|
|
);
|
|
|
|
var opts1 = [[0, "{#DISP_SCREENSAVER_OFF}"], [1, "{#DISP_PIXEL_SHIFT}"], [2, "{#DISP_MOTION_SENS}"]];
|
|
var screensaver_sel = sel("disp_screensaver", opts1, obj["disp_screensaver"]);
|
|
screensaver_sel.id = 'disp_screensaver';
|
|
document.getElementById("screenSaver").append(
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-12 col-sm-3 my-2"}, "{#DISP_SCREENSAVER}"),
|
|
ml("div", {class: "col-12 col-sm-9"}, screensaver_sel)
|
|
])
|
|
);
|
|
|
|
var esp8266pirpins = [[255, "{#PIN_OFF}"],
|
|
[17, "A0"]];
|
|
document.getElementById("pirPin").append(
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-12 col-sm-3 my-2"}, "PIR sensor"),
|
|
ml("div", {class: "col-12 col-sm-9"}, sel("pir_pin", ("ESP8266" == type) ? esp8266pirpins : pinList, obj["pir_pin"]))
|
|
])
|
|
);
|
|
|
|
document.getElementsByName("disp_cont")[0].value = obj["disp_cont"];
|
|
|
|
dtype_sel.addEventListener('change', function(e) {
|
|
hideDispPins(pins, parseInt(e.target.value))
|
|
});
|
|
|
|
document.getElementById("disp_screensaver").addEventListener('change', function(e) {
|
|
hideDispPins(pins, parseInt(dtype_sel.value))
|
|
});
|
|
|
|
document.getElementsByName("disp_graph_ratio")[0].value = obj["disp_graph_ratio"];
|
|
|
|
var opts2 = [[0, "{#GRAPH_LINES_1_2}"], [1, "{#GRAPH_LINES_2_3}"], [2, "{#GRAPH_LINES_1_3}"], [3, "{#GRAPH_LINES_2_4}"], [4, "{#GRAPH_LINES_1_4}"]];
|
|
var graph_size_sel = sel("disp_graph_size", opts2, obj["disp_graph_size"]);
|
|
graph_size_sel.id = 'disp_graph_size';
|
|
document.getElementById("graphSize").append(
|
|
ml("div", {class: "row mb-3"}, [
|
|
ml("div", {class: "col-12 col-sm-3 my-2"}, "{#GRAPH_POSITION}"),
|
|
ml("div", {class: "col-12 col-sm-9"}, graph_size_sel)
|
|
])
|
|
);
|
|
|
|
hideDispPins(pins, obj.disp_typ);
|
|
}
|
|
|
|
function hideDispPins(pins, dispType) {
|
|
// create pin map for each display type.
|
|
// It depends on fix pin array, see var pins: ['clock', 'data', 'cs', 'dc', 'reset', 'busy']
|
|
const pinMap = new Map([
|
|
[0, [0,0,0,0,0,0]], //none
|
|
[1, [1,1,0,0,0,0]], //SSD1306_128X64
|
|
[2, [1,1,0,0,0,0]], //SH1106_128X64
|
|
[3, [1,1,1,1,0,0]], //PCD8544_84X48 /nokia5110
|
|
[4, [1,1,0,0,0,0]], //SSD1306_128X32
|
|
[5, [1,1,0,0,0,0]], //SSD1306_64X48
|
|
[6, [1,1,0,0,0,0]], //SSD1309_128x64
|
|
[10, [1,1,1,1,1,1]] //ePaper
|
|
])
|
|
for(var i = 0; i < pins.length; i++) {
|
|
var cl = document.getElementById("row_" + pins[i][1]).classList;
|
|
if(pinMap.get(dispType)[i]) {
|
|
cl.remove("hide");
|
|
}
|
|
else {
|
|
cl.add("hide");
|
|
}
|
|
}
|
|
|
|
const optionsMap = new Map([ // options: [Graph, Luminance, Screensaver]
|
|
[0, [0,0,0]], //none
|
|
[1, [1,1,1]], //SSD1306_128X64
|
|
[2, [1,1,1]], //SH1106_128X64
|
|
[3, [1,1,0]], //PCD8544_84X48 /nokia5110
|
|
[4, [0,1,1]], //SSD1306_128X32
|
|
[5, [0,1,1]], //SSD1306_64X48
|
|
[6, [1,1,1]], //SSD1309_128x64
|
|
[10, [0,0,0]] //ePaper
|
|
])
|
|
|
|
var screenSaver = document.getElementById("disp_screensaver").value;
|
|
setHide("graphOptions", !optionsMap.get(dispType)[0]);
|
|
setHide("luminanceOption", !optionsMap.get(dispType)[1]);
|
|
setHide("screenSaver", !optionsMap.get(dispType)[2]);
|
|
setHide("pirPin", !(optionsMap.get(dispType)[2] && (screenSaver==2))); // show pir pin only for motion screensaver
|
|
}
|
|
/*ENDIF_PLUGIN_DISPLAY*/
|
|
|
|
function tick() {
|
|
document.getElementById("date").innerHTML = toIsoDateStr((new Date((++ts) * 1000)));
|
|
}
|
|
|
|
/*IF_PLUGIN_ZEROEXPORT*/
|
|
|
|
function apiCbBattOnOff(obj) {
|
|
// var e = document.getElementById("battSwitch");
|
|
// e.value = "88";
|
|
// selDelAllOpt(e);
|
|
// if(obj["success"])
|
|
// e.appendChild(opt("-1", "{#NETWORK_SCANNING}"))
|
|
// else
|
|
// e.appendChild(opt("-1", "{#ERROR} " + obj["error"]));
|
|
}
|
|
|
|
function battOnOff() {
|
|
var obj = {cmd: "ze_batt_onff", token: "*"}
|
|
getAjax("/api/setup", apiCbBattOnOff, "POST", JSON.stringify(obj));
|
|
// setTimeout(function() {getAjax('/api/setup/networks', listNetworks)}, 5000);
|
|
}
|
|
|
|
function ZeroExportGroup_Modal(obj, ivObj) {
|
|
|
|
// Tab_General
|
|
var cbEnabled = ml("input", {name: "enabled", type: "checkbox"}, null);
|
|
cbEnabled.checked = (obj.enabled);
|
|
|
|
// Tab_Powermeter
|
|
|
|
// Tab_Inverter
|
|
maxInv = obj["max_inverters"];
|
|
|
|
var lines = [];
|
|
|
|
lines.push(ml("tr", {}, [
|
|
ml("th", {style: "width: 10%;"}, ml("input", {name: "invMax", id: "invMax", type: "hidden", value: maxInv}, null)),
|
|
ml("th", {style: "width: 10%;"}, "{#ZE_GROUP_TAB_INVERTER_ENABLED}"),
|
|
ml("th", {}, "{#ZE_GROUP_TAB_INVERTER_NAME}"),
|
|
ml("th", {style: "width: 15%;"}, "{#ZE_GROUP_TAB_INVERTER_POWERMIN}"),
|
|
ml("th", {style: "width: 15%;"}, "{#ZE_GROUP_TAB_INVERTER_POWERMAX}"),
|
|
ml("th", {style: "width: 5%;"}, "{#ZE_GROUP_TAB_INVERTER_TURNOFF}"),
|
|
]));
|
|
|
|
for(var inv = 0; inv < maxInv; inv++) {
|
|
lines.push(ml("tr", {}, [
|
|
ml("td", {}, String(inv)),
|
|
ml("td", {},
|
|
ml("div", {}, [
|
|
ml("input", {name: "invEnabled"+inv, class: "text", id: "invEnabled"+inv, type: "checkbox"}, null)
|
|
]),
|
|
),
|
|
ml("td", {},
|
|
ml("div", {}, [
|
|
ml("select", {name: "invId"+inv, class: "text", id: "invId"+inv}, null),
|
|
]),
|
|
),
|
|
ml("td", {},
|
|
ml("div", {}, [
|
|
ml("input", {name: "invPowerMin"+inv, class: "text", id: "invPowerMin"+inv, type: "number", min: "0", max: "65535"}, null)
|
|
]),
|
|
),
|
|
ml("td", {},
|
|
ml("div", {}, [
|
|
ml("input", {name: "invPowerMax"+inv, class: "text", id: "invPowerMax"+inv, type: "number", min: "0", max: "65535"}, null)
|
|
]),
|
|
),
|
|
ml("td", {},
|
|
ml("div", {}, [
|
|
ml("input", {name: "invTurnOff"+inv, class: "text", id: "invTurnOff"+inv, type: "checkbox"}, null)
|
|
]),
|
|
),
|
|
]));
|
|
}
|
|
|
|
// Tab_Battery
|
|
|
|
// Tab_Advanced
|
|
var cb_minimum = ml("input", {name: "minimum", type: "checkbox"}, null);
|
|
cb_minimum.checked = (obj.minimum);
|
|
|
|
// Tab
|
|
var html = ml("div", {}, [
|
|
tabs(["{#ZE_GROUP_TAB_GENERAL}", "{#ZE_GROUP_TAB_POWERMETER}", "{#ZE_GROUP_TAB_INVERTER}", "{#ZE_GROUP_TAB_BATTERY}", "{#ZE_GROUP_TAB_ADVANCED}"]),
|
|
// General
|
|
ml("div", {id: "div{#ZE_GROUP_TAB_GENERAL}", class: "tab-content"}, [
|
|
divRow("{#ZE_GROUP_TAB_GENERAL_GRUPPE}", String(obj.id)),
|
|
divRow("{#ZE_GROUP_TAB_GENERAL_ENABLE}", cbEnabled),
|
|
divRow("{#ZE_GROUP_TAB_GENERAL_NAME}", ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)),
|
|
// TODO: Uebersetzen mit lang.json und auf die entsprechende Dokuseite verlinken
|
|
divRow("Hinweis: ",
|
|
ml("a", {href: "https://docs.ahoydtu.de/de/latest/zeroExport.html"}, "Bitte beachten Sie die Ausfüllhinweise in der Dokumentation."),
|
|
),
|
|
// TODO: Hinweis Github/Discord - Entfernen wenn erledigt
|
|
divRow("ACHTUNG: ",
|
|
ml("a", {href: "https://discord.com/channels/984173303147155506/1211365440253726851"}, "Bitte auf Github keine Issues zu Zero eröffnen, sondern direkt im Discord melden."),
|
|
),
|
|
]),
|
|
// Powermeter
|
|
ml("div", {id: "div{#ZE_GROUP_TAB_POWERMETER}", class: "tab-content hide"}, [
|
|
divRow("{#ZE_GROUP_TAB_POWERMETER_TYPE}",
|
|
ml("select", {name: "pm_type", class: "text", id: "pm_type"}, null),
|
|
),
|
|
divRow("{#ZE_GROUP_TAB_POWERMETER_REFRESH}",
|
|
ml("input", {name: "pm_refresh", class: "text", type: "number", min: "1", max: "30", step: "1", value: obj.pm_refresh}, null),
|
|
),
|
|
// TODO: URL -> IP
|
|
divRow("{#ZE_GROUP_TAB_POWERMETER_TARGET}",
|
|
ml("select", {name: "pm_target", class: "text", id: "pm_target"}, null),
|
|
),
|
|
divRow("{#ZE_GROUP_TAB_POWERMETER_IP}", [
|
|
ml("input", {name: "pm_url", class: "text", type: "text", value: obj.pm_url, maxlength: "100"}, null),
|
|
]),
|
|
divRow("{#ZE_GROUP_TAB_POWERMETER_JSONPATH}", [
|
|
ml("input", {name: "pm_jsonPath", class: "text", type: "text", value: obj.pm_jsonPath}, null),
|
|
]),
|
|
divRow("{#ZE_GROUP_TAB_POWERMETER_USER}",
|
|
ml("input", {name: "pm_user", class: "text", type: "text", value: obj.pm_user }, null),
|
|
),
|
|
divRow("{#ZE_GROUP_TAB_POWERMETER_PASS}",
|
|
ml("input", {name: "pm_pass", class: "text", type: "password", value: "****"}, null),
|
|
),
|
|
divRow("{#ZE_GROUP_TAB_POWERMETER_TOPIC}",
|
|
ml("input", {id: 3, name: "pm_topic", class: "text", type: "text", value: ""}, null),
|
|
),
|
|
// TODO: Uebersetzen mit lang.json und auf die entsprechende Dokuseite verlinken
|
|
divRow("Hinweis: ",
|
|
ml("a", {href: "https://docs.ahoydtu.de/de/latest/zeroExport.html"}, "Bitte beachten Sie die Ausfüllhinweise in der Dokumentation."),
|
|
),
|
|
// TODO: Hinweis Github/Discord - Entfernen wenn erledigt
|
|
divRow("ACHTUNG: ",
|
|
ml("a", {href: "https://discord.com/channels/984173303147155506/1211365440253726851"}, "Bitte auf Github keine Issues zu Zero eröffnen, sondern direkt im Discord melden."),
|
|
),
|
|
]),
|
|
// Inverter
|
|
ml("div", {id: "div{#ZE_GROUP_TAB_INVERTER}", class: "tab-content hide"}, [
|
|
ml("table", {class: "table"}, ml("tbody", {}, lines)),
|
|
// TODO: Uebersetzen mit lang.json und auf die entsprechende Dokuseite verlinken
|
|
divRow("Hinweis: ",
|
|
ml("a", {href: "https://docs.ahoydtu.de/de/latest/zeroExport.html"}, "Bitte beachten Sie die Ausfüllhinweise in der Dokumentation."),
|
|
),
|
|
// TODO: Hinweis Github/Discord - Entfernen wenn erledigt
|
|
divRow("ACHTUNG: ",
|
|
ml("a", {href: "https://discord.com/channels/984173303147155506/1211365440253726851"}, "Bitte auf Github keine Issues zu Zero eröffnen, sondern direkt im Discord melden."),
|
|
),
|
|
]),
|
|
// Battery
|
|
ml("div", {id: "div{#ZE_GROUP_TAB_BATTERY}", class: "tab-content hide"}, [
|
|
divRow("{#ZE_GROUP_TAB_BATTERY_CFG}",
|
|
ml("select", {name: "battCfg", class: "text", id: "battCfg"}, null),
|
|
),
|
|
divRow("{#ZE_GROUP_TAB_BATTERY_TOPIC}",
|
|
ml("input", {name: "battTopic", class: "text", type: "text", value: obj.battTopic}, null),
|
|
),
|
|
divRow("{#ZE_GROUP_TAB_BATTERY_LIMITON}",
|
|
ml("input", {name: "battLimitOn", class: "text", type: "number", min: "0", max: "100", step: "0.1", value: obj.battLimitOn}, null),
|
|
),
|
|
divRow("{#ZE_GROUP_TAB_BATTERY_LIMITOFF}",
|
|
ml("input", {name: "battLimitOff", class: "text", type: "number", min: "0", max: "100", step: "0.1", value: obj.battLimitOff}, null),
|
|
),
|
|
divRow("{#ZE_GROUP_TAB_BATTERY_ONOFF}", ml("input", {name: "battSwitch", id: "battSwitch", class: "btn", type: "button", value: "{#BTN_ONOFF}", onclick: battOnOff()}, null)),
|
|
// TODO: Uebersetzen mit lang.json und auf die entsprechende Dokuseite verlinken
|
|
divRow("Hinweis: ",
|
|
ml("a", {href: "https://docs.ahoydtu.de/de/latest/zeroExport.html"}, "Bitte beachten Sie die Ausfüllhinweise in der Dokumentation."),
|
|
),
|
|
// TODO: Hinweis Github/Discord - Entfernen wenn erledigt
|
|
divRow("ACHTUNG: ",
|
|
ml("a", {href: "https://discord.com/channels/984173303147155506/1211365440253726851"}, "Bitte auf Github keine Issues zu Zero eröffnen, sondern direkt im Discord melden."),
|
|
),
|
|
]),
|
|
// Advanced
|
|
ml("div", {id: "div{#ZE_GROUP_TAB_ADVANCED}", class: "tab-content hide"}, [
|
|
divRow("{#ZE_GROUP_TAB_ADVANCED_SETPOINT}", ml("input", {name: "setPoint", class: "text", type: "number", min: "-32768", max: "32767", step: "1", value: obj.setPoint}, null)),
|
|
divRow("{#ZE_GROUP_TAB_ADVANCED_MINIMUM}", cb_minimum),
|
|
divRow("{#ZE_GROUP_TAB_ADVANCED_POWERTOLERANCE}", ml("input", {name: "powerTolerance", class: "text", type: "number", min: "0", max: "255", value: obj.powerTolerance}, null)),
|
|
divRow("{#ZE_GROUP_TAB_ADVANCED_POWERMAX}", ml("input", {name: "powerMax", class: "text", type: "number", min: "0", max: "65535", value: obj.powerMax}, null)),
|
|
divRow("{#ZE_GROUP_TAB_ADVANCED_KP}", ml("input", {name: "Kp", class: "text", type: "number", min: "-1", max: "0", step: "0.001", value: obj.Kp}, null)),
|
|
divRow("{#ZE_GROUP_TAB_ADVANCED_KI}", ml("input", {name: "Ki", class: "text", type: "number", min: "-0.01", max: "0", step: "0.001", value: obj.Ki}, null)),
|
|
divRow("{#ZE_GROUP_TAB_ADVANCED_KD}", ml("input", {name: "Kd", class: "text", type: "number", min: "-0.01", max: "0", step: "0.001", value: obj.Kd}, null)),
|
|
// TODO: Uebersetzen mit lang.json und auf die entsprechende Dokuseite verlinken
|
|
divRow("Hinweis: ",
|
|
ml("a", {href: "https://docs.ahoydtu.de/de/latest/zeroExport.html"}, "Bitte beachten Sie die Ausfüllhinweise in der Dokumentation."),
|
|
),
|
|
// TODO: Hinweis Github/Discord - Entfernen wenn erledigt
|
|
divRow("ACHTUNG: ",
|
|
ml("a", {href: "https://discord.com/channels/984173303147155506/1211365440253726851"}, "Bitte auf Github keine Issues zu Zero eröffnen, sondern direkt im Discord melden."),
|
|
),
|
|
]),
|
|
// Global
|
|
ml("div", {class: "row mt-5"}, [
|
|
ml("div", {class: "col-8", id: "res"}, ""),
|
|
ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "{#ZE_GROUP_EDIT_BTN_SAVE}", class: "btn", onclick: function() { save(); }}, null)),
|
|
])
|
|
]);
|
|
|
|
modal("{#ZE_GROUP_EDIT_MODAL}: " + obj.id, html);
|
|
// ser.dispatchEvent(new Event('change'));
|
|
|
|
// Tab_Powermeter
|
|
// - pm_type
|
|
// Inhalt fuer pm_type aus config laden und in eine Funktion ausgliedern
|
|
var e = document.getElementById("pm_type");
|
|
selDelAllOpt(e);
|
|
e.appendChild(opt("0", "---"));
|
|
e.appendChild(opt("1", "Shelly"));
|
|
//e.appendChild(opt("2", "Tasmota"));
|
|
e.appendChild(opt("3", "Mqtt"));
|
|
//e.appendChild(opt("4", "Hichi"));
|
|
e.appendChild(opt("5", "Tibber"));
|
|
e.appendChild(opt("6", "Shrdzm"));
|
|
for (var i = 0; i < e.options.length; i++) {
|
|
if (e.options[i].value == obj.pm_type) {
|
|
e.selectedIndex = i;
|
|
}
|
|
}
|
|
|
|
// - pm_target
|
|
var e = document.getElementById("pm_target");
|
|
selDelAllOpt(e);
|
|
e.appendChild(opt("0", "Sum"));
|
|
e.appendChild(opt("1", "L1"));
|
|
e.appendChild(opt("2", "L2"));
|
|
e.appendChild(opt("3", "L3"));
|
|
for (var i = 0; i < e.options.length; i++) {
|
|
if (e.options[i].value == obj.pm_target) {
|
|
e.selectedIndex = i;
|
|
}
|
|
}
|
|
|
|
// add addEventListener
|
|
const selectElement = document.querySelector("#pm_type");
|
|
//selectElement.addEventListener("change", (event) => { pm_type_dropdown() });
|
|
selectElement.addEventListener("change", (event) => { pm_type_dropdown() });
|
|
|
|
// run event one time
|
|
pm_type_dropdown();
|
|
|
|
// Tab_Inverters
|
|
// - Enabled
|
|
for (var inv = 0; inv < maxInv; inv++) {
|
|
var e = document.getElementById("invEnabled"+inv);
|
|
e.checked = (obj.inverters[inv].enabled);
|
|
}
|
|
// - InverterId
|
|
for (var inv = 0; inv < maxInv; inv++) {
|
|
var e = document.getElementById("invId"+inv);
|
|
selDelAllOpt(e);
|
|
e.appendChild(opt("-1", "---"));
|
|
for (var i = 0; i < ivObj.inverter.length; i++) {
|
|
e.appendChild(opt((ivObj.inverter[i].id), (ivObj.inverter[i].name)));
|
|
}
|
|
for (var i = 0; i < (e.length); i++) {
|
|
if (e.options[i].value == obj.inverters[inv].id) {
|
|
e.selectedIndex = i;
|
|
}
|
|
}
|
|
}
|
|
// - powerMin
|
|
for (var inv = 0; inv < maxInv; inv++) {
|
|
var e = document.getElementById("invPowerMin"+inv);
|
|
e.value = (obj.inverters[inv].powerMin);
|
|
}
|
|
// - powerMax
|
|
for (var inv = 0; inv < maxInv; inv++) {
|
|
var e = document.getElementById("invPowerMax"+inv);
|
|
e.value = (obj.inverters[inv].powerMax);
|
|
}
|
|
// - TurnOff
|
|
for (var inv = 0; inv < maxInv; inv++) {
|
|
var e = document.getElementById("invTurnOff"+inv);
|
|
e.checked = (obj.inverters[inv].turnOff);
|
|
}
|
|
|
|
// Tab_Battery
|
|
// battCfg
|
|
var e = document.getElementById("battCfg");
|
|
selDelAllOpt(e);
|
|
// TODO: uebersetzen?
|
|
e.appendChild(opt("0", "---"));
|
|
e.appendChild(opt("1", "Inverter U dc"));
|
|
e.appendChild(opt("2", "MQTT U"));
|
|
e.appendChild(opt("3", "MQTT Soc"));
|
|
for (var i = 0; i < e.options.length; i++) {
|
|
if (e.options[i].value == obj.battCfg) {
|
|
e.selectedIndex = i;
|
|
}
|
|
}
|
|
|
|
function pm_type_dropdown()
|
|
{
|
|
var e = document.getElementsByName("pm_type")[0];
|
|
var value = e.options[e.selectedIndex].text;
|
|
|
|
var divsToHide = document.getElementById("divPowermeter");
|
|
|
|
// Formular for Powermeter-DropDown
|
|
// show all DIVs and remove only what is not necessary
|
|
for(var i = 0; i < divsToHide.childElementCount; i++) divsToHide.childNodes[i].style.display = '';
|
|
|
|
if(value == "---") for(var i = 1; i < divsToHide.childElementCount; i++) divsToHide.childNodes[i].style.display = 'none';
|
|
else if(value == "Shelly") {
|
|
divsToHide.childNodes[7].style.display = 'none';
|
|
}
|
|
else if(value == "Mqtt") {
|
|
divsToHide.childNodes[3].style.display = 'none';
|
|
divsToHide.childNodes[4].style.display = 'none';
|
|
divsToHide.childNodes[5].style.display = 'none';
|
|
divsToHide.childNodes[6].style.display = 'none';
|
|
}
|
|
else if(value == "Tibber") {
|
|
divsToHide.childNodes[4].style.display = 'none';
|
|
divsToHide.childNodes[7].style.display = 'none';
|
|
}
|
|
}
|
|
|
|
function save() {
|
|
var o = new Object();
|
|
o.cmd = "ze_save_group"
|
|
// o.token = "*"
|
|
// General
|
|
o.id = obj.id
|
|
o.enabled = document.getElementsByName("enabled")[0].checked;
|
|
o.name = document.getElementsByName("name")[0].value;
|
|
|
|
// Powermeter
|
|
o.pm_refresh = document.getElementsByName("pm_refresh")[0].value;
|
|
var e = document.getElementsByName("pm_type")[0];
|
|
o.pm_type = e.options[e.selectedIndex].value;
|
|
o.pm_url = document.getElementsByName("pm_url")[0].value;
|
|
o.pm_jsonPath = document.getElementsByName("pm_jsonPath")[0].value;
|
|
o.pm_user = document.getElementsByName("pm_user")[0].value;
|
|
o.pm_pass = document.getElementsByName("pm_pass")[0].value;
|
|
var e = document.getElementsByName("pm_target")[0];
|
|
o.pm_target = e.options[e.selectedIndex].value;
|
|
// Inverters
|
|
o.invMax = document.getElementById("invMax").value;
|
|
o.inverters = [];
|
|
for(var inv = 0; inv < o.invMax; inv++) {
|
|
var q = new Object();
|
|
q.enabled = document.getElementById("invEnabled"+inv).checked;
|
|
var e = document.getElementById("invId"+inv);
|
|
q.id = e.options[e.selectedIndex].value;
|
|
q.powerMin = document.getElementById("invPowerMin"+inv).value;
|
|
q.powerMax = document.getElementById("invPowerMax"+inv).value;
|
|
q.turnOff = document.getElementById("invTurnOff"+inv).checked;
|
|
o.inverters.push(q);
|
|
}
|
|
// Battery
|
|
var e = document.getElementsByName("battCfg")[0];
|
|
o.battCfg = e.options[e.selectedIndex].value;
|
|
o.battTopic = document.getElementsByName("battTopic")[0].value;
|
|
o.battLimitOn = document.getElementsByName("battLimitOn")[0].value;
|
|
o.battLimitOff = document.getElementsByName("battLimitOff")[0].value;
|
|
// Advanced
|
|
o.setPoint = document.getElementsByName("setPoint")[0].value;
|
|
o.minimum = document.getElementsByName("minimum")[0].checked;
|
|
o.powerTolerance = document.getElementsByName("powerTolerance")[0].value;
|
|
o.powerMax = document.getElementsByName("powerMax")[0].value;
|
|
o.Kp = document.getElementsByName("Kp")[0].value;
|
|
o.Ki = document.getElementsByName("Ki")[0].value;
|
|
o.Kd = document.getElementsByName("Kd")[0].value;
|
|
// Global
|
|
getAjax("/api/setup", cb, "POST", JSON.stringify(o));
|
|
}
|
|
|
|
function cb(obj2) {
|
|
var e = document.getElementById("res");
|
|
if(!obj2.success)
|
|
e.innerHTML = "{#ERROR}" + obj2.error;
|
|
else {
|
|
modalClose();
|
|
getAjax("/api/setup", parse);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
function ZeroExportGroup_Del(obj) {
|
|
var html = ml("div", {class: "row"}, [
|
|
ml("div", {class: "col-9"}, "{#ZE_GROUP_DELETE_SURE} (" + obj.name + ")"),
|
|
ml("div", {class: "col-3 a-r"}, ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "{#ZE_GROUP_DELETE_BTN_YES}", class: "btn", onclick: function() { del(); }}, null)))
|
|
]);
|
|
modal("{#ZE_GROUP_DELETE_MODAL}: " + obj.name, html);
|
|
|
|
function del() {
|
|
// TODO: Es waere gut, wenn die Defaultwerte nicht hier sondern wie in der settings.h gesetzt wuerden.
|
|
var o = new Object();
|
|
o.cmd = "ze_save_group";
|
|
// General
|
|
o.id = obj.id;
|
|
o.enabled = false;
|
|
o.name = "";
|
|
// Powermeter
|
|
o.pm_refresh = 5;
|
|
o.pm_type = 0;
|
|
o.pm_url = "";
|
|
o.pm_jsonPath = "";
|
|
o.pm_user = "";
|
|
o.pm_pass = "";
|
|
o.pm_target = 0;
|
|
// Inverters
|
|
o.invMax = obj.inverters.length;
|
|
o.inverters = [];
|
|
for(var inv = 0; inv < o.invMax; inv++) {
|
|
var q = new Object();
|
|
q.enabled = false;
|
|
var e = document.getElementById("invId"+inv);
|
|
q.id = -1;
|
|
q.powerMin = 0;
|
|
q.powerMax = 0;
|
|
q.turnOff = false;
|
|
o.inverters.push(q);
|
|
}
|
|
// Battery
|
|
o.battCfg = 0;
|
|
o.battTopic = "";
|
|
o.battLimitOn = 0;
|
|
o.battLimitOff = 0;
|
|
// Advanced
|
|
o.setPoint = 0;
|
|
o.minimum = true;
|
|
o.power = 0;
|
|
o.powerTolerance = 10;
|
|
o.powerMax = 600;
|
|
o.Kp = -1;
|
|
o.Ki = 0;
|
|
o.Kd = 0;
|
|
// Global
|
|
getAjax("/api/setup", cb, "POST", JSON.stringify(o));
|
|
}
|
|
|
|
function cb(obj) {
|
|
if(obj.success) {
|
|
modalClose();
|
|
getAjax("/api/setup", parse);
|
|
}
|
|
}
|
|
|
|
}
|
|
/*ENDIF_PLUGIN_ZEROEXPORT*/
|
|
|
|
function parseZeroExport(obj, type) {
|
|
|
|
/*IF_PLUGIN_ZEROEXPORT*/
|
|
|
|
// enabled
|
|
document.getElementsByName("ze_enabled")[0].checked = obj["enabled"];
|
|
|
|
// log_over_webserial
|
|
document.getElementsByName("ze_log_over_webserial")[0].checked = obj["log_over_webserial"];
|
|
|
|
// log_over_mqtt
|
|
document.getElementsByName("ze_log_over_mqtt")[0].checked = obj["log_over_mqtt"];
|
|
|
|
// debug
|
|
document.getElementsByName("ze_debug")[0].checked = obj["debug"];
|
|
|
|
// groups
|
|
maxGroups = obj["max_groups"];
|
|
|
|
var lines = [];
|
|
|
|
lines.push(ml("tr", {}, [
|
|
ml("th", {style: "width: 10%; text-align: center;"}, "{#ZE_GROUP_ENABLED}"),
|
|
ml("th", {style: "width: 10%; text-align: center;"}, "{#ZE_GROUP_ID}"),
|
|
ml("th", {style: "text-align: center;"}, "{#ZE_GROUP_NAME}"),
|
|
ml("th", {style: "width: 10%; text-align: center;"}, "{#ZE_GROUP_POWERTOTAL}"),
|
|
ml("th", {style: "width: 10%; text-align: center;"}, "{#ZE_GROUP_EDIT}"),
|
|
ml("th", {style: "width: 10%; text-align: center;"}, "{#ZE_GROUP_DELETE}")
|
|
]));
|
|
|
|
for(let group = 0; group < obj.groups.length; group++) {
|
|
lines.push(ml("tr", {}, [
|
|
ml("td", {style: "text-align: left;", }, badge(obj.groups[group].enabled, (obj.groups[group].enabled) ? "{#ENABLED}" : "{#DISABLED}")),
|
|
ml("td", {style: "text-align: center;", }, String(obj.groups[group].id)),
|
|
ml("td", {style: "text-align: left;", }, String(obj.groups[group].name)),
|
|
// ml("td", {style: "text-align: right;", id: "groupPowerTotal"+group}, "n/a"),
|
|
ml("td", {style: "text-align: right;", id: "groupPower"+group}, String(obj.groups[group].power)),
|
|
ml("td", {style: "text-align: center;", onclick: function() {
|
|
function zeroGetIvList(ivObj) {
|
|
ZeroExportGroup_Modal(obj.groups[group], ivObj)
|
|
}
|
|
getAjax("/api/inverter/list", zeroGetIvList)
|
|
}}, svg(iconGear, 25, 25, "icon icon-fg pointer")),
|
|
ml("td", {style: "text-align: center;", onclick: function() {ZeroExportGroup_Del(obj.groups[group]);}}, svg(iconDel, 25, 25, "icon icon-fg pointer"))
|
|
]));
|
|
}
|
|
|
|
// TODO: Das Add sollte anders / ueberhaupt geloest werden
|
|
var add = new Object();
|
|
add.enabled = true;
|
|
add.id = obj.groups.length;
|
|
add.name = "";
|
|
// add.ch_max_pwr = [400,400,400,400,400,400];
|
|
// add.ch_name = [];
|
|
// add.ch_yield_cor = [];
|
|
// add.freq = 12;
|
|
// add.pa = 30;
|
|
|
|
var e = document.getElementById("ze_groups");
|
|
e.innerHTML = ""; // remove all childs
|
|
e.append(ml("table", {class: "table"}, ml("tbody", {}, lines)));
|
|
// TODO: Hinweis Developmentversion - Entfernen wenn erledigt
|
|
e.append(
|
|
divRow("ACHTUNG:", "Dies ist eine sehr junge Developmentversion, bitte nicht unbeaufsichtig laufen lassen."),
|
|
);
|
|
// TODO: Uebersetzen mit lang.json und auf die entsprechende Dokuseite verlinken
|
|
e.append(
|
|
divRow("Hinweis: ",
|
|
ml("a", {href: "https://docs.ahoydtu.de/de/latest/zeroExport.html"}, "Bitte beachten Sie die Ausfüllhinweise in der Dokumentation."),
|
|
),
|
|
);
|
|
// TODO: Hinweis Github/Discord - Entfernen wenn erledigt
|
|
e.append(
|
|
divRow("ACHTUNG: ",
|
|
ml("a", {href: "https://discord.com/channels/984173303147155506/1211365440253726851"}, "Bitte auf Github keine Issues zu Zero eröffnen, sondern direkt im Discord melden."),
|
|
),
|
|
);
|
|
if(maxGroups > obj.groups.length) {
|
|
e.append(ml("div", {class: "row my-3"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", value: "{#BTN_INV_ADD}", class: "btn", onclick: function() { ZeroExportGroup_Modal(add); }}, null))));
|
|
}
|
|
|
|
/*ELSE*/
|
|
var e = document.getElementById("zeroExport_button");
|
|
e.textContent += " (only for ESP32-S3 available)";
|
|
e.disabled = true;
|
|
element.classList.add("disabled");
|
|
/*ENDIF_PLUGIN_ZEROEXPORT*/
|
|
}
|
|
|
|
function parse(root) {
|
|
if(null != root) {
|
|
parseGeneric(root["generic"]);
|
|
parseSys(root["system"]);
|
|
parseStaticIp(root["static_ip"]);
|
|
parseMqtt(root["mqtt"]);
|
|
parseNtp(root["ntp"]);
|
|
parseSun(root["sun"]);
|
|
parsePinout(root.pinout);
|
|
parseNrfRadio(root["radioNrf"], root["pinout"]);
|
|
|
|
/*IF_ESP32*/
|
|
parseCmtRadio(root.radioCmt);
|
|
/*ENDIF_ESP32*/
|
|
/*IF_ETHERNET*/
|
|
parseEth(root.eth)
|
|
/*ENDIF_ETHERNET*/
|
|
parseSerial(root["serial"]);
|
|
/*IF_PLUGIN_DISPLAY*/
|
|
parseDisplay(root["display"], root["system"]["esp_type"], root["system"]);
|
|
/*ENDIF_PLUGIN_DISPLAY*/
|
|
parseZeroExport(root["zeroExport"], root["system"]["esp_type"]);
|
|
|
|
getAjax("/api/inverter/list", parseIv);
|
|
}
|
|
}
|
|
|
|
function listNetworks(root) {
|
|
var s = document.getElementById("networks");
|
|
selDelAllOpt(s);
|
|
if(root["networks"].length > 0) {
|
|
s.appendChild(opt("-1", "{#NETWORK_PLEASE_SELECT}"));
|
|
for(i = 0; i < root["networks"].length; i++) {
|
|
s.appendChild(opt(root["networks"][i]["ssid"], root["networks"][i]["ssid"] + " (" + root["networks"][i]["rssi"] + " dBm)"));
|
|
}
|
|
} else
|
|
s.appendChild(opt("-1", "{#NO_NETWORK_FOUND}"));
|
|
}
|
|
|
|
getAjax("/api/setup", parse);
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|