saltylab-firmware/ui/diagnostics_panel.html
sl-mechanical a2c554c232 cleanup: remove all Mamba/F722S/STM32F722 refs — replace with ESP32-S3 BALANCE/IO
- docs/: rewrite AGENTS.md, wiring-diagram.md (SAUL-TEE arch); update
  SALTYLAB.md, FACE_LCD_ANIMATION.md, board-viz.html, SALTYLAB-DETAILED refs
- cad/: dimensions.scad FC params → ESP32-S3 BALANCE params
- chassis/: ASSEMBLY.md, BOM.md, ip54_BOM.md, *.scad — FC_MOUNT_SPACING/
  FC_PITCH → TBD ESP32-S3; Drone FC → MCU mount throughout
- CLAUDE.md, TEAM.md: project desc → SAUL-TEE; hardware table → ESP32-S3/VESC
- USB_CDC_BUG.md: marked ARCHIVED (legacy STM32 era)
- AUTONOMOUS_ARMING.md: USB CDC → inter-board UART (ESP32-S3 BALANCE)
- projects/saltybot/SLAM-SETUP-PLAN.md: FC/STM32F722 → BALANCE/CAN
- jetson/docs/pinout.md, power-budget.md, README.md: STM32 bridge → CAN bridge
- jetson/config/RECOVERY_BEHAVIORS.md: FC+Hoverboard → BALANCE+VESC
- jetson/ros2_ws: stm32_protocol.py → esp32_protocol.py,
  stm32_cmd_node.py → esp32_cmd_node.py,
  mamba_protocol.py → balance_protocol.py; can_bridge_node imports updated
- scripts/flash_firmware.py: DFU/STM32 → pio run -t upload
- src/ include/: ARCHIVED headers added (legacy code preserved)
- test/: ARCHIVED notices; STM32F722 comments marked LEGACY
- ui/diagnostics_panel.html: Board/STM32 → ESP32-S3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 09:06:09 -04:00

