Add battery voltage reading to web UI, apply fixed VBAT multiplier, closes #3

This commit is contained in:
2026-03-02 21:01:58 +01:00
parent c41a2932ba
commit 6ecae74483
6 changed files with 43 additions and 8 deletions
+24 -4
View File
@@ -14,7 +14,8 @@ const config = { sensitivity:600, deadZone:0.06, accelStrength:0.08, curve:0, ax
tapThreshold:12, tapAction:0, tapKey:0, tapMod:0 };
let device=null, server=null, chars={}, userDisconnected=false;
let currentChargeStatus=0, currentBattPct=null;
let currentChargeStatus=0, currentBattPct=null, currentBattVoltage=null;
let advancedMode = localStorage.getItem('advanced') === 'true';
// ── GATT write queue (prevents "operation already in progress") ───────────────
// Serialises all GATT writes. Features:
@@ -351,10 +352,11 @@ async function doReset() {
}
// ── Telemetry ────────────────────────────────────────────────────────────────
// TelemetryPacket (24 bytes LE):
// TelemetryPacket (28 bytes LE — backwards compatible with 24-byte v3.3):
// uint32 uptime [0], uint32 leftClicks [4], uint32 rightClicks [8]
// float temp [12], float biasRms [16]
// uint16 recalCount [20], uint8 chargeStatus [22], uint8 pad [23]
// float battVoltage [24] (new in v3.4, absent on older firmware)
function parseTelemetry(dv) {
let view;
try {
@@ -364,11 +366,11 @@ function parseTelemetry(dv) {
if (view.byteLength < 24) {
const bytes = new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
const hex = Array.from(bytes).map(b=>b.toString(16).padStart(2,'0')).join(' ');
log(`TELEM: expected 24B, got ${view.byteLength}B — MTU too small? raw: ${hex}`,'err');
log(`TELEM: expected 24-28B, got ${view.byteLength}B — MTU too small? raw: ${hex}`,'err');
return;
}
let uptime, leftClicks, rightClicks, temp, biasRms, recalCount, chargeStatus;
let uptime, leftClicks, rightClicks, temp, biasRms, recalCount, chargeStatus, battVoltage=null;
try {
uptime = view.getUint32(0, true);
leftClicks = view.getUint32(4, true);
@@ -377,6 +379,7 @@ function parseTelemetry(dv) {
biasRms = view.getFloat32(16,true);
recalCount = view.getUint16(20, true);
chargeStatus= view.getUint8(22);
if (view.byteLength >= 28) battVoltage = view.getFloat32(24, true);
} catch(e) { log(`parseTelemetry: parse error at offset — ${e.message}`,'err'); return; }
document.getElementById('telTemp').textContent = temp.toFixed(1)+'°';
@@ -393,6 +396,11 @@ function parseTelemetry(dv) {
currentChargeStatus = chargeStatus;
updateChargeUI();
}
if (battVoltage !== null) {
currentBattVoltage = battVoltage;
document.getElementById('ciVolt').textContent = battVoltage.toFixed(2) + 'V';
}
}
function formatUptime(s) {
const h=Math.floor(s/3600), m=Math.floor((s%3600)/60), ss=s%60;
@@ -427,6 +435,15 @@ function updateChargeUI() {
if (currentBattPct!==null) updateBatteryBar(currentBattPct, currentChargeStatus);
}
// ── Advanced toggle ───────────────────────────────────────────────────────
function toggleAdvanced(on) {
advancedMode = on;
localStorage.setItem('advanced', on);
document.getElementById('ciVoltItem').style.display = on ? '' : 'none';
// Switch charge-info grid between 3 and 4 columns
document.getElementById('chargeInfo').style.gridTemplateColumns = on ? '1fr 1fr 1fr 1fr' : '1fr 1fr 1fr';
}
// ── Param display ─────────────────────────────────────────────────────────────
function updateDisplay(key, val) {
const map = {
@@ -815,6 +832,9 @@ function applyTheme(t) {
themeIdx = Math.max(0, THEMES.indexOf(saved));
applyTheme(saved);
initOrientViewer();
// Restore advanced toggle state
document.getElementById('advancedToggle').checked = advancedMode;
if (advancedMode) toggleAdvanced(true);
})();
if (!navigator.bluetooth) {