From 5396949cf6a823c2a30dcdf75d30a1313001cecb Mon Sep 17 00:00:00 2001 From: Grant Date: Tue, 12 May 2026 00:42:13 +0200 Subject: [PATCH] chore: remove duplicate and zip files from widgets folder --- widgets/files.zip | Bin 12489 -> 0 bytes widgets/w1_system_health_indicator copy.json | 7 ------- widgets/w2_mission_status copy.json | 7 ------- widgets/w3_abort_button copy.json | 7 ------- widgets/w4_mission_setup_button copy.json | 7 ------- widgets/w5_battery_return_budget copy.json | 7 ------- 6 files changed, 35 deletions(-) delete mode 100644 widgets/files.zip delete mode 100644 widgets/w1_system_health_indicator copy.json delete mode 100644 widgets/w2_mission_status copy.json delete mode 100644 widgets/w3_abort_button copy.json delete mode 100644 widgets/w4_mission_setup_button copy.json delete mode 100644 widgets/w5_battery_return_budget copy.json diff --git a/widgets/files.zip b/widgets/files.zip deleted file mode 100644 index 575c7b5c29536f604969969d923319574385f6cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12489 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 V`kPb%05E@#qrdNRobg|0{|itWQ+oga diff --git a/widgets/w1_system_health_indicator copy.json b/widgets/w1_system_health_indicator copy.json deleted file mode 100644 index d455650..0000000 --- a/widgets/w1_system_health_indicator copy.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "html": "
\n
\n
\n Green\n
\n
\n
\n Amber\n
\n
\n
\n Red\n
\n
\n
Connecting\u2026
\n
\u2014
", - - "css": "*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n:root {\n --bg: #09111a;\n --text0: #d8eeff;\n --text1: #6a9bbf;\n --green: #00e09a;\n --amber: #ffb830;\n --red: #ff3a5a;\n --dim: #1a2d42;\n --border: #1e3050;\n --mono: 'Courier New', monospace;\n}\nbody {\n background: var(--bg);\n color: var(--text0);\n font-family: var(--mono);\n height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n user-select: none;\n}\n#circles { display: flex; gap: 12px; align-items: center; justify-content: center; margin-bottom: 10px; }\n.circle-wrap { display: flex; flex-direction: column; align-items: center; gap: 4px; }\n.circle {\n width: 36px; height: 36px;\n border-radius: 50%;\n border: 2px solid var(--border);\n background: var(--dim);\n transition: background 0.3s, border-color 0.3s, box-shadow 0.3s;\n}\n.circle.green { background: var(--green); border-color: var(--green); box-shadow: 0 0 12px var(--green); }\n.circle.amber { background: var(--amber); border-color: var(--amber); box-shadow: 0 0 12px var(--amber); }\n.circle.red { background: var(--red); border-color: var(--red); animation: flash-red 1s ease-in-out infinite; }\n@keyframes flash-red {\n 0%, 100% { box-shadow: 0 0 16px var(--red); }\n 50% { box-shadow: 0 0 32px var(--red), 0 0 8px #ff000088; }\n}\n.circle-label { font-size: 9px; color: var(--text1); text-transform: uppercase; letter-spacing: 0.08em; }\n.circle-label.active { color: var(--text0); font-weight: bold; }\n#message { font-size: 11px; color: var(--text1); text-align: center; max-width: 180px; line-height: 1.4; min-height: 16px; }\n#message.green { color: var(--green); }\n#message.amber { color: var(--amber); }\n#message.red { color: var(--red); }\n#footer { margin-top: 6px; font-size: 9px; color: #2a4060; }", - - "js": "// Config\nvar VARIABLE = 'rov_failsafe';\nvar POLL_MS = 500;\nvar STATE_GREEN = 0, STATE_AMBER = 1, STATE_RED = 2;\nvar MESSAGES = {};\nMESSAGES[STATE_GREEN] = 'Systems nominal';\nMESSAGES[STATE_AMBER] = 'Parameter degraded \u2014 check system';\nMESSAGES[STATE_RED] = 'CRITICAL \u2014 Safe action triggered';\n\n// DOM\nvar cGreen = document.getElementById('c-green');\nvar cAmber = document.getElementById('c-amber');\nvar cRed = document.getElementById('c-red');\nvar lGreen = document.getElementById('l-green');\nvar lAmber = document.getElementById('l-amber');\nvar lRed = document.getElementById('l-red');\nvar msgEl = document.getElementById('message');\nvar footEl = document.getElementById('footer');\n\nfunction applyState(state, reason) {\n [cGreen, cAmber, cRed].forEach(function(c) { c.classList.remove('green','amber','red'); });\n [lGreen, lAmber, lRed].forEach(function(l) { l.classList.remove('active'); });\n msgEl.classList.remove('green','amber','red');\n if (state === STATE_GREEN) {\n cGreen.classList.add('green'); lGreen.classList.add('active');\n msgEl.classList.add('green'); msgEl.textContent = reason || MESSAGES[STATE_GREEN];\n } else if (state === STATE_AMBER) {\n cAmber.classList.add('amber'); lAmber.classList.add('active');\n msgEl.classList.add('amber'); msgEl.textContent = reason || MESSAGES[STATE_AMBER];\n } else if (state === STATE_RED) {\n cRed.classList.add('red'); lRed.classList.add('active');\n msgEl.classList.add('red'); msgEl.textContent = reason || MESSAGES[STATE_RED];\n } else {\n msgEl.textContent = 'Waiting for data\u2026';\n }\n}\n\nfunction poll() {\n try {\n if (typeof window.cockpit === 'undefined' || typeof window.cockpit.getDataLakeValue !== 'function') {\n applyState(null); footEl.textContent = 'API not ready'; return;\n }\n var raw = window.cockpit.getDataLakeValue(VARIABLE);\n if (raw === null || raw === undefined) {\n applyState(null); footEl.textContent = 'Waiting for ' + VARIABLE; return;\n }\n applyState(parseInt(raw, 10), null);\n footEl.textContent = 'Updated ' + new Date().toLocaleTimeString();\n } catch(err) {\n applyState(null); footEl.textContent = 'Poll error';\n console.error('[Health Widget]', err);\n }\n}\n\nsetTimeout(poll, 300);\nsetInterval(poll, POLL_MS);" -} diff --git a/widgets/w2_mission_status copy.json b/widgets/w2_mission_status copy.json deleted file mode 100644 index be11e1c..0000000 --- a/widgets/w2_mission_status copy.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "html": "
\u2014
\n
\n
\u2014%
\n
Waypoint: \u2014
\n
Waiting for rov_mission_state\u2026
", - - "css": "*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n:root {\n --bg: #09111a;\n --border: #1e3050;\n --text0: #d8eeff;\n --text1: #6a9bbf;\n --green: #00e09a;\n --amber: #ffb830;\n --red: #ff3a5a;\n --blue: #00c8f0;\n --dim: #1a2d42;\n --mono: 'Courier New', monospace;\n}\nbody {\n background: var(--bg); color: var(--text0); font-family: var(--mono);\n height: 100vh; display: flex; flex-direction: column;\n align-items: center; justify-content: center;\n overflow: hidden; padding: 10px 14px; gap: 8px;\n}\n#state-label {\n font-size: 18px; font-weight: bold;\n letter-spacing: 0.12em; text-transform: uppercase; color: var(--text1);\n}\n#state-label.idle { color: var(--text1); }\n#state-label.running { color: var(--green); }\n#state-label.paused { color: var(--amber); }\n#state-label.complete { color: var(--blue); }\n#state-label.aborted { color: var(--red); }\n#state-label.waiting { color: var(--dim); }\n#bar-wrap {\n width: 100%; height: 8px;\n background: var(--dim); border-radius: 4px;\n border: 1px solid var(--border); overflow: hidden;\n}\n#bar-fill { height: 100%; width: 0%; border-radius: 4px; background: var(--green); transition: width 0.5s ease, background 0.3s; }\n#pct-label { font-size: 11px; color: var(--text1); align-self: flex-end; margin-top: -4px; }\n#waypoint { font-size: 10px; color: var(--text1); text-align: center; }\n#footer { font-size: 9px; color: #1e3050; }", - - "js": "var VAR_STATE = 'rov_mission_state';\nvar VAR_PROGRESS = 'rov_mission_progress';\nvar POLL_MS = 500;\nvar STATE = {0:'IDLE',1:'RUNNING',2:'PAUSED',3:'COMPLETE',4:'ABORTED'};\nvar META = {\n 0:{cls:'idle', bar:'#1a2d42'},\n 1:{cls:'running', bar:'#00e09a'},\n 2:{cls:'paused', bar:'#ffb830'},\n 3:{cls:'complete',bar:'#00c8f0'},\n 4:{cls:'aborted', bar:'#ff3a5a'}\n};\nvar stateLabelEl = document.getElementById('state-label');\nvar barFillEl = document.getElementById('bar-fill');\nvar pctLabelEl = document.getElementById('pct-label');\nvar waypointEl = document.getElementById('waypoint');\nvar footerEl = document.getElementById('footer');\n\nfunction render(state, progress) {\n var stateStr = STATE[state] || '?';\n var meta = META[state] || {cls:'waiting', bar:'#1a2d42'};\n var pct = Math.round((progress || 0) * 100);\n stateLabelEl.className = meta.cls;\n stateLabelEl.textContent = stateStr;\n barFillEl.style.width = pct + '%';\n barFillEl.style.background = meta.bar;\n pctLabelEl.textContent = (state===1||state===2) ? pct+'%' : (state===3 ? '100%' : '\u2014%');\n if (state===1||state===2) waypointEl.textContent = 'Progress ' + pct + '% complete';\n else if (state===3) waypointEl.textContent = 'Mission complete';\n else if (state===4) waypointEl.textContent = 'Mission aborted \u2014 vehicle holding';\n else waypointEl.textContent = 'No mission active';\n footerEl.textContent = 'Updated ' + new Date().toLocaleTimeString();\n}\n\nfunction poll() {\n try {\n if (typeof window.cockpit === 'undefined' || typeof window.cockpit.getDataLakeValue !== 'function') {\n stateLabelEl.className = 'waiting'; stateLabelEl.textContent = '\u2014';\n footerEl.textContent = 'API not ready'; return;\n }\n var raw = window.cockpit.getDataLakeValue(VAR_STATE);\n if (raw === null || raw === undefined) {\n stateLabelEl.className = 'waiting'; stateLabelEl.textContent = '\u2014';\n footerEl.textContent = 'Waiting for ' + VAR_STATE; return;\n }\n var prog = window.cockpit.getDataLakeValue(VAR_PROGRESS);\n render(parseInt(raw,10), parseFloat(prog||0));\n } catch(err) {\n stateLabelEl.className='waiting'; stateLabelEl.textContent='ERR';\n footerEl.textContent='Poll error'; console.error('[MissionStatus]',err);\n }\n}\nsetTimeout(poll,300); setInterval(poll,POLL_MS);" -} diff --git a/widgets/w3_abort_button copy.json b/widgets/w3_abort_button copy.json deleted file mode 100644 index d65395c..0000000 --- a/widgets/w3_abort_button copy.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "html": "\n
Standby
\n
\n
\n

Abort mission?
Vehicle will hold position
and await instruction.

\n
\n \n \n
\n
\n
\n
", - - "css": "*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n:root {\n --bg: #09111a; --text0: #d8eeff; --text1: #8fb3d4;\n --red: #ff3a5a; --red-dim: #7a1a28; --green: #00e09a; --mono: 'Courier New', monospace;\n}\nbody {\n background: var(--bg); color: var(--text0); font-family: var(--mono);\n height: 100vh; display: flex; flex-direction: column;\n align-items: center; justify-content: center;\n overflow: hidden; padding: 12px; gap: 10px;\n}\n#abort-btn {\n width: 100%; padding: 14px 0;\n background: var(--red-dim); border: 2px solid var(--red); border-radius: 6px;\n color: var(--red); font-family: var(--mono); font-size: 15px; font-weight: bold;\n letter-spacing: 0.15em; text-transform: uppercase; cursor: pointer;\n transition: background 0.15s, box-shadow 0.15s;\n}\n#abort-btn:hover { background: #2a0c18; box-shadow: 0 0 16px var(--red); }\n#abort-btn:active { background: var(--red); color: #fff; }\n#abort-btn:disabled { background: #1a0a10; border-color: #3a1020; color: var(--red-dim); cursor: not-allowed; box-shadow: none; }\n#confirm-overlay {\n display: none; position: fixed; inset: 0;\n background: rgba(0,0,0,0.7);\n align-items: center; justify-content: center; z-index: 10;\n}\n#confirm-overlay.active { display: flex; }\n#confirm-box {\n background: #100510; border: 2px solid var(--red); border-radius: 8px;\n padding: 18px; max-width: 220px; text-align: center;\n box-shadow: 0 0 30px var(--red);\n}\n#confirm-box p { font-size: 12px; color: var(--text0); line-height: 1.5; margin-bottom: 14px; }\n.btn-row { display: flex; gap: 8px; justify-content: center; }\n#confirm-yes {\n flex: 1; padding: 8px; background: var(--red); border: none;\n border-radius: 4px; color: #fff; font-family: var(--mono);\n font-size: 12px; font-weight: bold; cursor: pointer; letter-spacing: 0.08em;\n}\n#confirm-yes:hover { background: #ff6080; }\n#confirm-no {\n flex: 1; padding: 8px; background: transparent;\n border: 1px solid var(--text1); border-radius: 4px;\n color: var(--text1); font-family: var(--mono); font-size: 12px; cursor: pointer;\n}\n#confirm-no:hover { border-color: var(--text0); color: var(--text0); }\n#countdown { font-size: 10px; color: var(--red-dim); margin-top: 8px; }\n#status { font-size: 10px; color: var(--text1); text-align: center; min-height: 14px; }\n#status.ok { color: var(--green); }\n#status.err { color: var(--red); }", - - "js": "var FASTAPI_HOST = 'http://blueos.local:8081';\nvar AUTO_DISMISS_SEC = 10;\nvar abortBtn = document.getElementById('abort-btn');\nvar overlay = document.getElementById('confirm-overlay');\nvar confirmYes = document.getElementById('confirm-yes');\nvar confirmNo = document.getElementById('confirm-no');\nvar countdownEl = document.getElementById('countdown');\nvar statusEl = document.getElementById('status');\nvar dismissTimer = null;\nvar countdownVal = AUTO_DISMISS_SEC;\n\nfunction showConfirm() {\n overlay.classList.add('active');\n countdownVal = AUTO_DISMISS_SEC;\n countdownEl.textContent = 'Auto-cancel in ' + countdownVal + 's';\n dismissTimer = setInterval(function() {\n countdownVal--;\n countdownEl.textContent = 'Auto-cancel in ' + countdownVal + 's';\n if (countdownVal <= 0) hideConfirm();\n }, 1000);\n}\n\nfunction hideConfirm() {\n overlay.classList.remove('active');\n clearInterval(dismissTimer);\n dismissTimer = null;\n countdownEl.textContent = '';\n}\n\nasync function sendAbort() {\n hideConfirm();\n abortBtn.disabled = true;\n statusEl.className = '';\n statusEl.textContent = 'Sending abort\u2026';\n try {\n var res = await fetch(FASTAPI_HOST + '/abort', {\n method: 'POST',\n headers: {'Content-Type':'application/json'},\n body: JSON.stringify({abort:true}),\n signal: AbortSignal.timeout(5000)\n });\n if (res.ok) {\n statusEl.className = 'ok';\n statusEl.textContent = 'Abort sent \u2014 vehicle holding';\n } else {\n statusEl.className = 'err';\n statusEl.textContent = 'Server error: ' + res.status;\n abortBtn.disabled = false;\n }\n } catch(err) {\n statusEl.className = 'err';\n statusEl.textContent = 'Network error \u2014 check connection';\n abortBtn.disabled = false;\n console.error('[Abort]', err);\n }\n}\n\nabortBtn.addEventListener('click', function() { if (!abortBtn.disabled) showConfirm(); });\nconfirmYes.addEventListener('click', sendAbort);\nconfirmNo.addEventListener('click', hideConfirm);" -} diff --git a/widgets/w4_mission_setup_button copy.json b/widgets/w4_mission_setup_button copy.json deleted file mode 100644 index 1ba13e8..0000000 --- a/widgets/w4_mission_setup_button copy.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "html": "\n
\u2014
", - - "css": "*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n:root {\n --bg: #09111a; --border: #1e3050;\n --text0: #d8eeff; --text1: #6a9bbf;\n --accent: #00c8f0; --dim: #1a2d42; --amber: #ffb830;\n --mono: 'Courier New', monospace;\n}\nbody {\n background: var(--bg); color: var(--text0); font-family: var(--mono);\n height: 100vh; display: flex; flex-direction: column;\n align-items: center; justify-content: center;\n overflow: hidden; padding: 10px; gap: 6px;\n}\n#setup-btn {\n width: 100%; padding: 10px 0;\n background: transparent; border: 1px solid var(--accent); border-radius: 5px;\n color: var(--accent); font-family: var(--mono); font-size: 12px; font-weight: bold;\n letter-spacing: 0.1em; text-transform: uppercase; cursor: pointer;\n transition: background 0.2s, border-color 0.2s, color 0.2s, opacity 0.3s;\n}\n#setup-btn:hover { background: rgba(0,200,240,0.1); box-shadow: 0 0 10px rgba(0,200,240,0.3); }\n#setup-btn.subdued { border-color: var(--dim); color: var(--text1); opacity: 0.5; }\n#setup-btn.subdued:hover { opacity: 0.75; background: transparent; box-shadow: none; }\n#status { font-size: 9px; color: var(--text1); text-align: center; }\n#status.active-warn { color: var(--amber); }", - - "js": "var SETUP_URL = 'http://blueos.local:8081/setup';\nvar VAR_STATE = 'rov_mission_state';\nvar POLL_MS = 1000;\nvar setupBtn = document.getElementById('setup-btn');\nvar statusEl = document.getElementById('status');\n\nsetupBtn.addEventListener('click', function() {\n window.open(SETUP_URL, '_blank', 'noopener,noreferrer');\n});\n\nfunction poll() {\n try {\n if (typeof window.cockpit === 'undefined' || typeof window.cockpit.getDataLakeValue !== 'function') {\n setupBtn.classList.remove('subdued'); statusEl.className = '';\n statusEl.textContent = 'Connecting\u2026'; return;\n }\n var raw = window.cockpit.getDataLakeValue(VAR_STATE);\n if (raw === null || raw === undefined) {\n setupBtn.classList.remove('subdued'); statusEl.className = '';\n statusEl.textContent = 'No mission loaded'; return;\n }\n var state = parseInt(raw, 10);\n if (state === 1 || state === 2) {\n setupBtn.classList.add('subdued'); statusEl.className = 'active-warn';\n statusEl.textContent = state === 1\n ? 'Mission running \u2014 setup changes not recommended'\n : 'Mission paused \u2014 setup changes not recommended';\n } else {\n setupBtn.classList.remove('subdued'); statusEl.className = '';\n statusEl.textContent = state === 0\n ? 'No mission loaded \u2014 configure before diving'\n : 'Ready to configure next mission';\n }\n } catch(err) { console.error('[SetupBtn]', err); }\n}\nsetTimeout(poll, 300); setInterval(poll, POLL_MS);" -} diff --git a/widgets/w5_battery_return_budget copy.json b/widgets/w5_battery_return_budget copy.json deleted file mode 100644 index 673c968..0000000 --- a/widgets/w5_battery_return_budget copy.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "html": "Return Budget\n
\n Battery\n --%\n
\n
\n Required\n --%\n
\n
\n
\n
\n Headroom\n --\n
\n
\n
\n
Waiting for data\u2026
\n
\u2014
", - - "css": "*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n:root {\n --bg: #09111a; --border: #1e3050;\n --text0: #d8eeff; --text1: #6a9bbf;\n --green: #00e09a; --amber: #ffb830; --red: #ff3a5a; --dim: #1a2d42;\n --mono: 'Courier New', monospace;\n}\nbody {\n background: var(--bg); color: var(--text0); font-family: var(--mono);\n height: 100vh; display: flex; flex-direction: column;\n align-items: center; justify-content: center;\n overflow: hidden; padding: 8px 12px; gap: 5px;\n}\n.section-label { font-size: 9px; color: var(--text1); text-transform: uppercase; letter-spacing: 0.1em; align-self: flex-start; }\n.data-row { display: flex; width: 100%; justify-content: space-between; align-items: baseline; gap: 8px; }\n.data-label { font-size: 10px; color: var(--text1); white-space: nowrap; }\n.data-value { font-size: 16px; font-weight: bold; color: var(--text0); text-align: right; min-width: 48px; transition: color 0.3s; }\n.divider { width: 100%; height: 1px; background: var(--border); flex-shrink: 0; }\n#headroom-wrap { width: 100%; }\n#headroom-bar-bg { width: 100%; height: 5px; background: var(--dim); border-radius: 3px; overflow: hidden; margin-top: 2px; }\n#headroom-bar-fill { height: 100%; border-radius: 3px; background: var(--green); transition: width 0.5s ease, background 0.3s; }\n#status-text { font-size: 10px; color: var(--text1); text-align: center; min-height: 12px; transition: color 0.3s; }\n.green { color: var(--green) !important; }\n.amber { color: var(--amber) !important; }\n.red { color: var(--red) !important; }\n#footer { font-size: 9px; color: #1a2d42; margin-top: 1px; }", - - "js": "var VAR_BATTERY = 'SYS_STATUS/battery_remaining';\nvar VAR_BUDGET = 'rov_return_budget';\nvar WARN = 15, CRIT = 5, POLL_MS = 1000;\nvar battValEl = document.getElementById('batt-val');\nvar budgetValEl = document.getElementById('budget-val');\nvar headroomValEl = document.getElementById('headroom-val');\nvar headroomFillEl = document.getElementById('headroom-bar-fill');\nvar statusTextEl = document.getElementById('status-text');\nvar footerEl = document.getElementById('footer');\n\nfunction setClass(el, cls) { el.classList.remove('green','amber','red'); if(cls) el.classList.add(cls); }\n\nfunction render(batt, budget, budgetLive) {\n batt = Math.round(batt);\n budget = Math.round(budget);\n var margin = batt - budget;\n battValEl.textContent = batt + '%';\n setClass(battValEl, batt > 40 ? 'green' : batt > 20 ? 'amber' : 'red');\n budgetValEl.textContent = budget + '%';\n headroomValEl.textContent = margin + '%';\n var barPct = batt > 0 ? Math.min(100, Math.max(0, (margin / batt) * 100)) : 0;\n headroomFillEl.style.width = barPct + '%';\n var sev, msg;\n if (margin < CRIT) { sev = 'red'; msg = '\u26a0 CRITICAL \u2014 insufficient return budget'; }\n else if (margin < WARN) { sev = 'amber'; msg = 'Low headroom \u2014 consider returning'; }\n else { sev = 'green'; msg = 'Sufficient return headroom'; }\n var colors = {green:'var(--green)', amber:'var(--amber)', red:'var(--red)'};\n headroomFillEl.style.background = colors[sev];\n setClass(headroomValEl, sev); setClass(statusTextEl, sev);\n statusTextEl.textContent = msg;\n footerEl.textContent = budgetLive\n ? 'Updated ' + new Date().toLocaleTimeString()\n : 'Updated ' + new Date().toLocaleTimeString() + ' (budget: FastAPI pending)';\n}\n\nfunction poll() {\n try {\n if (typeof window.cockpit === 'undefined' || typeof window.cockpit.getDataLakeValue !== 'function') {\n statusTextEl.textContent = 'API not ready'; return;\n }\n var battRaw = window.cockpit.getDataLakeValue(VAR_BATTERY);\n if (battRaw === null || battRaw === undefined) { statusTextEl.textContent = 'Waiting for battery data\u2026'; return; }\n var batt = parseInt(battRaw, 10);\n if (batt === -1) { statusTextEl.textContent = 'Battery % not reported by vehicle'; battValEl.textContent='??%'; return; }\n var budgetRaw = window.cockpit.getDataLakeValue(VAR_BUDGET);\n var budgetLive = budgetRaw !== null && budgetRaw !== undefined;\n render(batt, budgetLive ? parseFloat(budgetRaw) : 0, budgetLive);\n } catch(err) { statusTextEl.textContent='Poll error'; console.error('[Budget]',err); }\n}\nsetTimeout(poll,300); setInterval(poll,POLL_MS);" -}