268 lines
11 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<title>Saltybot — System Diagnostics</title>
<link rel="stylesheet" href="diagnostics_panel.css">
<script src="https://cdn.jsdelivr.net/npm/roslib@1.3.0/build/roslib.min.js"></script>
</head>
<body>
<!-- ── Header ── -->
<div id="header">
<div class="logo">⚡ SALTYBOT — DIAGNOSTICS</div>
<div id="conn-bar">
<div id="conn-dot"></div>
<input id="ws-input" type="text" value="ws://localhost:9090" placeholder="ws://robot-ip:9090" />
<button id="btn-connect" class="hdr-btn">CONNECT</button>
<span id="conn-label" style="color:#4b5563;font-size:10px">Not connected</span>
</div>
<div id="refresh-info">
<div id="refresh-dot"></div>
<span>auto 2 Hz</span>
</div>
</div>
<!-- ── System status bar ── -->
<div id="status-bar">
<span style="color:#6b7280;font-size:10px">SYSTEM</span>
<span class="sys-badge badge-stale" id="system-badge">STALE</span>
<span style="color:#4b5563"></span>
<span style="color:#6b7280;font-size:10px">BATTERY</span>
<span class="sys-badge badge-stale" id="batt-badge"></span>
<span style="color:#4b5563"></span>
<span style="color:#6b7280;font-size:10px">THERMAL</span>
<span class="sys-badge badge-stale" id="temp-badge"></span>
<span style="color:#4b5563"></span>
<span style="color:#6b7280;font-size:10px">NETWORK</span>
<span class="sys-badge badge-stale" id="net-badge"></span>
<span id="last-update">Awaiting data…</span>
</div>
<!-- ── Dashboard grid ── -->
<div id="dashboard">
<!-- ╔═══════════════════ BATTERY ═══════════════════╗ -->
<div class="card span2">
<div class="card-title">
BATTERY — 4S LiPo (12.016.8 V)
<span class="badge badge-stale" id="batt-badge-2" style="font-size:9px"></span>
</div>
<!-- Big readout row -->
<div style="display:flex;gap:16px;align-items:flex-end;flex-wrap:wrap">
<div>
<div style="font-size:9px;color:#6b7280;margin-bottom:2px">VOLTAGE</div>
<div class="big-metric">
<span class="big-num" id="batt-voltage" style="color:#22c55e"></span>
</div>
</div>
<div>
<div style="font-size:9px;color:#6b7280;margin-bottom:2px">SOC</div>
<div class="big-metric">
<span class="big-num" id="batt-soc" style="color:#22c55e"></span>
</div>
</div>
<div>
<div style="font-size:9px;color:#6b7280;margin-bottom:2px">CURRENT</div>
<div class="big-metric">
<span class="big-num" id="batt-current" style="color:#06b6d4;font-size:20px"></span>
</div>
</div>
</div>
<!-- Gauge bars -->
<div class="gauge-row">
<div class="gauge-label-row">
<span class="gauge-label">Voltage</span>
<span class="gauge-value" id="batt-voltage-2" style="color:#6b7280">12.016.8 V</span>
</div>
<div class="gauge-track"><div class="gauge-fill" id="batt-volt-bar" style="width:0%"></div></div>
</div>
<div class="gauge-row">
<div class="gauge-label-row">
<span class="gauge-label">State of Charge</span>
<span class="gauge-value" style="color:#6b7280">0100%</span>
</div>
<div class="gauge-track"><div class="gauge-fill" id="batt-soc-bar" style="width:0%"></div></div>
</div>
<!-- Sparkline history -->
<div>
<div style="font-size:9px;color:#6b7280;margin-bottom:4px">VOLTAGE HISTORY (last 2 min)</div>
<canvas id="batt-sparkline" height="56"></canvas>
</div>
</div>
<!-- ╔═══════════════════ TEMPERATURES ═══════════════════╗ -->
<div class="card">
<div class="card-title">TEMPERATURES</div>
<div class="temp-grid">
<div class="temp-box" id="cpu-temp-box">
<div class="temp-label">CPU (Jetson)</div>
<div class="temp-value" id="cpu-temp-val"></div>
<div class="temp-bar-track"><div class="temp-bar-fill" id="cpu-temp-bar" style="width:0%"></div></div>
</div>
<div class="temp-box" id="gpu-temp-box">
<div class="temp-label">GPU (Jetson)</div>
<div class="temp-value" id="gpu-temp-val"></div>
<div class="temp-bar-track"><div class="temp-bar-fill" id="gpu-temp-bar" style="width:0%"></div></div>
</div>
<div class="temp-box" id="board-temp-box">
<div class="temp-label">ESP32-S3</div>
<div class="temp-value" id="board-temp-val"></div>
<div class="temp-bar-track"><div class="temp-bar-fill" id="board-temp-bar" style="width:0%"></div></div>
</div>
<div class="temp-box" id="motor-temp-l-box">
<div class="temp-label">Motor L</div>
<div class="temp-value" id="motor-temp-l-val"></div>
<div class="temp-bar-track"><div class="temp-bar-fill" id="motor-temp-l-bar" style="width:0%"></div></div>
</div>
<!-- spacer to keep 2-col grid balanced if motor-temp-r is alone -->
<div class="temp-box" id="motor-temp-r-box">
<div class="temp-label">Motor R</div>
<div class="temp-value" id="motor-temp-r-val"></div>
<div class="temp-bar-track"><div class="temp-bar-fill" id="motor-temp-r-bar" style="width:0%"></div></div>
</div>
</div>
<div style="font-size:9px;color:#374151">
Zones: &lt;60°C green · 6075°C amber · &gt;75°C red
</div>
</div>
<!-- ╔═══════════════════ MOTOR CURRENT ═══════════════════╗ -->
<div class="card">
<div class="card-title">MOTOR CURRENT &amp; CMD</div>
<div class="motor-grid">
<div class="motor-box">
<div class="motor-label">LEFT WHEEL</div>
<div style="font-size:20px;font-weight:bold;font-family:monospace" id="motor-cur-l"></div>
<div class="gauge-track" style="margin-top:4px">
<div class="gauge-fill" id="motor-bar-l" style="width:0%"></div>
</div>
<div style="font-size:9px;color:#4b5563;margin-top:4px">
CMD: <span id="motor-cmd-l" style="color:#6b7280"></span>
</div>
</div>
<div class="motor-box">
<div class="motor-label">RIGHT WHEEL</div>
<div style="font-size:20px;font-weight:bold;font-family:monospace" id="motor-cur-r"></div>
<div class="gauge-track" style="margin-top:4px">
<div class="gauge-fill" id="motor-bar-r" style="width:0%"></div>
</div>
<div style="font-size:9px;color:#4b5563;margin-top:4px">
CMD: <span id="motor-cmd-r" style="color:#6b7280"></span>
</div>
</div>
</div>
<div style="font-size:10px;color:#6b7280">
Balance state: <span id="balance-state" style="color:#9ca3af;font-family:monospace"></span>
</div>
<div style="font-size:9px;color:#374151">Thresholds: warn 8A · crit 12A</div>
</div>
<!-- ╔═══════════════════ MEMORY / DISK ═══════════════════╗ -->
<div class="card">
<div class="card-title">RESOURCES</div>
<div class="gauge-row">
<div class="gauge-label-row">
<span class="gauge-label">RAM</span>
<span class="gauge-value" id="ram-val" style="color:#9ca3af"></span>
</div>
<div class="gauge-track"><div class="gauge-fill" id="ram-bar" style="width:0%"></div></div>
</div>
<div class="gauge-row">
<div class="gauge-label-row">
<span class="gauge-label">GPU Memory</span>
<span class="gauge-value" id="gpu-val" style="color:#9ca3af"></span>
</div>
<div class="gauge-track"><div class="gauge-fill" id="gpu-bar" style="width:0%"></div></div>
</div>
<div class="gauge-row">
<div class="gauge-label-row">
<span class="gauge-label">Disk</span>
<span class="gauge-value" id="disk-val" style="color:#9ca3af"></span>
</div>
<div class="gauge-track"><div class="gauge-fill" id="disk-bar" style="width:0%"></div></div>
</div>
<div style="font-size:9px;color:#374151">Warn ≥80% · Critical ≥95%</div>
</div>
<!-- ╔═══════════════════ WIFI / LATENCY ═══════════════════╗ -->
<div class="card">
<div class="card-title">NETWORK</div>
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap">
<div id="rssi-bars" class="rssi-bars"></div>
<div>
<div style="font-size:9px;color:#6b7280">RSSI</div>
<div style="font-size:20px;font-weight:bold;font-family:monospace" id="rssi-val"></div>
<div style="font-size:9px" id="rssi-label" style="color:#6b7280"></div>
</div>
</div>
<div class="gauge-row">
<div class="gauge-label-row">
<span class="gauge-label">Rosbridge Latency</span>
<span class="gauge-value" id="latency-val" style="color:#9ca3af"></span>
</div>
</div>
<!-- MQTT status -->
<div style="margin-top:4px;padding-top:8px;border-top:1px solid #0c2a3a">
<div style="font-size:9px;color:#6b7280;margin-bottom:4px">MQTT BROKER</div>
<div class="mqtt-status">
<div class="mqtt-dot" id="mqtt-dot"></div>
<span id="mqtt-label" style="color:#6b7280">No data</span>
</div>
<div style="font-size:9px;color:#374151;margin-top:4px">
Via /diagnostics KeyValue: mqtt_connected
</div>
</div>
</div>
<!-- ╔═══════════════════ ROS2 NODE HEALTH ═══════════════════╗ -->
<div class="card span3">
<div class="card-title">
ROS2 NODE HEALTH — /diagnostics
<span style="font-size:9px;color:#4b5563" id="node-count">0 nodes</span>
</div>
<div id="node-list">
<div style="color:#374151;font-size:10px;text-align:center;padding:12px">
Waiting for /diagnostics data…
</div>
</div>
</div>
</div>
<!-- ── Footer ── -->
<div id="footer">
<span>rosbridge: <code id="footer-ws">ws://localhost:9090</code></span>
<span>diagnostics dashboard — issue #562 · auto 2Hz</span>
</div>
<script src="diagnostics_panel.js"></script>
<script>
// Sync footer WS URL
document.getElementById('ws-input').addEventListener('input', (e) => {
document.getElementById('footer-ws').textContent = e.target.value;
});
// Keep node count updated after render
const origRenderNodes = window.renderNodes;
const nodeCountEl = document.getElementById('node-count');
const _origOnDiag = window.onDiagnostics;
// Node count updates via MutationObserver on the node-list div
const nl = document.getElementById('node-list');
if (nl) {
new MutationObserver(() => {
const rows = nl.querySelectorAll('.node-row');
if (nodeCountEl) nodeCountEl.textContent = rows.length + ' node' + (rows.length !== 1 ? 's' : '');
}).observe(nl, { childList: true, subtree: false });
}
</script>
</body>
</html>