fix(ble): write timeout 3s + log entry/exit + loop resiliente v1.10.10
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Log v1.10.9 mostrou que probe parou em '→ TX JBD-0x03' sem testar próximos 3 protocolos (JK, Daly, JBD-wnr). Causa provável: write trava mesmo com WNR no plugin v6. Fix: - bmsWriteCmd com Promise.race + timeout 3s — write nunca trava loop indefinidamente - bmsTryProtocols agora loga '✔ write retornou' e '✗ sem RX em 2.5s' pra distinguir write OK + BMS mudo de write travado - Try/catch interno no write — se falha, continua pro próximo protocolo em vez de abortar loop Próximo log vai mostrar TODOS os 4 protocolos testados — daí saberemos se é hardware mudo OU plugin travando. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e5c62e913f
commit
24d0162397
5 changed files with 36 additions and 18 deletions
|
|
@ -6146,10 +6146,12 @@ async function bmsWriteCmd(deviceId,bytes,withoutResponse){
|
||||||
const ble=window.Capacitor?.Plugins?.BluetoothLe;
|
const ble=window.Capacitor?.Plugins?.BluetoothLe;
|
||||||
const dev=state.btDevices?.find(d=>d.id===deviceId);
|
const dev=state.btDevices?.find(d=>d.id===deviceId);
|
||||||
if(!ble||!dev?.bmsService||!dev?.bmsWriteChar)throw new Error('config BMS ausente');
|
if(!ble||!dev?.bmsService||!dev?.bmsWriteChar)throw new Error('config BMS ausente');
|
||||||
// Se a write char só aceita wnr, força writeWithoutResponse independente do parâmetro
|
|
||||||
const useWnr=withoutResponse||dev.bmsForceWnr;
|
const useWnr=withoutResponse||dev.bmsForceWnr;
|
||||||
const fn=useWnr?'writeWithoutResponse':'write';
|
const fn=useWnr?'writeWithoutResponse':'write';
|
||||||
await ble[fn]({deviceId,service:dev.bmsService,characteristic:dev.bmsWriteChar,value:bytesToBase64(bytes)});
|
// Timeout 3s: plugins/firmware podem travar mesmo com WNR
|
||||||
|
const writePromise=ble[fn]({deviceId,service:dev.bmsService,characteristic:dev.bmsWriteChar,value:bytesToBase64(bytes)});
|
||||||
|
const timeoutPromise=new Promise((_,rej)=>setTimeout(()=>rej(new Error('write timeout 3s')),3000));
|
||||||
|
await Promise.race([writePromise,timeoutPromise]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function bmsTryProtocols(deviceId){
|
async function bmsTryProtocols(deviceId){
|
||||||
|
|
@ -6162,18 +6164,25 @@ async function bmsTryProtocols(deviceId){
|
||||||
for(const p of PROTOCOLS){
|
for(const p of PROTOCOLS){
|
||||||
try{
|
try{
|
||||||
setBleDiag(`→ TX ${p.name}: ${p.bytes.map(b=>b.toString(16).padStart(2,'0')).join(' ').slice(0,40)}`,'info');
|
setBleDiag(`→ TX ${p.name}: ${p.bytes.map(b=>b.toString(16).padStart(2,'0')).join(' ').slice(0,40)}`,'info');
|
||||||
|
try{
|
||||||
await bmsWriteCmd(deviceId,p.bytes,p.wnr);
|
await bmsWriteCmd(deviceId,p.bytes,p.wnr);
|
||||||
// Espera 2s pra ver se gerou RX
|
setBleDiag(`✔ write ${p.name} retornou`,'info');
|
||||||
|
}catch(we){
|
||||||
|
setBleDiag(`✗ write ${p.name} erro: ${we.message||we.errorMessage}`,'warn');
|
||||||
|
// Continue pro próximo protocolo mesmo se write falhar
|
||||||
|
}
|
||||||
|
// Aguarda RX por 2.5s
|
||||||
await new Promise(r=>setTimeout(r,2500));
|
await new Promise(r=>setTimeout(r,2500));
|
||||||
const dev=state.btDevices?.find(d=>d.id===deviceId);
|
const dev=state.btDevices?.find(d=>d.id===deviceId);
|
||||||
if(dev?.bms?.voltage||dev?._lastRxAt){
|
if(dev?.bms?.voltage||dev?._lastRxAt){
|
||||||
setBleDiag(`✓ ${p.name} respondeu!`,'ok');
|
setBleDiag(`✓ ${p.name} respondeu!`,'ok');
|
||||||
// Configura poll periódico com este protocolo
|
|
||||||
if(dev)dev.bmsProtocol=p.name;
|
if(dev)dev.bmsProtocol=p.name;
|
||||||
setInterval(async()=>{try{await bmsWriteCmd(deviceId,p.bytes,p.wnr)}catch{}},30000);
|
setInterval(async()=>{try{await bmsWriteCmd(deviceId,p.bytes,p.wnr)}catch{}},30000);
|
||||||
return true;
|
return true;
|
||||||
|
}else{
|
||||||
|
setBleDiag(`✗ ${p.name} sem RX em 2.5s`,'info');
|
||||||
}
|
}
|
||||||
}catch(e){setBleDiag(`${p.name} falhou: ${e.message||e.errorMessage}`,'warn')}
|
}catch(e){setBleDiag(`${p.name} loop erro: ${e.message||e.errorMessage}`,'warn')}
|
||||||
}
|
}
|
||||||
setBleDiag('⚠ Nenhum protocolo funcionou. BMS pode usar firmware proprietário não documentado.','err');
|
setBleDiag('⚠ Nenhum protocolo funcionou. BMS pode usar firmware proprietário não documentado.','err');
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -6343,7 +6352,7 @@ async function removeBluetoothDevice(id){
|
||||||
renderBluetoothCard();
|
renderBluetoothCard();
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP_VERSION='1.10.9';
|
const APP_VERSION='1.10.10';
|
||||||
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');
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ android {
|
||||||
applicationId "br.com.pontualtech.shivao"
|
applicationId "br.com.pontualtech.shivao"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 25
|
versionCode 26
|
||||||
versionName "1.10.9"
|
versionName "1.10.10"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "shivao-mobile",
|
"name": "shivao-mobile",
|
||||||
"version": "1.10.9",
|
"version": "1.10.10",
|
||||||
"description": "Shivao app nativo (Capacitor wrapper Android/iOS)",
|
"description": "Shivao app nativo (Capacitor wrapper Android/iOS)",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
|
||||||
|
|
@ -6146,10 +6146,12 @@ async function bmsWriteCmd(deviceId,bytes,withoutResponse){
|
||||||
const ble=window.Capacitor?.Plugins?.BluetoothLe;
|
const ble=window.Capacitor?.Plugins?.BluetoothLe;
|
||||||
const dev=state.btDevices?.find(d=>d.id===deviceId);
|
const dev=state.btDevices?.find(d=>d.id===deviceId);
|
||||||
if(!ble||!dev?.bmsService||!dev?.bmsWriteChar)throw new Error('config BMS ausente');
|
if(!ble||!dev?.bmsService||!dev?.bmsWriteChar)throw new Error('config BMS ausente');
|
||||||
// Se a write char só aceita wnr, força writeWithoutResponse independente do parâmetro
|
|
||||||
const useWnr=withoutResponse||dev.bmsForceWnr;
|
const useWnr=withoutResponse||dev.bmsForceWnr;
|
||||||
const fn=useWnr?'writeWithoutResponse':'write';
|
const fn=useWnr?'writeWithoutResponse':'write';
|
||||||
await ble[fn]({deviceId,service:dev.bmsService,characteristic:dev.bmsWriteChar,value:bytesToBase64(bytes)});
|
// Timeout 3s: plugins/firmware podem travar mesmo com WNR
|
||||||
|
const writePromise=ble[fn]({deviceId,service:dev.bmsService,characteristic:dev.bmsWriteChar,value:bytesToBase64(bytes)});
|
||||||
|
const timeoutPromise=new Promise((_,rej)=>setTimeout(()=>rej(new Error('write timeout 3s')),3000));
|
||||||
|
await Promise.race([writePromise,timeoutPromise]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function bmsTryProtocols(deviceId){
|
async function bmsTryProtocols(deviceId){
|
||||||
|
|
@ -6162,18 +6164,25 @@ async function bmsTryProtocols(deviceId){
|
||||||
for(const p of PROTOCOLS){
|
for(const p of PROTOCOLS){
|
||||||
try{
|
try{
|
||||||
setBleDiag(`→ TX ${p.name}: ${p.bytes.map(b=>b.toString(16).padStart(2,'0')).join(' ').slice(0,40)}`,'info');
|
setBleDiag(`→ TX ${p.name}: ${p.bytes.map(b=>b.toString(16).padStart(2,'0')).join(' ').slice(0,40)}`,'info');
|
||||||
|
try{
|
||||||
await bmsWriteCmd(deviceId,p.bytes,p.wnr);
|
await bmsWriteCmd(deviceId,p.bytes,p.wnr);
|
||||||
// Espera 2s pra ver se gerou RX
|
setBleDiag(`✔ write ${p.name} retornou`,'info');
|
||||||
|
}catch(we){
|
||||||
|
setBleDiag(`✗ write ${p.name} erro: ${we.message||we.errorMessage}`,'warn');
|
||||||
|
// Continue pro próximo protocolo mesmo se write falhar
|
||||||
|
}
|
||||||
|
// Aguarda RX por 2.5s
|
||||||
await new Promise(r=>setTimeout(r,2500));
|
await new Promise(r=>setTimeout(r,2500));
|
||||||
const dev=state.btDevices?.find(d=>d.id===deviceId);
|
const dev=state.btDevices?.find(d=>d.id===deviceId);
|
||||||
if(dev?.bms?.voltage||dev?._lastRxAt){
|
if(dev?.bms?.voltage||dev?._lastRxAt){
|
||||||
setBleDiag(`✓ ${p.name} respondeu!`,'ok');
|
setBleDiag(`✓ ${p.name} respondeu!`,'ok');
|
||||||
// Configura poll periódico com este protocolo
|
|
||||||
if(dev)dev.bmsProtocol=p.name;
|
if(dev)dev.bmsProtocol=p.name;
|
||||||
setInterval(async()=>{try{await bmsWriteCmd(deviceId,p.bytes,p.wnr)}catch{}},30000);
|
setInterval(async()=>{try{await bmsWriteCmd(deviceId,p.bytes,p.wnr)}catch{}},30000);
|
||||||
return true;
|
return true;
|
||||||
|
}else{
|
||||||
|
setBleDiag(`✗ ${p.name} sem RX em 2.5s`,'info');
|
||||||
}
|
}
|
||||||
}catch(e){setBleDiag(`${p.name} falhou: ${e.message||e.errorMessage}`,'warn')}
|
}catch(e){setBleDiag(`${p.name} loop erro: ${e.message||e.errorMessage}`,'warn')}
|
||||||
}
|
}
|
||||||
setBleDiag('⚠ Nenhum protocolo funcionou. BMS pode usar firmware proprietário não documentado.','err');
|
setBleDiag('⚠ Nenhum protocolo funcionou. BMS pode usar firmware proprietário não documentado.','err');
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -6343,7 +6352,7 @@ async function removeBluetoothDevice(id){
|
||||||
renderBluetoothCard();
|
renderBluetoothCard();
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP_VERSION='1.10.9';
|
const APP_VERSION='1.10.10';
|
||||||
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');
|
||||||
|
|
|
||||||
|
|
@ -413,7 +413,7 @@ app.get('/.well-known/assetlinks.json', (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Atalho: /apk redireciona pra última APK release no Forgejo
|
// Atalho: /apk redireciona pra última APK release no Forgejo
|
||||||
const LATEST_APK_URL = 'https://git.pontualtech.work/karlao/shivao-projeto/releases/download/v1.10.9/Shivao-v1.10.9.apk';
|
const LATEST_APK_URL = 'https://git.pontualtech.work/karlao/shivao-projeto/releases/download/v1.10.10/Shivao-v1.10.10.apk';
|
||||||
app.get('/apk', (req, res) => res.redirect(302, LATEST_APK_URL));
|
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)
|
// Página A4 imprimível com QR Code + instruções (cola no barco/marina)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue