fix(ble): dispatcher rotea chunks JBD de continuação v1.10.15
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run

🎉 BMS RESPONDEU! Log v1.10.14 mostrou 3 chunks chegando do BMS
do Karlão:
- Chunk 1 (20b): dd 03 00 22 05 2b 02 8a... (header JBD + dados)
- Chunk 2 (20b): 00 00 d0 15 03 04 01 0b b7... (continuação)
- Chunk 3 (1b): 77 (end-of-frame)

Decoded: 13.23V (4S LiFePO4), +6.50A carregando, 21% SoC, 175 ciclos,
4 células, 27°C. PROTOCOLO JBD CORRETO.

Bug do parser: dispatcher só chamava bmsHandleChunk se primeiro byte
do chunk atual era 0xDD. Chunks 2 e 3 começam com 0x00 e 0x77 — não
roteados → reassembly nunca completou → dev.bms.voltage ficou null →
bmsTryProtocols viu '✗ JBD-0x03 sem RX'.

Fix em ambos os paths (Web Bluetooth + Capacitor):
- Se _bmsBuffers.has(deviceId), é continuação → roteia direto pra
  bmsHandleChunk
- Buffer vazio: primeiro byte determina protocolo

Próxima rodada deve mostrar 'BMS lido · 13.23V · 6.50A · 21%...' +
dashboard cheio.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
PontualTech / Karlão 2026-04-29 09:02:10 -03:00
parent 4cf670ae76
commit 56ddca53a4
3 changed files with 27 additions and 5 deletions

View file

