diff --git a/web/app.js b/web/app.js index 0117a78..3324b95 100644 --- a/web/app.js +++ b/web/app.js @@ -41,6 +41,6 @@ function renderMotors(servos){const signature=JSON.stringify(servos);if(signatur function render(s){connected=s.connected;$('#connect').textContent=connected?'Disconnect':'Connect';$('#link').textContent=s.link;$('.link-state').classList.toggle('online',s.link==='LINK OK');$('#vehicle').textContent=s.vehicle;$('#status').textContent=s.status;const b=s.battery;if(b){$('#battery-title').textContent=`${b.voltage.toFixed(2)} V`;$('#battery-percent').textContent=`${Math.round(b.percent)}% • ${b.cells}S`;$('#battery-fill').style.width=`${b.percent}%`;$('#battery-fill').style.background=b.low?'var(--red)':'var(--acid)'}else{$('#battery-title').textContent='—';$('#battery-percent').textContent='Waiting';$('#battery-fill').style.width='0'}renderMotors(s.servos)} async function poll(){if(!bridgeReady)return;try{render(await api('poll'))}catch(e){}setTimeout(poll,250)} let booted=false; -async function boot(){if(booted||!window.pywebview?.api)return;booted=true;bridgeReady=true;try{const init=await api('initial_state');batteryConfig=init.battery_config;populatePorts(init.ports);fillBatteryForm();render(init.state);const saved=await api('get_saved_model_info');if(saved){try{$('#load-model').textContent='Loading saved STL…';await loadCachedModel(saved);$('#load-model').textContent='Replace STL'}catch(error){$('#load-model').textContent='Load STL';toast(`Saved STL failed: ${error.message}`,true)}}poll();setInterval(async()=>{if(!connected)try{populatePorts(await api('refresh_ports'))}catch(_){}},2000)}catch(e){booted=false;bridgeReady=false;toast(`Python bridge: ${e.message}`,true);setTimeout(waitForBridge,500)}} +async function boot(){if(booted||!window.pywebview?.api)return;booted=true;bridgeReady=true;try{const init=await api('initial_state');batteryConfig=init.battery_config;populatePorts(init.ports);fillBatteryForm();render(init.state);const saved=init.saved_model||await api('get_saved_model_info');if(saved){try{$('#load-model').textContent='Loading saved STL…';await loadCachedModel(saved);$('#load-model').textContent='Replace STL'}catch(error){$('#load-model').textContent='Load STL';toast(`Saved STL failed: ${error.message}`,true)}}poll();setInterval(async()=>{if(!connected)try{populatePorts(await api('refresh_ports'))}catch(_){}},2000)}catch(e){booted=false;bridgeReady=false;toast(`Python bridge: ${e.message}`,true);setTimeout(waitForBridge,500)}} function waitForBridge(){if(window.pywebview?.api)boot();else setTimeout(waitForBridge,50)} addEventListener('pywebviewready',boot);if(document.readyState==='loading')addEventListener('DOMContentLoaded',waitForBridge);else waitForBridge(); diff --git a/web_ui.py b/web_ui.py index 5d9d440..0410b62 100644 --- a/web_ui.py +++ b/web_ui.py @@ -59,6 +59,7 @@ class ControlApi: return { "ports": [p.device for p in list_ports.comports()], "battery_config": self.battery_config, + "saved_model": self.get_saved_model_info(), "state": self._snapshot(), }