Redesign embedded dashboard with tabs
This commit is contained in:
@@ -19,144 +19,208 @@ const char INDEX_HTML[] PROGMEM = R"rawliteral(
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>Overland Controller</title>
|
<title>Overland Controller</title>
|
||||||
<style>
|
<style>
|
||||||
:root{--bg:#0b0f14;--card:#141b24;--muted:#7f8da3;--text:#eef4ff;--good:#48d17a;--warn:#ffd166;--bad:#ff5c7a;--line:#223044;--btn:#233249}
|
:root{--bg:#0b0f14;--card:#141b24;--muted:#7f8da3;--text:#eef4ff;--good:#48d17a;--warn:#ffd166;--bad:#ff5c7a;--line:#223044;--btn:#233249}
|
||||||
*{box-sizing:border-box} body{margin:0;background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Arial,sans-serif}
|
*{box-sizing:border-box}
|
||||||
.wrap{max-width:980px;margin:0 auto;padding:18px}
|
body{margin:0;background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Arial,sans-serif}
|
||||||
.top{display:flex;justify-content:space-between;gap:12px;align-items:center;margin-bottom:14px}
|
.wrap{max-width:980px;margin:0 auto;padding:14px 14px 90px}
|
||||||
h1{font-size:22px;margin:0}.sub{color:var(--muted);font-size:13px;margin-top:4px}.pill{border:1px solid var(--line);border-radius:999px;padding:7px 10px;color:var(--muted);font-size:12px}
|
.top{display:flex;justify-content:space-between;gap:12px;align-items:center;margin-bottom:12px}
|
||||||
.grid{display:grid;grid-template-columns:repeat(12,1fr);gap:12px}.card{background:var(--card);border:1px solid var(--line);border-radius:18px;padding:16px;box-shadow:0 10px 28px rgba(0,0,0,.22)}
|
h1{font-size:21px;margin:0}.sub{color:var(--muted);font-size:13px;margin-top:4px}
|
||||||
.span6{grid-column:span 6}.span4{grid-column:span 4}.span12{grid-column:span 12}
|
.pill{border:1px solid var(--line);border-radius:999px;padding:7px 10px;color:var(--muted);font-size:12px;white-space:nowrap}
|
||||||
.label{color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.08em}.big{font-size:42px;font-weight:750;margin:8px 0}.row{display:flex;justify-content:space-between;gap:10px;border-top:1px solid var(--line);padding-top:10px;margin-top:10px}
|
.tabs{position:fixed;left:0;right:0;bottom:0;background:#080c11;border-top:1px solid var(--line);display:grid;grid-template-columns:repeat(3,1fr);z-index:10}
|
||||||
.v{font-weight:650}.good{color:var(--good)}.warn{color:var(--warn)}.bad{color:var(--bad)}.muted{color:var(--muted)}
|
.tabbtn{border:0;border-radius:0;background:#080c11;color:var(--muted);padding:13px 8px;font-weight:800}
|
||||||
.bar{height:10px;background:#0e141c;border-radius:999px;overflow:hidden;border:1px solid var(--line)}.fill{height:100%;background:linear-gradient(90deg,var(--good),#9be15d);width:0%}
|
.tabbtn.active{color:var(--text);background:#111923}
|
||||||
button{width:100%;border:0;border-radius:12px;padding:12px;background:var(--btn);color:var(--text);font-weight:700;font-size:15px}
|
.page{display:none}.page.active{display:block}
|
||||||
input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;background:#0f151d;color:var(--text);font-size:15px}
|
.grid{display:grid;grid-template-columns:repeat(12,1fr);gap:12px}
|
||||||
button.on{background:#17462a;color:#dfffea}button.off{background:#46202a;color:#ffe2e8}.relayBtns{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:12px}
|
.card{background:var(--card);border:1px solid var(--line);border-radius:18px;padding:16px;box-shadow:0 10px 28px rgba(0,0,0,.22)}
|
||||||
.tempList,.alarmList{display:grid;gap:8px;margin-top:12px}.item{display:flex;justify-content:space-between;gap:8px;background:#0f151d;border:1px solid var(--line);border-radius:12px;padding:10px}
|
.span4{grid-column:span 4}.span6{grid-column:span 6}.span12{grid-column:span 12}
|
||||||
@media(max-width:760px){.span6,.span4{grid-column:span 12}.big{font-size:36px}.wrap{padding:12px}}
|
.label{color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.08em}
|
||||||
</style>
|
.big{font-size:42px;font-weight:800;margin:8px 0}
|
||||||
|
.medium{font-size:25px;font-weight:800;margin:6px 0}
|
||||||
|
.row{display:flex;justify-content:space-between;gap:10px;border-top:1px solid var(--line);padding-top:10px;margin-top:10px}
|
||||||
|
.v{font-weight:700}.good{color:var(--good)}.warn{color:var(--warn)}.bad{color:var(--bad)}.muted{color:var(--muted)}
|
||||||
|
.bar{height:10px;background:#0e141c;border-radius:999px;overflow:hidden;border:1px solid var(--line)}
|
||||||
|
.fill{height:100%;background:linear-gradient(90deg,var(--good),#9be15d);width:0%}
|
||||||
|
button{width:100%;border:0;border-radius:12px;padding:12px;background:var(--btn);color:var(--text);font-weight:800;font-size:15px}
|
||||||
|
button.on{background:#17462a;color:#dfffea}button.off{background:#46202a;color:#ffe2e8}
|
||||||
|
input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;background:#0f151d;color:var(--text);font-size:15px}
|
||||||
|
.list{display:grid;gap:8px;margin-top:12px}
|
||||||
|
.item{display:flex;justify-content:space-between;gap:8px;background:#0f151d;border:1px solid var(--line);border-radius:12px;padding:10px}
|
||||||
|
.btnrow{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:12px}
|
||||||
|
.kpi{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:12px}
|
||||||
|
.kpi div{background:#0f151d;border:1px solid var(--line);border-radius:12px;padding:10px}
|
||||||
|
.kpi .num{font-size:20px;font-weight:800;margin-top:4px}
|
||||||
|
@media(max-width:760px){.span4,.span6{grid-column:span 12}.big{font-size:36px}.wrap{padding:12px 12px 82px}.kpi{grid-template-columns:1fr}}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<div class="top">
|
<div class="top">
|
||||||
<div>
|
<div>
|
||||||
<h1 id="device">Overland Controller</h1>
|
<h1 id="device">Overland Controller</h1>
|
||||||
<div class="sub">Local camp dashboard</div>
|
<div class="sub" id="subtitle">Local camp dashboard</div>
|
||||||
</div>
|
|
||||||
<div class="pill" id="conn">Connecting...</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="pill" id="conn">Connecting...</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="overviewPage" class="page active">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<section class="card span6">
|
<section class="card span6">
|
||||||
<div class="label">Battery</div>
|
<div class="label">Battery</div>
|
||||||
<div class="big"><span id="soc">--</span>%</div>
|
<div class="big"><span id="soc">--</span>%</div>
|
||||||
<div class="bar"><div class="fill" id="socbar"></div></div>
|
<div class="bar"><div class="fill" id="socbar"></div></div>
|
||||||
<div class="row"><span class="muted">Voltage</span><span class="v" id="voltage">--</span></div>
|
<div class="kpi">
|
||||||
<div class="row"><span class="muted">Current</span><span class="v" id="current">--</span></div>
|
<div><div class="muted">Voltage</div><div class="num" id="voltage">--</div></div>
|
||||||
<div class="row"><span class="muted">Remaining</span><span class="v" id="ah">--</span></div>
|
<div><div class="muted">Current</div><div class="num" id="current">--</div></div>
|
||||||
</section>
|
<div><div class="muted">Runtime</div><div class="num" id="runtime">--</div></div>
|
||||||
|
|
||||||
<section class="card span6">
|
|
||||||
<div class="label">BMS</div>
|
|
||||||
<div class="big" id="bmsState">--</div>
|
|
||||||
<div class="row"><span class="muted">Battery temp</span><span class="v" id="battTemp">--</span></div>
|
|
||||||
<div class="row"><span class="muted">Cell delta</span><span class="v" id="delta">--</span></div>
|
|
||||||
<div class="row"><span class="muted">Cycles</span><span class="v" id="cycles">--</span></div>
|
|
||||||
<div class="row"><span class="muted">BMS Polling</span><span class="v" id="bmsEnabledText">--</span></div>
|
|
||||||
<div class="relayBtns">
|
|
||||||
<button onclick="setBmsEnabled(true)">Enable BMS</button>
|
|
||||||
<button class="off" onclick="setBmsEnabled(false)">Disable BMS</button>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="card span6">
|
|
||||||
<div class="label">Temperatures</div>
|
|
||||||
<div class="tempList" id="temps"></div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="card span6">
|
<section class="card span6">
|
||||||
<div class="label">Relays</div>
|
<div class="label">Relays</div>
|
||||||
<div class="tempList" id="relays"></div>
|
<div class="list" id="relays"></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="card span12">
|
<section class="card span6">
|
||||||
<div class="label">WiFi</div>
|
<div class="label">Temperatures</div>
|
||||||
<div class="sub">AP stays available at 192.168.4.1. STA networks are tried in order.</div>
|
<div class="list" id="temps"></div>
|
||||||
<div class="tempList" style="margin-top:12px">
|
</section>
|
||||||
<input id="w1s" placeholder="Network 1 SSID">
|
|
||||||
<input id="w1p" placeholder="Network 1 password" type="password">
|
<section class="card span6">
|
||||||
<input id="w1r" placeholder="Network 1 priority, lower = first" inputmode="numeric">
|
<div class="label">Network / Alarms</div>
|
||||||
<input id="w2s" placeholder="Network 2 SSID">
|
|
||||||
<input id="w2p" placeholder="Network 2 password" type="password">
|
|
||||||
<input id="w2r" placeholder="Network 2 priority, lower = first" inputmode="numeric">
|
|
||||||
<input id="w3s" placeholder="Network 3 SSID">
|
|
||||||
<input id="w3p" placeholder="Network 3 password" type="password">
|
|
||||||
<input id="w3r" placeholder="Network 3 priority, lower = first" inputmode="numeric">
|
|
||||||
<button onclick="saveWifi()">Save WiFi</button>
|
|
||||||
<button onclick="connectWifi()">Connect Now</button>
|
|
||||||
</div>
|
|
||||||
<div class="row"><span class="muted">STA</span><span class="v" id="wifiSta">--</span></div>
|
<div class="row"><span class="muted">STA</span><span class="v" id="wifiSta">--</span></div>
|
||||||
<div class="row"><span class="muted">STA IP</span><span class="v" id="wifiIp">--</span></div>
|
<div class="row"><span class="muted">STA IP</span><span class="v" id="wifiIp">--</span></div>
|
||||||
</section>
|
<div class="list" id="alarmSummary"></div>
|
||||||
|
|
||||||
<section class="card span12">
|
|
||||||
<div class="label">Alarms / System</div>
|
|
||||||
<div class="alarmList" id="alarms"></div>
|
|
||||||
<div class="row"><span class="muted">Firmware</span><span class="v" id="fw">--</span></div>
|
|
||||||
<div class="row"><span class="muted">Uptime</span><span class="v" id="uptime">--</span></div>
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="batteryPage" class="page">
|
||||||
|
<div class="grid">
|
||||||
|
<section class="card span6">
|
||||||
|
<div class="label">Battery Detail</div>
|
||||||
|
<div class="medium" id="bmsState">--</div>
|
||||||
|
<div class="row"><span class="muted">Source</span><span class="v" id="battSource">--</span></div>
|
||||||
|
<div class="row"><span class="muted">Remaining</span><span class="v" id="ah">--</span></div>
|
||||||
|
<div class="row"><span class="muted">Capacity</span><span class="v" id="capacity">--</span></div>
|
||||||
|
<div class="row"><span class="muted">Battery temp</span><span class="v" id="battTemp">--</span></div>
|
||||||
|
<div class="row"><span class="muted">Cycles</span><span class="v" id="cycles">--</span></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="card span6">
|
||||||
|
<div class="label">Cells</div>
|
||||||
|
<div class="row"><span class="muted">Cell count</span><span class="v" id="cellCount">--</span></div>
|
||||||
|
<div class="row"><span class="muted">Cell delta</span><span class="v" id="delta">--</span></div>
|
||||||
|
<div class="list" id="cells"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="card span12">
|
||||||
|
<div class="label">BMS Control</div>
|
||||||
|
<div class="row"><span class="muted">BMS Polling</span><span class="v" id="bmsEnabledText">--</span></div>
|
||||||
|
<div class="btnrow">
|
||||||
|
<button onclick="setBmsEnabled(true)">Enable BMS</button>
|
||||||
|
<button class="off" onclick="setBmsEnabled(false)">Disable BMS</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="configPage" class="page">
|
||||||
|
<div class="grid">
|
||||||
|
<section class="card span12">
|
||||||
|
<div class="label">WiFi Config</div>
|
||||||
|
<div class="sub">AP remains available at 192.168.4.1. Lower priority number is tried first.</div>
|
||||||
|
<div class="list">
|
||||||
|
<input id="w1s" placeholder="Network 1 SSID">
|
||||||
|
<input id="w1p" placeholder="Network 1 password" type="password">
|
||||||
|
<input id="w1r" placeholder="Network 1 priority" inputmode="numeric">
|
||||||
|
<input id="w2s" placeholder="Network 2 SSID">
|
||||||
|
<input id="w2p" placeholder="Network 2 password" type="password">
|
||||||
|
<input id="w2r" placeholder="Network 2 priority" inputmode="numeric">
|
||||||
|
<input id="w3s" placeholder="Network 3 SSID">
|
||||||
|
<input id="w3p" placeholder="Network 3 password" type="password">
|
||||||
|
<input id="w3r" placeholder="Network 3 priority" inputmode="numeric">
|
||||||
|
<button onclick="saveWifi()">Save WiFi</button>
|
||||||
|
<button onclick="connectWifi()">Connect Now</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="card span12">
|
||||||
|
<div class="label">System</div>
|
||||||
|
<div class="row"><span class="muted">Firmware</span><span class="v" id="fw">--</span></div>
|
||||||
|
<div class="row"><span class="muted">Uptime</span><span class="v" id="uptime">--</span></div>
|
||||||
|
<div class="row"><span class="muted">AP IP</span><span class="v" id="apIp">--</span></div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tabs">
|
||||||
|
<button class="tabbtn active" onclick="showTab('overview')">Overview</button>
|
||||||
|
<button class="tabbtn" onclick="showTab('battery')">Battery</button>
|
||||||
|
<button class="tabbtn" onclick="showTab('config')">Config</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const $=id=>document.getElementById(id);
|
const $=id=>document.getElementById(id);
|
||||||
function fmt(n,d=1){return typeof n==="number"?n.toFixed(d):"--"}
|
function fmt(n,d=1){return typeof n==="number"?n.toFixed(d):"--"}
|
||||||
function temp(v){return typeof v==="number"?fmt(v,1)+"°F":"Offline"}
|
function temp(v){return typeof v==="number"?fmt(v,1)+"°F":"Offline"}
|
||||||
function clsAlarm(v){return v?"bad":"good"}
|
function runtimeText(b){
|
||||||
|
if(!b.connected) return "--";
|
||||||
|
if(typeof b.runtime_hours==="number" && b.runtime_hours>0) return fmt(b.runtime_hours,1)+"h";
|
||||||
|
if(typeof b.current==="number" && b.current<-.1 && typeof b.remaining_ah==="number"){
|
||||||
|
return fmt(b.remaining_ah/Math.abs(b.current),1)+"h";
|
||||||
|
}
|
||||||
|
return "Idle";
|
||||||
|
}
|
||||||
|
function showTab(name){
|
||||||
|
["overview","battery","config"].forEach(t=>{
|
||||||
|
$(t+"Page").classList.toggle("active",t===name);
|
||||||
|
});
|
||||||
|
document.querySelectorAll(".tabbtn").forEach((b,i)=>{
|
||||||
|
b.classList.toggle("active",["overview","battery","config"][i]===name);
|
||||||
|
});
|
||||||
|
}
|
||||||
async function setBmsEnabled(enabled){
|
async function setBmsEnabled(enabled){
|
||||||
try{
|
await fetch("/config/bms",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled})});
|
||||||
await fetch("/config/bms",{
|
await fetch("/config/save",{method:"POST"});
|
||||||
method:"POST",
|
await load();
|
||||||
headers:{"Content-Type":"application/json"},
|
|
||||||
body:JSON.stringify({enabled:enabled})
|
|
||||||
});
|
|
||||||
await fetch("/config/save",{method:"POST"});
|
|
||||||
await load();
|
|
||||||
}catch(e){}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function relay(id,on){
|
async function relay(id,on){
|
||||||
try{
|
await fetch("/relay/set",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id,state:on})});
|
||||||
await fetch("/relay/set",{
|
await load();
|
||||||
method:"POST",
|
|
||||||
headers:{"Content-Type":"application/json"},
|
|
||||||
body:JSON.stringify({id:id,state:on})
|
|
||||||
});
|
|
||||||
await load();
|
|
||||||
}catch(e){}
|
|
||||||
}
|
}
|
||||||
function render(data){
|
function render(data){
|
||||||
$("conn").textContent="Live";
|
$("conn").textContent="Live";
|
||||||
$("conn").className="pill good";
|
$("conn").className="pill good";
|
||||||
$("device").textContent=data.config?.device_name||"Overland Controller";
|
$("device").textContent=data.config?.device_name||"Overland Controller";
|
||||||
|
|
||||||
const b=data.battery||{};
|
const b=data.battery||{};
|
||||||
$("soc").textContent=fmt(b.soc,0);
|
$("soc").textContent=fmt(b.soc,0);
|
||||||
$("socbar").style.width=Math.max(0,Math.min(100,b.soc||0))+"%";
|
$("socbar").style.width=Math.max(0,Math.min(100,b.soc||0))+"%";
|
||||||
$("voltage").textContent=fmt(b.voltage,2)+" V";
|
$("voltage").textContent=fmt(b.voltage,2)+" V";
|
||||||
$("current").textContent=fmt(b.current,2)+" A";
|
$("current").textContent=fmt(b.current,2)+" A";
|
||||||
|
$("runtime").textContent=runtimeText(b);
|
||||||
|
$("bmsState").textContent=b.connected?"BMS Online":"BMS Offline";
|
||||||
|
$("bmsState").className=b.connected?"medium good":"medium bad";
|
||||||
|
$("battSource").textContent=b.source||"--";
|
||||||
$("ah").textContent=fmt(b.remaining_ah,1)+" Ah";
|
$("ah").textContent=fmt(b.remaining_ah,1)+" Ah";
|
||||||
$("bmsState").textContent=b.connected?"Online":"Offline";
|
$("capacity").textContent=fmt(b.capacity_ah,1)+" Ah";
|
||||||
$("bmsState").className=b.connected?"big good":"big bad";
|
|
||||||
$("battTemp").textContent=temp(b.temperature_f);
|
$("battTemp").textContent=temp(b.temperature_f);
|
||||||
$("delta").textContent=(typeof b.cell_delta_mv==="number"?b.cell_delta_mv:"--")+" mV";
|
|
||||||
$("cycles").textContent=b.cycle_count??"--";
|
$("cycles").textContent=b.cycle_count??"--";
|
||||||
|
$("cellCount").textContent=b.cell_count??"--";
|
||||||
|
$("delta").textContent=(typeof b.cell_delta_mv==="number"?b.cell_delta_mv:"--")+" mV";
|
||||||
|
|
||||||
const bmsCfg=data.config?.bms||{};
|
const bmsCfg=data.config?.bms||{};
|
||||||
$("bmsEnabledText").textContent=bmsCfg.enabled ? "Enabled" : "Disabled";
|
$("bmsEnabledText").textContent=bmsCfg.enabled ? "Enabled" : "Disabled";
|
||||||
|
|
||||||
|
$("cells").innerHTML=(b.cell_voltages||[]).map((v,i)=>`
|
||||||
|
<div class="item"><span>Cell ${i+1}</span><strong>${fmt(v,3)} V</strong></div>`).join("") ||
|
||||||
|
`<div class="item"><span>No cell data</span><strong class="muted">--</strong></div>`;
|
||||||
|
|
||||||
$("temps").innerHTML=(data.temps||[]).map(t=>`
|
$("temps").innerHTML=(data.temps||[]).map(t=>`
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<span>${t.name||t.id}</span>
|
<span>${t.name||t.id}</span>
|
||||||
@@ -165,21 +229,27 @@ function render(data){
|
|||||||
|
|
||||||
$("relays").innerHTML=(data.relays||[]).map(r=>`
|
$("relays").innerHTML=(data.relays||[]).map(r=>`
|
||||||
<div class="item" style="display:block">
|
<div class="item" style="display:block">
|
||||||
<div style="display:flex;justify-content:space-between"><span>${r.name||r.id}</span><strong class="${r.state?"good":"muted"}">${r.state?"ON":"OFF"}</strong></div>
|
<div style="display:flex;justify-content:space-between">
|
||||||
<div class="relayBtns">
|
<span>${r.name||r.id}</span>
|
||||||
|
<strong class="${r.state?"good":"muted"}">${r.state?"ON":"OFF"}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="btnrow">
|
||||||
<button class="on" onclick="relay('${r.id}',true)">ON</button>
|
<button class="on" onclick="relay('${r.id}',true)">ON</button>
|
||||||
<button class="off" onclick="relay('${r.id}',false)">OFF</button>
|
<button class="off" onclick="relay('${r.id}',false)">OFF</button>
|
||||||
</div>
|
</div>
|
||||||
</div>`).join("");
|
</div>`).join("");
|
||||||
|
|
||||||
const alarms=data.alarms||{};
|
const alarms=data.alarms||{};
|
||||||
$("alarms").innerHTML=Object.keys(alarms).map(k=>`
|
const active=Object.keys(alarms).filter(k=>alarms[k]);
|
||||||
<div class="item"><span>${k.replaceAll("_"," ")}</span><strong class="${clsAlarm(alarms[k])}">${alarms[k]?"ALARM":"OK"}</strong></div>`).join("");
|
$("alarmSummary").innerHTML=active.length
|
||||||
|
? active.map(k=>`<div class="item"><span>${k.replaceAll("_"," ")}</span><strong class="bad">ALARM</strong></div>`).join("")
|
||||||
|
: `<div class="item"><span>Alarms</span><strong class="good">OK</strong></div>`;
|
||||||
|
|
||||||
const s=data.system||{};
|
const s=data.system||{};
|
||||||
const n=data.network||{};
|
const n=data.network||{};
|
||||||
$("wifiSta").textContent=n.sta_connected ? (n.sta_ssid||"connected") : "Not connected";
|
$("wifiSta").textContent=n.sta_connected ? (n.sta_ssid||"connected") : "Not connected";
|
||||||
$("wifiIp").textContent=n.sta_ip||"--";
|
$("wifiIp").textContent=n.sta_ip||"--";
|
||||||
|
$("apIp").textContent=n.ap_ip||"--";
|
||||||
$("fw").textContent=(s.firmware_name||"--")+" "+(s.firmware_version||"");
|
$("fw").textContent=(s.firmware_name||"--")+" "+(s.firmware_version||"");
|
||||||
$("uptime").textContent=(s.uptime_seconds||0)+" sec";
|
$("uptime").textContent=(s.uptime_seconds||0)+" sec";
|
||||||
}
|
}
|
||||||
@@ -190,10 +260,8 @@ async function loadWifiConfig(){
|
|||||||
const nets=d.wifi?.networks||[];
|
const nets=d.wifi?.networks||[];
|
||||||
for(let i=0;i<3;i++){
|
for(let i=0;i<3;i++){
|
||||||
const n=nets[i]||{};
|
const n=nets[i]||{};
|
||||||
const s=$("w"+(i+1)+"s");
|
$("w"+(i+1)+"s").value=n.ssid||"";
|
||||||
if(s) s.value=n.ssid||"";
|
$("w"+(i+1)+"r").value=n.priority||i+1;
|
||||||
const pr=$("w"+(i+1)+"r");
|
|
||||||
if(pr) pr.value=n.priority||i+1;
|
|
||||||
}
|
}
|
||||||
}catch(e){}
|
}catch(e){}
|
||||||
}
|
}
|
||||||
@@ -205,11 +273,7 @@ async function saveWifi(){
|
|||||||
const priority=parseInt($("w"+i+"r").value||i,10);
|
const priority=parseInt($("w"+i+"r").value||i,10);
|
||||||
if(ssid) networks.push({ssid,password,priority});
|
if(ssid) networks.push({ssid,password,priority});
|
||||||
}
|
}
|
||||||
await fetch("/config/wifi",{
|
await fetch("/config/wifi",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({networks})});
|
||||||
method:"POST",
|
|
||||||
headers:{"Content-Type":"application/json"},
|
|
||||||
body:JSON.stringify({networks})
|
|
||||||
});
|
|
||||||
await loadWifiConfig();
|
await loadWifiConfig();
|
||||||
await load();
|
await load();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user