@ -6091,6 +6091,12 @@ async function bmsProbeWebBluetooth(deviceId,deviceName){
const dv=ev.target.value; const dv=ev.target.value;
const hex=Array.from(new Uint8Array(dv.buffer)).map(b=>b.toString(16).padStart(2,'0')).join(' '); const hex=Array.from(new Uint8Array(dv.buffer)).map(b=>b.toString(16).padStart(2,'0')).join(' ');
setBleDiag(`← RX ${dv.byteLength}b: ${hex.slice(0,100)}${hex.length>100?'...':''}`,'ok'); setBleDiag(`← RX ${dv.byteLength}b: ${hex.slice(0,100)}${hex.length>100?'...':''}`,'ok');
// Se há buffer pendente JBD, é chunk de continuação — roteia sempre
if(_bmsBuffers.has(deviceId)){
bmsHandleChunk(deviceId,dv,deviceName);
return;
}
// Buffer vazio: primeiro byte determina protocolo (início de novo pacote)
const first=new Uint8Array(dv.buffer)[0]; const first=new Uint8Array(dv.buffer)[0];
if(first===0xDD)bmsHandleChunk(deviceId,dv,deviceName); if(first===0xDD)bmsHandleChunk(deviceId,dv,deviceName);
else if(first===0xAA)bmsHandleJK(deviceId,dv,deviceName); else if(first===0xAA)bmsHandleJK(deviceId,dv,deviceName);
@ -6192,7 +6198,12 @@ async function bmsProbeAndAttach(deviceId,deviceName){
const dv=parseDataView(ev.value); const dv=parseDataView(ev.value);
const hex=Array.from(new Uint8Array(dv.buffer)).map(b=>b.toString(16).padStart(2,'0')).join(' '); const hex=Array.from(new Uint8Array(dv.buffer)).map(b=>b.toString(16).padStart(2,'0')).join(' ');
setBleDiag('← RX '+dv.byteLength+'b: '+hex.slice(0,100)+(hex.length>100?'...':''),'ok'); setBleDiag('← RX '+dv.byteLength+'b: '+hex.slice(0,100)+(hex.length>100?'...':''),'ok');
// Detecta protocolo por byte de início // Se buffer JBD pendente, é continuação — roteia sempre
if(_bmsBuffers.has(deviceId)){
bmsHandleChunk(deviceId,dv,deviceName);
return;
}
// Detecta protocolo por byte de início (novo pacote)
const first=new Uint8Array(dv.buffer)[0]; const first=new Uint8Array(dv.buffer)[0];
if(first===0xDD)bmsHandleChunk(deviceId,dv,deviceName); // JBD if(first===0xDD)bmsHandleChunk(deviceId,dv,deviceName); // JBD
else if(first===0xAA)bmsHandleJK(deviceId,dv,deviceName); // JK BMS else if(first===0xAA)bmsHandleJK(deviceId,dv,deviceName); // JK BMS
@ -6446,7 +6457,7 @@ async function removeBluetoothDevice(id){
renderBluetoothCard(); renderBluetoothCard();
} }
const APP_VERSION='1.10.14'; const APP_VERSION='1.10.15';
function renderBluetoothCard(){ function renderBluetoothCard(){
const el=document.getElementById('bt-list'); const el=document.getElementById('bt-list');
const supportEl=document.getElementById('bt-support'); const supportEl=document.getElementById('bt-support');

View file

@ -6091,6 +6091,12 @@ async function bmsProbeWebBluetooth(deviceId,deviceName){
const dv=ev.target.value; const dv=ev.target.value;
const hex=Array.from(new Uint8Array(dv.buffer)).map(b=>b.toString(16).padStart(2,'0')).join(' '); const hex=Array.from(new Uint8Array(dv.buffer)).map(b=>b.toString(16).padStart(2,'0')).join(' ');
setBleDiag(`← RX ${dv.byteLength}b: ${hex.slice(0,100)}${hex.length>100?'...':''}`,'ok'); setBleDiag(`← RX ${dv.byteLength}b: ${hex.slice(0,100)}${hex.length>100?'...':''}`,'ok');
// Se há buffer pendente JBD, é chunk de continuação — roteia sempre
if(_bmsBuffers.has(deviceId)){
bmsHandleChunk(deviceId,dv,deviceName);
return;
}
// Buffer vazio: primeiro byte determina protocolo (início de novo pacote)
const first=new Uint8Array(dv.buffer)[0]; const first=new Uint8Array(dv.buffer)[0];
if(first===0xDD)bmsHandleChunk(deviceId,dv,deviceName); if(first===0xDD)bmsHandleChunk(deviceId,dv,deviceName);
else if(first===0xAA)bmsHandleJK(deviceId,dv,deviceName); else if(first===0xAA)bmsHandleJK(deviceId,dv,deviceName);
@ -6192,7 +6198,12 @@ async function bmsProbeAndAttach(deviceId,deviceName){
const dv=parseDataView(ev.value); const dv=parseDataView(ev.value);
const hex=Array.from(new Uint8Array(dv.buffer)).map(b=>b.toString(16).padStart(2,'0')).join(' '); const hex=Array.from(new Uint8Array(dv.buffer)).map(b=>b.toString(16).padStart(2,'0')).join(' ');
setBleDiag('← RX '+dv.byteLength+'b: '+hex.slice(0,100)+(hex.length>100?'...':''),'ok'); setBleDiag('← RX '+dv.byteLength+'b: '+hex.slice(0,100)+(hex.length>100?'...':''),'ok');
// Detecta protocolo por byte de início // Se buffer JBD pendente, é continuação — roteia sempre
if(_bmsBuffers.has(deviceId)){
bmsHandleChunk(deviceId,dv,deviceName);
return;
}
// Detecta protocolo por byte de início (novo pacote)
const first=new Uint8Array(dv.buffer)[0]; const first=new Uint8Array(dv.buffer)[0];
if(first===0xDD)bmsHandleChunk(deviceId,dv,deviceName); // JBD if(first===0xDD)bmsHandleChunk(deviceId,dv,deviceName); // JBD
else if(first===0xAA)bmsHandleJK(deviceId,dv,deviceName); // JK BMS else if(first===0xAA)bmsHandleJK(deviceId,dv,deviceName); // JK BMS
@ -6446,7 +6457,7 @@ async function removeBluetoothDevice(id){
renderBluetoothCard(); renderBluetoothCard();
} }
const APP_VERSION='1.10.14'; const APP_VERSION='1.10.15';
function renderBluetoothCard(){ function renderBluetoothCard(){
const el=document.getElementById('bt-list'); const el=document.getElementById('bt-list');
const supportEl=document.getElementById('bt-support'); const supportEl=document.getElementById('bt-support');

View file

@ -1,7 +1,7 @@
// Shivao Service Worker — offline real // Shivao Service Worker — offline real
// Estratégia: shell precachado, tiles cache-first, windy network-first, /api passa direto. // Estratégia: shell precachado, tiles cache-first, windy network-first, /api passa direto.
// Versão usada nos cache names — bumpa essa string pra invalidar caches antigos em deploys. // Versão usada nos cache names — bumpa essa string pra invalidar caches antigos em deploys.
const VERSION = 'shivao-v1.10.14'; const VERSION = 'shivao-v1.10.15';
const SHELL_CACHE = `shivao-shell-${VERSION}`; const SHELL_CACHE = `shivao-shell-${VERSION}`;
const TILES_CACHE = 'shivao-tiles-v1'; // separado pra não invalidar tiles em update do shell const TILES_CACHE = 'shivao-tiles-v1'; // separado pra não invalidar tiles em update do shell
const WINDY_CACHE = `shivao-windy-${VERSION}`; const WINDY_CACHE = `shivao-windy-${VERSION}`;