ESP8266 v0.4.16

* request only one inverter per loop (https://github.com/grindylow/ahoy/issues/53#issuecomment-1147042489)
* mqtt loop interval calculated by # of inverters and inverter request interval
* limit maximum number of retries
* added feature request #62 (readable names for channels)
* improved setup page, added javascript to hide / show channel fields

** IMORTANT: memory layout change, all configuration will be lost, except WiFI **
This commit is contained in:
lumapu 2022-06-09 23:03:38 +02:00
parent b995cc0a93
commit f148c41a1f
13 changed files with 260 additions and 117 deletions

View file

@ -1,4 +1,4 @@
#ifndef __SETUP_HTML_H__
#define __SETUP_HTML_H__
const char setup_html[] PROGMEM = "<!doctype html><html><head><title>Setup - {DEVICE}</title><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head><body><h1>Setup</h1><div id=\"setup\" class=\"content\"><div id=\"content\"><p>Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information. </p><form method=\"post\" action=\"{IP}/save\"><p class=\"des\">WiFi</p><label for=\"ssid\">SSID</label><input type=\"text\" class=\"text\" name=\"ssid\" value=\"{SSID}\"/><label for=\"pwd\">Password</label><input type=\"password\" class=\"text\" name=\"pwd\" value=\"{PWD}\"/><p class=\"des\">Device Host Name</p><label for=\"device\">Device Name</label><input type=\"text\" class=\"text\" name=\"device\" value=\"{DEVICE}\"/><a class=\"erase\" href=\"/erase\">ERASE SETTINGS (not WiFi)</a><p class=\"des\">Inverter</p>{INVERTERS}<br/><p class=\"subdes\">General</p><label for=\"invInterval\">Interval (s)</label><input type=\"text\" class=\"text\" name=\"invInterval\" value=\"{INV_INTVL}\"/><p class=\"des\">Pinout (Wemos)</p>{PINOUT}<p class=\"des\">Radio (NRF24L01+)</p><label for=\"rf24Power\">Amplifier Power Level</label><select name=\"rf24Power\">{RF24}</select><p class=\"des\">MQTT</p><label for=\"mqttAddr\">Broker / Server IP</label><input type=\"text\" class=\"text\" name=\"mqttAddr\" value=\"{MQTT_ADDR}\"/><label for=\"mqttPort\">Port</label><input type=\"text\" class=\"text\" name=\"mqttPort\" value=\"{MQTT_PORT}\"/><label for=\"mqttUser\">Username (optional)</label><input type=\"text\" class=\"text\" name=\"mqttUser\" value=\"{MQTT_USER}\"/><label for=\"mqttPwd\">Password (optional)</label><input type=\"text\" class=\"text\" name=\"mqttPwd\" value=\"{MQTT_PWD}\"/><label for=\"mqttTopic\">Topic</label><input type=\"text\" class=\"text\" name=\"mqttTopic\" value=\"{MQTT_TOPIC}\"/><label for=\"mqttIntvl\">Interval (s)</label><input type=\"text\" class=\"text\" name=\"mqttIntvl\" value=\"{MQTT_INTVL}\"/><p class=\"des\">Serial Console</p><label for=\"serEn\">print inverter data</label><input type=\"checkbox\" class=\"cb\" name=\"serEn\" {SER_VAL_CB}/><br/><label for=\"serDbg\">print RF24 debug</label><input type=\"checkbox\" class=\"cb\" name=\"serDbg\" {SER_DBG_CB}/><br/><label for=\"serIntvl\">Interval (s)</label><input type=\"text\" class=\"text\" name=\"serIntvl\" value=\"{SER_INTVL}\"/><p class=\"des\">&nbsp;</p><label for=\"reboot\">Reboot device after successful save</label><input type=\"checkbox\" class=\"cb\" name=\"reboot\"/><input type=\"submit\" value=\"save\" class=\"btn\" /></form></div></div><div id=\"footer\"><p class=\"left\"><a href=\"{IP}/\">Home</a></p><p class=\"left\"><a href=\"{IP}/update\">Update Firmware</a></p><p class=\"right\">AHOY - {VERSION}</p><p class=\"right\"><a href=\"{IP}/factory\">Factory Reset</a></p><p class=\"right\"><a href=\"{IP}/reboot\">Reboot</a></p></div></body></html>";
const char setup_html[] PROGMEM = "<!doctype html><html><head><title>Setup - {DEVICE}</title><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><script type=\"text/javascript\">function toggle(name, hide) {var elm = document.getElementsByName(name)[0];if(hide) {if(!elm.classList.contains(\"hide\")) elm.classList.add(\"hide\");}else elm.classList.remove('hide');}function load() {document.querySelectorAll('input[name^=\"inv\"][name$=\"Addr\"]').forEach(elm =>{elm.addEventListener(\"keyup\", (e) =>{serial = elm.value.substring(0,4);iv = elm.name.substring(3,4);max = 0;for(i=0;i<4;i++) {toggle(\"inv\"+iv+\"ModPwr\"+i, true);toggle(\"inv\"+iv+\"ModName\"+i, true);}toggle(\"lbl\"+iv+\"ModPwr\", true);toggle(\"lbl\"+iv+\"ModName\", true);if(serial == \"1161\") max = 4;else if(serial == \"1141\") max = 2;else if(serial == \"1121\") max = 1;for(i=0;i<max;i++) {toggle(\"inv\"+iv+\"ModPwr\"+i, false);toggle(\"inv\"+iv+\"ModName\"+i, false);}if(max != 0) {toggle(\"lbl\"+iv+\"ModPwr\", false);toggle(\"lbl\"+iv+\"ModName\", false);}});evt = document.createEvent(\"HTMLEvents\");evt.initEvent(\"keyup\", false, true);elm.dispatchEvent(evt);});}</script></head><body onload=\"load()\"><h1>Setup</h1><div id=\"setup\" class=\"content\"><div id=\"content\"><p>Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information. </p><form method=\"post\" action=\"{IP}/save\"><p class=\"des\">WiFi</p><label for=\"ssid\">SSID</label><input type=\"text\" class=\"text\" name=\"ssid\" value=\"{SSID}\"/><label for=\"pwd\">Password</label><input type=\"password\" class=\"text\" name=\"pwd\" value=\"{PWD}\"/><p class=\"des\">Device Host Name</p><label for=\"device\">Device Name</label><input type=\"text\" class=\"text\" name=\"device\" value=\"{DEVICE}\"/><a class=\"erase\" href=\"/erase\">ERASE SETTINGS (not WiFi)</a><p class=\"des\">Inverter</p>{INVERTERS}<br/><p class=\"subdes\">General</p><label for=\"invInterval\">Interval [s]</label><input type=\"text\" class=\"text\" name=\"invInterval\" value=\"{INV_INTVL}\"/><label for=\"invRetry\">Max retries per Payload</label><input type=\"text\" class=\"text\" name=\"invRetry\" value=\"{INV_RETRIES}\"/><p class=\"des\">Pinout (Wemos)</p>{PINOUT}<p class=\"des\">Radio (NRF24L01+)</p><label for=\"rf24Power\">Amplifier Power Level</label><select name=\"rf24Power\">{RF24}</select><p class=\"des\">MQTT</p><label for=\"mqttAddr\">Broker / Server IP</label><input type=\"text\" class=\"text\" name=\"mqttAddr\" value=\"{MQTT_ADDR}\"/><label for=\"mqttPort\">Port</label><input type=\"text\" class=\"text\" name=\"mqttPort\" value=\"{MQTT_PORT}\"/><label for=\"mqttUser\">Username (optional)</label><input type=\"text\" class=\"text\" name=\"mqttUser\" value=\"{MQTT_USER}\"/><label for=\"mqttPwd\">Password (optional)</label><input type=\"text\" class=\"text\" name=\"mqttPwd\" value=\"{MQTT_PWD}\"/><label for=\"mqttTopic\">Topic</label><input type=\"text\" class=\"text\" name=\"mqttTopic\" value=\"{MQTT_TOPIC}\"/><label for=\"mqttIntvl\">Interval [s] (read-only)</label><input type=\"text\" class=\"text\" name=\"mqttIntvl\" value=\"{MQTT_INTVL}\" readonly/><p class=\"des\">Serial Console</p><label for=\"serEn\">print inverter data</label><input type=\"checkbox\" class=\"cb\" name=\"serEn\" {SER_VAL_CB}/><br/><label for=\"serDbg\">print RF24 debug</label><input type=\"checkbox\" class=\"cb\" name=\"serDbg\" {SER_DBG_CB}/><br/><label for=\"serIntvl\">Interval [s]</label><input type=\"text\" class=\"text\" name=\"serIntvl\" value=\"{SER_INTVL}\"/><p class=\"des\">&nbsp;</p><label for=\"reboot\">Reboot device after successful save</label><input type=\"checkbox\" class=\"cb\" name=\"reboot\" checked/><input type=\"submit\" value=\"save\" class=\"btn\" /></form></div></div><div id=\"footer\"><p class=\"left\"><a href=\"{IP}/\">Home</a></p><p class=\"left\"><a href=\"{IP}/update\">Update Firmware</a></p><p class=\"right\">AHOY - {VERSION}</p><p class=\"right\"><a href=\"{IP}/factory\">Factory Reset</a></p><p class=\"right\"><a href=\"{IP}/reboot\">Reboot</a></p></div></body></html>";
#endif /*__SETUP_HTML_H__*/

View file

@ -1,4 +1,4 @@
#ifndef __STYLE_CSS_H__
#define __STYLE_CSS_H__
const char style_css[] PROGMEM = "h1 {margin:0;padding:20pt;font-size:22pt;color:#fff;background-color:#006ec0;display:block;text-transform:uppercase;}html, body {font-family:Arial;margin:0;padding:0;}p {text-align:justify;font-size:13pt;}.des {margin-top:35px;font-size:13pt;color:#006ec0;}.subdes {font-size:12pt;color:#006ec0;margin-left:7px;}a:link, a:visited {text-decoration:none;font-size:13pt;color:#006ec0;}a:hover, a:focus {color:#f00;}a.erase {background-color:#006ec0;color:#fff;padding:7px;display:inline-block;margin-top:30px;float:right;}#content {padding:15px 15px 60px 15px;}#footer {position:fixed;bottom:0px;height:45px;background-color:#006ec0;width:100%;border-top:5px solid #fff;}#footer p, #footer a {color:#fff;padding:0 7px 0 7px;font-size:10pt !important;}div.content {background-color:#fff;padding-bottom:65px;overflow:auto;}input, select {padding:7px;font-size:13pt;}input.text, select {width:70%;box-sizing:border-box;margin-bottom:10px;border:1px solid #ccc;}input.sh {max-width:100px !important;margin-right:10px;}input.btn {background-color:#006ec0;color:#fff;border:0px;float:right;margin:10px 0 30px;text-transform:uppercase;}input.cb {margin-bottom:20px;}label {width:20%;display:inline-block;font-size:12pt;padding-right:10px;margin-left:10px;}.left {float:left;}.right {float:right;}div.ch-iv {width:100%;background-color:#32b004;display:inline-block;margin-bottom:15px;padding-bottom:20px;overflow:auto;}div.ch {width:220px;min-height:350px;background-color:#006ec0;display:inline-block;margin:0 10px 15px 10px;overflow:auto;padding-bottom:20px;}div.ch .value, div.ch .info, div.ch .head, div.ch-iv .value, div.ch-iv .info, div.ch-iv .head {color:#fff;display:block;width:100%;text-align:center;}.subgrp {float:left;width:220px;}div.ch .unit, div.ch-iv .unit {font-size:19px;margin-left:10px;}div.ch .value, div.ch-iv .value {margin-top:20px;font-size:24px;}div.ch .info, div.ch-iv .info {margin-top:3px;font-size:10px;}div.ch .head {background-color:#003c80;padding:10px 0 10px 0;}div.ch-iv .head {background-color:#1c6800;padding:10px 0 10px 0;}div.iv {max-width:960px;margin-bottom:40px;}div.ts {font-size:13px;background-color:#ddd;border-top:7px solid #999;padding:7px;}#note {margin:50px 10px 10px 10px;padding-top:10px;width:100%;border-top:1px solid #bbb;}@media(max-width:500px) {div.ch .unit, div.ch-iv .unit {font-size:18px;}div.ch {width:170px;min-height:100px;}.subgrp {width:180px;}}";
const char style_css[] PROGMEM = "h1 {margin:0;padding:20pt;font-size:22pt;color:#fff;background-color:#006ec0;display:block;text-transform:uppercase;}html, body {font-family:Arial;margin:0;padding:0;}p {text-align:justify;font-size:13pt;}.des {margin-top:35px;font-size:13pt;color:#006ec0;}.subdes {font-size:12pt;color:#006ec0;margin-left:7px;}.subsubdes {font-size:12pt;color:#006ec0;margin:0 0 7px 12px;}.hide {display:none;}a:link, a:visited {text-decoration:none;font-size:13pt;color:#006ec0;}a:hover, a:focus {color:#f00;}a.erase {background-color:#006ec0;color:#fff;padding:7px;display:inline-block;margin-top:30px;float:right;}#content {padding:15px 15px 60px 15px;}#footer {position:fixed;bottom:0px;height:45px;background-color:#006ec0;width:100%;border-top:5px solid #fff;}#footer p, #footer a {color:#fff;padding:0 7px 0 7px;font-size:10pt !important;}div.content {background-color:#fff;padding-bottom:65px;overflow:auto;}input, select {padding:7px;font-size:13pt;}input.text, select {width:70%;box-sizing:border-box;margin-bottom:10px;border:1px solid #ccc;}input.sh {max-width:150px !important;margin-right:10px;}input.btn {background-color:#006ec0;color:#fff;border:0px;float:right;margin:10px 0 30px;text-transform:uppercase;}input.cb {margin-bottom:20px;}label {width:20%;display:inline-block;font-size:12pt;padding-right:10px;margin-left:15px;}.left {float:left;}.right {float:right;}div.ch-iv {width:100%;background-color:#32b004;display:inline-block;margin-bottom:15px;padding-bottom:20px;overflow:auto;}div.ch {width:220px;min-height:350px;background-color:#006ec0;display:inline-block;margin:0 10px 15px 10px;overflow:auto;padding-bottom:20px;}div.ch .value, div.ch .info, div.ch .head, div.ch-iv .value, div.ch-iv .info, div.ch-iv .head {color:#fff;display:block;width:100%;text-align:center;}.subgrp {float:left;width:220px;}div.ch .unit, div.ch-iv .unit {font-size:19px;margin-left:10px;}div.ch .value, div.ch-iv .value {margin-top:20px;font-size:24px;}div.ch .info, div.ch-iv .info {margin-top:3px;font-size:10px;}div.ch .head {background-color:#003c80;padding:10px 0 10px 0;}div.ch-iv .head {background-color:#1c6800;padding:10px 0 10px 0;}div.iv {max-width:960px;margin-bottom:40px;}div.ts {font-size:13px;background-color:#ddd;border-top:7px solid #999;padding:7px;}#note {margin:50px 10px 10px 10px;padding-top:10px;width:100%;border-top:1px solid #bbb;}@media(max-width:500px) {div.ch .unit, div.ch-iv .unit {font-size:18px;}div.ch {width:170px;min-height:100px;}.subgrp {width:180px;}}";
#endif /*__STYLE_CSS_H__*/

View file

@ -4,8 +4,51 @@
<title>Setup - {DEVICE}</title>
<link rel="stylesheet" type="text/css" href="style.css"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript">
function toggle(name, hide) {
var elm = document.getElementsByName(name)[0];
if(hide) {
if(!elm.classList.contains("hide"))
elm.classList.add("hide");
}
else
elm.classList.remove('hide');
}
function load() {
document.querySelectorAll('input[name^="inv"][name$="Addr"]').forEach(elm => {
elm.addEventListener("keyup", (e) => {
serial = elm.value.substring(0,4);
iv = elm.name.substring(3,4);
max = 0;
for(i=0;i<4;i++) {
toggle("inv"+iv+"ModPwr"+i, true);
toggle("inv"+iv+"ModName"+i, true);
}
toggle("lbl"+iv+"ModPwr", true);
toggle("lbl"+iv+"ModName", true);
if(serial == "1161") max = 4;
else if(serial == "1141") max = 2;
else if(serial == "1121") max = 1;
for(i=0;i<max;i++) {
toggle("inv"+iv+"ModPwr"+i, false);
toggle("inv"+iv+"ModName"+i, false);
}
if(max != 0) {
toggle("lbl"+iv+"ModPwr", false);
toggle("lbl"+iv+"ModName", false);
}
});
evt = document.createEvent("HTMLEvents");
evt.initEvent("keyup", false, true);
elm.dispatchEvent(evt);
});
}
</script>
</head>
<body>
<body onload="load()">
<h1>Setup</h1>
<div id="setup" class="content">
<div id="content">
@ -28,8 +71,10 @@
<p class="des">Inverter</p>
{INVERTERS}<br/>
<p class="subdes">General</p>
<label for="invInterval">Interval (s)</label>
<label for="invInterval">Interval [s]</label>
<input type="text" class="text" name="invInterval" value="{INV_INTVL}"/>
<label for="invRetry">Max retries per Payload</label>
<input type="text" class="text" name="invRetry" value="{INV_RETRIES}"/>
<p class="des">Pinout (Wemos)</p>
{PINOUT}
@ -49,20 +94,20 @@
<input type="text" class="text" name="mqttPwd" value="{MQTT_PWD}"/>
<label for="mqttTopic">Topic</label>
<input type="text" class="text" name="mqttTopic" value="{MQTT_TOPIC}"/>
<label for="mqttIntvl">Interval (s)</label>
<input type="text" class="text" name="mqttIntvl" value="{MQTT_INTVL}"/>
<label for="mqttIntvl">Interval [s] (read-only)</label>
<input type="text" class="text" name="mqttIntvl" value="{MQTT_INTVL}" readonly/>
<p class="des">Serial Console</p>
<label for="serEn">print inverter data</label>
<input type="checkbox" class="cb" name="serEn" {SER_VAL_CB}/><br/>
<label for="serDbg">print RF24 debug</label>
<input type="checkbox" class="cb" name="serDbg" {SER_DBG_CB}/><br/>
<label for="serIntvl">Interval (s)</label>
<label for="serIntvl">Interval [s]</label>
<input type="text" class="text" name="serIntvl" value="{SER_INTVL}"/>
<p class="des">&nbsp;</p>
<label for="reboot">Reboot device after successful save</label>
<input type="checkbox" class="cb" name="reboot"/>
<input type="checkbox" class="cb" name="reboot" checked/>
<input type="submit" value="save" class="btn" />
</form>
</div>

View file

@ -31,6 +31,15 @@ p {
margin-left: 7px;
}
.subsubdes {
font-size:12pt;
color:#006ec0;
margin: 0 0 7px 12px;
}
.hide {
display: none;
}
a:link, a:visited {
text-decoration: none;
@ -89,7 +98,7 @@ input.text, select {
}
input.sh {
max-width: 100px !important;
max-width: 150px !important;
margin-right: 10px;
}
@ -111,7 +120,7 @@ label {
display: inline-block;
font-size: 12pt;
padding-right: 10px;
margin-left: 10px;
margin-left: 15px;
}
.left {