Display multiple meters in tabbed interface

This commit is contained in:
2026-07-04 20:35:28 +02:00
parent c55eea0e14
commit 547f9a42b4
+21 -1
View File
@@ -432,6 +432,15 @@ static void handleRoot() {
if (!requireAuth()) { Serial.println("[HTTP] GET / -> 401"); return; } if (!requireAuth()) { Serial.println("[HTTP] GET / -> 401"); return; }
Serial.println("[HTTP] GET /"); Serial.println("[HTTP] GET /");
String meterRows; String meterRows;
bool useTabs = meterCount > 1;
if (useTabs) {
meterRows += "<div class=tabs><div class=tab-nav>";
for (int i = 0; i < meterCount; i++) {
String label = strlen(meters[i].name) > 0 ? escHtml(meters[i].name) : "Meter " + String(i);
meterRows += "<button class=tab-btn" + String(i == 0 ? " active" : "") + " data-tab=" + String(i) + ">" + label + "</button>";
}
meterRows += "</div>";
}
for (int i = 0; i < meterCount; i++) { for (int i = 0; i < meterCount; i++) {
char maxStr[8], curStr[8]; char maxStr[8], curStr[8];
dtostrf(meters[i].maxDuty, 1, 1, maxStr); dtostrf(meters[i].maxDuty, 1, 1, maxStr);
@@ -443,7 +452,9 @@ static void handleRoot() {
dtostrf(meters[i].rangeMin, 1, 1, rMinStr); dtostrf(meters[i].rangeMin, 1, 1, rMinStr);
dtostrf(meters[i].rangeMax, 1, 1, rMaxStr); dtostrf(meters[i].rangeMax, 1, 1, rMaxStr);
meterRows += "<fieldset><legend>Meter " + String(i) + "</legend>"; if (useTabs) meterRows += "<div class=tab-panel" + String(i == 0 ? " active" : "") + " data-tab=" + String(i) + ">";
meterRows += "<fieldset>";
if (!useTabs) meterRows += "<legend>Meter " + String(i) + "</legend>";
meterRows += "<div class=row><label>Pin</label><input name=m" + String(i) + "_pin type=number min=0 max=99 value=" + String(meters[i].pin) + "></div>"; meterRows += "<div class=row><label>Pin</label><input name=m" + String(i) + "_pin type=number min=0 max=99 value=" + String(meters[i].pin) + "></div>";
meterRows += "<div class=row><label>Name</label><input name=m" + String(i) + "_name value='" + nameVal + "'></div>"; meterRows += "<div class=row><label>Name</label><input name=m" + String(i) + "_name value='" + nameVal + "'></div>";
meterRows += "<div class=row><label>Unit</label><input name=m" + String(i) + "_unit value='" + unitVal + "'></div>"; meterRows += "<div class=row><label>Unit</label><input name=m" + String(i) + "_unit value='" + unitVal + "'></div>";
@@ -455,7 +466,9 @@ static void handleRoot() {
meterRows += "<input name=m" + String(i) + "_cur type=range min=0 max=100 step=0.1 value=" + String(curStr) + ">"; meterRows += "<input name=m" + String(i) + "_cur type=range min=0 max=100 step=0.1 value=" + String(curStr) + ">";
meterRows += "<span class=val id=m" + String(i) + ">" + String(curStr) + "%</span>"; meterRows += "<span class=val id=m" + String(i) + ">" + String(curStr) + "%</span>";
meterRows += "</div></fieldset>"; meterRows += "</div></fieldset>";
if (useTabs) meterRows += "</div>";
} }
if (useTabs) meterRows += "</div>";
String countOpts; String countOpts;
for (int i = 1; i <= MAX_METERS; i++) { for (int i = 1; i <= MAX_METERS; i++) {
@@ -537,6 +550,10 @@ html += ".tgl-lbl{margin-bottom:0!important;line-height:18px}.switch{position:re
html += ".switch input{opacity:0;width:0;height:0}.slid{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background:#ccc;border-radius:18px;transition:.3s}"; html += ".switch input{opacity:0;width:0;height:0}.slid{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background:#ccc;border-radius:18px;transition:.3s}";
html += ".slid::before{content:\"\";position:absolute;height:14px;width:14px;left:2px;top:2px;background:#fff;border-radius:50%;transition:.3s;box-shadow:0 1px 3px rgba(0,0,0,.2)}"; html += ".slid::before{content:\"\";position:absolute;height:14px;width:14px;left:2px;top:2px;background:#fff;border-radius:50%;transition:.3s;box-shadow:0 1px 3px rgba(0,0,0,.2)}";
html += ".switch input:checked+.slid{background:#4361ee}.switch input:checked+.slid::before{transform:translateX(14px)}"; html += ".switch input:checked+.slid{background:#4361ee}.switch input:checked+.slid::before{transform:translateX(14px)}";
html += ".tab-nav{display:flex;gap:4px;margin-bottom:16px;flex-wrap:wrap}";
html += ".tab-btn{padding:8px 16px;border:1px solid #d1d5db;background:#f8f9fc;border-radius:8px 8px 0 0;cursor:pointer;font-size:13px;font-weight:600;color:#666;transition:all .2s;font-family:inherit}";
html += ".tab-btn:hover{background:#e8eaf0}.tab-btn.active{background:#fff;border-color:#4361ee;color:#4361ee;border-bottom-color:#fff}";
html += ".tab-panel{display:none}.tab-panel.active{display:block}";
html += "</style></head><body><div class=card>"; html += "</style></head><body><div class=card>";
html += "<div class=hdr><img src=/logo.png alt=logo><div><h1>M1730</h1><div class=sub>Configuration</div></div></div><div class=info>"; html += "<div class=hdr><img src=/logo.png alt=logo><div><h1>M1730</h1><div class=sub>Configuration</div></div></div><div class=info>";
html += "<div><span>Hostname</span><span>" + String(hostname) + "</span></div>"; html += "<div><span>Hostname</span><span>" + String(hostname) + "</span></div>";
@@ -561,6 +578,9 @@ html += ".switch input:checked+.slid{background:#4361ee}.switch input:checked+.s
html += "x.open('GET','/set?i='+this.name.match(/\\d+/)[0]+'&v='+this.value,true);x.send();"; html += "x.open('GET','/set?i='+this.name.match(/\\d+/)[0]+'&v='+this.value,true);x.send();";
html += "});}});"; html += "});}});";
html += "document.querySelector('select[name=meter_count]').addEventListener('change',function(){this.form.submit();});"; html += "document.querySelector('select[name=meter_count]').addEventListener('change',function(){this.form.submit();});";
if (meterCount > 1) {
html += "document.querySelectorAll('.tab-btn').forEach(function(b){b.addEventListener('click',function(){var t=this.dataset.tab;document.querySelectorAll('.tab-btn').forEach(function(x){x.classList.remove('active')});document.querySelectorAll('.tab-panel').forEach(function(x){x.classList.remove('active')});this.classList.add('active');document.querySelector('.tab-panel[data-tab=\"'+t+'\"]').classList.add('active')})});";
}
html += "</script></body></html>"; html += "</script></body></html>";
server.send(200, "text/html", html); server.send(200, "text/html", html);
Serial.printf("[HTTP] GET / -> 200 (%u bytes)\n", html.length()); Serial.printf("[HTTP] GET / -> 200 (%u bytes)\n", html.length());