Add versioned HTTP API routes
This commit is contained in:
@@ -209,7 +209,6 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
|
||||
</div>
|
||||
<div class="btnrow">
|
||||
<button onclick="setBmsEnabled(true)">Enable BMS</button>
|
||||
<button onclick="reconnectBms()">Reconnect BMS</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -218,7 +217,6 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
|
||||
<div class="label">System Actions</div>
|
||||
<div class="sub">Use carefully. Factory reset clears install-specific configuration.</div>
|
||||
<div class="btnrow">
|
||||
<button onclick="restartController()">Restart</button>
|
||||
<button class="off" onclick="factoryReset()">Factory Reset</button>
|
||||
</div>
|
||||
</section>
|
||||
@@ -240,6 +238,8 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const API_BASE="/api/v1";
|
||||
function api(path){return API_BASE+path;}
|
||||
const $=id=>document.getElementById(id);
|
||||
function fmt(n,d=1){return typeof n==="number"?n.toFixed(d):"--"}
|
||||
function temp(v){return typeof v==="number"?fmt(v,1)+"°F":"Offline"}
|
||||
@@ -323,12 +323,12 @@ function showTab(name){
|
||||
});
|
||||
}
|
||||
async function setBmsEnabled(enabled){
|
||||
await fetch("/config/bms",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled})});
|
||||
await fetch("/config/save",{method:"POST"});
|
||||
await fetch(api("/config/bms"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled})});
|
||||
await fetch(api("/config/save"),{method:"POST"});
|
||||
await load();
|
||||
}
|
||||
async function relay(id,on){
|
||||
await fetch("/relay/set",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id,state:on})});
|
||||
await fetch(api("/relay/set"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id,state:on})});
|
||||
await load();
|
||||
}
|
||||
function render(data){
|
||||
@@ -411,13 +411,13 @@ async function saveDeviceConfig(){
|
||||
const name=$("deviceNameInput")?.value.trim();
|
||||
if(!name){ alert("Device name is required"); return; }
|
||||
|
||||
await fetch("/config/device",{
|
||||
await fetch(api("/config/device"),{
|
||||
method:"POST",
|
||||
headers:{"Content-Type":"application/json"},
|
||||
body:JSON.stringify({device_name:name})
|
||||
});
|
||||
|
||||
await fetch("/config/save",{method:"POST"});
|
||||
await fetch(api("/config/save"),{method:"POST"});
|
||||
await load();
|
||||
alert("Device name saved");
|
||||
}
|
||||
@@ -432,7 +432,7 @@ async function saveBmsFullConfig(){
|
||||
return;
|
||||
}
|
||||
|
||||
await fetch("/config/bms",{
|
||||
await fetch(api("/config/bms"),{
|
||||
method:"POST",
|
||||
headers:{"Content-Type":"application/json"},
|
||||
body:JSON.stringify({
|
||||
@@ -443,22 +443,16 @@ async function saveBmsFullConfig(){
|
||||
})
|
||||
});
|
||||
|
||||
await fetch("/config/save",{method:"POST"});
|
||||
await reconnectBms(false);
|
||||
await fetch(api("/config/save"),{method:"POST"});
|
||||
await load();
|
||||
alert("BMS config saved");
|
||||
}
|
||||
|
||||
async function reconnectBms(showAlert=true){
|
||||
await fetch("/bms/reconnect",{method:"POST"});
|
||||
if(showAlert) alert("BMS reconnect requested");
|
||||
}
|
||||
|
||||
async function scanTemps(){
|
||||
const box=$("tempScanResults");
|
||||
if(box) box.innerHTML=`<div class="item"><span>Scanning...</span><strong class="muted">wait</strong></div>`;
|
||||
|
||||
const r=await fetch("/temps/scan",{method:"POST"});
|
||||
const r=await fetch(api("/temps/scan"),{method:"POST"});
|
||||
const d=await r.json();
|
||||
const devices=d.devices||[];
|
||||
|
||||
@@ -487,13 +481,13 @@ async function scanTemps(){
|
||||
}
|
||||
|
||||
async function assignTemp(id,index){
|
||||
await fetch("/temps/assign",{
|
||||
await fetch(api("/temps/assign"),{
|
||||
method:"POST",
|
||||
headers:{"Content-Type":"application/json"},
|
||||
body:JSON.stringify({id:id,index:index})
|
||||
});
|
||||
|
||||
await fetch("/config/save",{method:"POST"});
|
||||
await fetch(api("/config/save"),{method:"POST"});
|
||||
await load();
|
||||
alert("Temp probe assigned to "+id);
|
||||
}
|
||||
@@ -501,7 +495,7 @@ async function assignTemp(id,index){
|
||||
async function clearTempAssignment(id){
|
||||
if(!confirm("Clear probe assignment for "+id+"?")) return;
|
||||
|
||||
const r=await fetch("/temps/clear",{
|
||||
const r=await fetch(api("/temps/clear"),{
|
||||
method:"POST",
|
||||
headers:{"Content-Type":"application/json"},
|
||||
body:JSON.stringify({id:id})
|
||||
@@ -517,17 +511,11 @@ async function clearTempAssignment(id){
|
||||
alert("Temp probe assignment cleared for "+id);
|
||||
}
|
||||
|
||||
async function restartController(){
|
||||
if(!confirm("Restart the controller now?")) return;
|
||||
await fetch("/system/restart",{method:"POST"});
|
||||
alert("Restart requested");
|
||||
}
|
||||
|
||||
async function factoryReset(){
|
||||
if(!confirm("Factory reset all controller configuration?")) return;
|
||||
if(!confirm("This clears WiFi/BMS/relay/temp config. Continue?")) return;
|
||||
|
||||
await fetch("/config/factory-reset",{method:"POST"});
|
||||
await fetch(api("/config/factory-reset"),{method:"POST"});
|
||||
alert("Factory reset requested. Reconnect to the controller AP if needed.");
|
||||
}
|
||||
|
||||
@@ -574,7 +562,7 @@ function renderConfigControls(data){
|
||||
}
|
||||
|
||||
async function saveRelayConfig(){
|
||||
const r=await fetch("/status",{cache:"no-store"});
|
||||
const r=await fetch(api("/status"),{cache:"no-store"});
|
||||
const data=await r.json();
|
||||
const relays=data.config?.relays||[];
|
||||
|
||||
@@ -582,7 +570,7 @@ async function saveRelayConfig(){
|
||||
const name=$("relayName"+i)?.value.trim();
|
||||
if(!name) continue;
|
||||
|
||||
await fetch("/config/relay",{
|
||||
await fetch(api("/config/relay"),{
|
||||
method:"POST",
|
||||
headers:{"Content-Type":"application/json"},
|
||||
body:JSON.stringify({
|
||||
@@ -593,13 +581,13 @@ async function saveRelayConfig(){
|
||||
});
|
||||
}
|
||||
|
||||
await fetch("/config/save",{method:"POST"});
|
||||
await fetch(api("/config/save"),{method:"POST"});
|
||||
await load();
|
||||
alert("Relay names saved");
|
||||
}
|
||||
|
||||
async function saveTempConfig(){
|
||||
const r=await fetch("/status",{cache:"no-store"});
|
||||
const r=await fetch(api("/status"),{cache:"no-store"});
|
||||
const data=await r.json();
|
||||
const temps=data.config?.temperature_sensors||[];
|
||||
|
||||
@@ -613,7 +601,7 @@ async function saveTempConfig(){
|
||||
const enabled=$("tempEnabled"+i)?.checked || false;
|
||||
const weather=$("tempWeather"+i)?.checked || false;
|
||||
|
||||
await fetch("/config/temp",{
|
||||
await fetch(api("/config/temp"),{
|
||||
method:"POST",
|
||||
headers:{"Content-Type":"application/json"},
|
||||
body:JSON.stringify({
|
||||
@@ -621,20 +609,19 @@ async function saveTempConfig(){
|
||||
name:name,
|
||||
address:temps[i].address||"",
|
||||
enabled:enabled,
|
||||
weather:weather,
|
||||
weather:weather
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
await fetch("/config/save",{method:"POST"});
|
||||
await fetch(api("/config/save"),{method:"POST"});
|
||||
await load();
|
||||
alert("Temperature config saved");
|
||||
}
|
||||
|
||||
async function loadWifiConfig(){
|
||||
try{
|
||||
const r=await fetch("/config/wifi",{cache:"no-store"});
|
||||
const r=await fetch(api("/config/wifi"),{cache:"no-store"});
|
||||
const d=await r.json();
|
||||
const nets=d.wifi?.networks||[];
|
||||
for(let i=0;i<3;i++){
|
||||
@@ -652,17 +639,17 @@ async function saveWifi(){
|
||||
const priority=parseInt($("w"+i+"r").value||i,10);
|
||||
if(ssid) networks.push({ssid,password,priority});
|
||||
}
|
||||
await fetch("/config/wifi",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({networks})});
|
||||
await fetch(api("/config/wifi"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({networks})});
|
||||
await loadWifiConfig();
|
||||
await load();
|
||||
}
|
||||
async function connectWifi(){
|
||||
await fetch("/wifi/connect",{method:"POST"});
|
||||
await fetch(api("/wifi/connect"),{method:"POST"});
|
||||
await load();
|
||||
}
|
||||
async function load(){
|
||||
try{
|
||||
const r=await fetch("/status",{cache:"no-store"});
|
||||
const r=await fetch(api("/status"),{cache:"no-store"});
|
||||
render(await r.json());
|
||||
}catch(e){
|
||||
$("conn").textContent="Offline";
|
||||
@@ -678,6 +665,8 @@ setInterval(load,3000);
|
||||
)rawliteral";
|
||||
|
||||
WebServer server(80);
|
||||
|
||||
#define API_V1(path) "/api/v1" path
|
||||
HardwareSerial DashboardSerial(2);
|
||||
|
||||
String uartLineBuffer;
|
||||
@@ -2445,6 +2434,32 @@ void setup() {
|
||||
server.send_P(200, "text/html", INDEX_HTML);
|
||||
});
|
||||
|
||||
server.on(API_V1("/status"), handleStatus);
|
||||
server.on(API_V1("/relay/set"), HTTP_POST, handleSetRelayPost);
|
||||
|
||||
server.on(API_V1("/config"), HTTP_GET, handleGetConfig);
|
||||
server.on(API_V1("/config/wifi"), HTTP_GET, handleGetWifiConfig);
|
||||
server.on(API_V1("/config/wifi"), HTTP_POST, handleUpdateWifiConfig);
|
||||
server.on(API_V1("/wifi/connect"), HTTP_POST, handleWifiConnect);
|
||||
server.on(API_V1("/wifi/clear"), HTTP_POST, handleWifiClear);
|
||||
|
||||
server.on(API_V1("/config/device"), HTTP_POST, handleUpdateDeviceConfig);
|
||||
server.on(API_V1("/config/relay"), HTTP_POST, handleUpdateRelayConfig);
|
||||
server.on(API_V1("/config/bms"), HTTP_POST, handleUpdateBmsConfig);
|
||||
server.on(API_V1("/config/temp"), HTTP_POST, handleUpdateTempSensorConfig);
|
||||
server.on(API_V1("/config/factory-reset"), HTTP_POST, handleFactoryResetConfig);
|
||||
server.on(API_V1("/config/save"), HTTP_POST, handleSaveConfig);
|
||||
|
||||
server.on(API_V1("/temps/scan"), HTTP_POST, handleTempScan);
|
||||
server.on(API_V1("/temps/assign"), HTTP_POST, handleTempAssign);
|
||||
server.on(API_V1("/temps/clear"), HTTP_POST, handleTempClear);
|
||||
|
||||
server.on(API_V1("/bms/setup/enter"), HTTP_POST, handleEnterBmsSetup);
|
||||
server.on(API_V1("/bms/setup/exit"), HTTP_POST, handleExitBmsSetup);
|
||||
server.on(API_V1("/bms/scan"), HTTP_POST, handleBleScan);
|
||||
server.on(API_V1("/bms/select"), HTTP_POST, handleSelectBms);
|
||||
|
||||
// Compatibility aliases for pre-versioned local clients.
|
||||
server.on("/status", handleStatus);
|
||||
server.on("/relay/set", HTTP_POST, handleSetRelayPost);
|
||||
server.on("/relay/relay_1/on", HTTP_GET, handleGenericRelayRoute);
|
||||
|
||||
Reference in New Issue
Block a user