feat(ble): wake-up Xiaoxiang BMS — read inicial + 5A x4 v1.10.11
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run

Confirmado: BMS responde ao app oficial Xiaoxiang. Problema é técnica
de inicialização não implementada na nossa abordagem.

Adicionado wake-up sequence ANTES do probe de protocolos:
1. ble.read na notify char (acorda stack BLE)
2. delay 300ms
3. write 0x5A x4 (handshake hello observado em alguns Xiaoxiang)
4. delay 1500ms (BMS processa wake)
5. probe normal de protocolos

Cada step protegido por try/catch + timeout 2s — não trava loop.
Logs detalhados pra ver onde falha se acontecer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
PontualTech / Karlão 2026-04-29 08:21:41 -03:00
parent 24d0162397
commit 330d5aaa62
5 changed files with 44 additions and 10 deletions

View file

@ -6122,8 +6122,25 @@ async function bmsProbeAndAttach(deviceId,deviceName){
else if(first===0xA5)bmsHandleDaly(deviceId,dv,deviceName); // Daly
});
await ble.startNotifications({deviceId,service:foundService,characteristic:notifyChar});
setBleDiag('Notify ativo · aguardando 800ms...','ok');
await new Promise(r=>setTimeout(r,800));
setBleDiag('Notify ativo · iniciando wake sequence...','ok');
await new Promise(r=>setTimeout(r,500));
// Wake-up sequence (técnica Xiaoxiang): read inicial + wake bytes
try{
await ble.read({deviceId,service:foundService,characteristic:notifyChar});
setBleDiag('Read inicial OK (acorda stack)','info');
}catch(e){setBleDiag('Read inicial skip: '+(e.message||'?'),'info')}
await new Promise(r=>setTimeout(r,300));
// Wake bytes 5A x4 (algumas firmwares Xiaoxiang)
try{
const useWnr=writeOnlyWnr;
const fn=useWnr?'writeWithoutResponse':'write';
const wakePromise=ble[fn]({deviceId,service:foundService,characteristic:writeChar,value:bytesToBase64([0x5A,0x5A,0x5A,0x5A])});
const wakeTimeout=new Promise((_,rej)=>setTimeout(()=>rej(new Error('wake timeout')),2000));
await Promise.race([wakePromise,wakeTimeout]);
setBleDiag('Wake 5A x4 enviado','info');
}catch(e){setBleDiag('Wake skip: '+(e.message||'?'),'info')}
await new Promise(r=>setTimeout(r,1500));
setBleDiag('Iniciando probe de protocolos...','ok');
// Salva config no device pra reuso
const dev=state.btDevices?.find(d=>d.id===deviceId);
if(dev){
@ -6352,7 +6369,7 @@ async function removeBluetoothDevice(id){
renderBluetoothCard();
}
const APP_VERSION='1.10.10';
const APP_VERSION='1.10.11';
function renderBluetoothCard(){
const el=document.getElementById('bt-list');
const supportEl=document.getElementById('bt-support');

View file

@ -7,8 +7,8 @@ android {
applicationId "br.com.pontualtech.shivao"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 26
versionName "1.10.10"
versionCode 27
versionName "1.10.11"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.

View file

@ -1,6 +1,6 @@
{
"name": "shivao-mobile",
"version": "1.10.10",
"version": "1.10.11",
"description": "Shivao app nativo (Capacitor wrapper Android/iOS)",
"main": "index.js",
"type": "module",

View file

@ -6122,8 +6122,25 @@ async function bmsProbeAndAttach(deviceId,deviceName){
else if(first===0xA5)bmsHandleDaly(deviceId,dv,deviceName); // Daly
});
await ble.startNotifications({deviceId,service:foundService,characteristic:notifyChar});
setBleDiag('Notify ativo · aguardando 800ms...','ok');
await new Promise(r=>setTimeout(r,800));
setBleDiag('Notify ativo · iniciando wake sequence...','ok');
await new Promise(r=>setTimeout(r,500));
// Wake-up sequence (técnica Xiaoxiang): read inicial + wake bytes
try{
await ble.read({deviceId,service:foundService,characteristic:notifyChar});
setBleDiag('Read inicial OK (acorda stack)','info');
}catch(e){setBleDiag('Read inicial skip: '+(e.message||'?'),'info')}
await new Promise(r=>setTimeout(r,300));
// Wake bytes 5A x4 (algumas firmwares Xiaoxiang)
try{
const useWnr=writeOnlyWnr;
const fn=useWnr?'writeWithoutResponse':'write';
const wakePromise=ble[fn]({deviceId,service:foundService,characteristic:writeChar,value:bytesToBase64([0x5A,0x5A,0x5A,0x5A])});
const wakeTimeout=new Promise((_,rej)=>setTimeout(()=>rej(new Error('wake timeout')),2000));
await Promise.race([wakePromise,wakeTimeout]);
setBleDiag('Wake 5A x4 enviado','info');
}catch(e){setBleDiag('Wake skip: '+(e.message||'?'),'info')}
await new Promise(r=>setTimeout(r,1500));
setBleDiag('Iniciando probe de protocolos...','ok');
// Salva config no device pra reuso
const dev=state.btDevices?.find(d=>d.id===deviceId);
if(dev){
@ -6352,7 +6369,7 @@ async function removeBluetoothDevice(id){
renderBluetoothCard();
}
const APP_VERSION='1.10.10';
const APP_VERSION='1.10.11';
function renderBluetoothCard(){
const el=document.getElementById('bt-list');
const supportEl=document.getElementById('bt-support');

View file

@ -413,7 +413,7 @@ app.get('/.well-known/assetlinks.json', (req, res) => {
});
// Atalho: /apk redireciona pra última APK release no Forgejo
const LATEST_APK_URL = 'https://git.pontualtech.work/karlao/shivao-projeto/releases/download/v1.10.10/Shivao-v1.10.10.apk';
const LATEST_APK_URL = 'https://git.pontualtech.work/karlao/shivao-projeto/releases/download/v1.10.11/Shivao-v1.10.11.apk';
app.get('/apk', (req, res) => res.redirect(302, LATEST_APK_URL));
// Página A4 imprimível com QR Code + instruções (cola no barco/marina)