diff --git a/app/diario-bordo.html b/app/diario-bordo.html index f7ec915..cf51dbe 100644 --- a/app/diario-bordo.html +++ b/app/diario-bordo.html @@ -2542,6 +2542,21 @@ Hora: {HORA} + + + + ${d.isJBD?``:''} ${!isConnected?``:''} + ${d.isJBD?``:''} ${bmsBlock} @@ -6196,6 +6240,123 @@ function renderBluetoothCard(){ // Re-render quando entra na aba Mais function refreshBluetoothCard(){renderBluetoothCard()} +// ============ BMS DASHBOARD (monitor de bordo full-screen) ============ +let _dashRefreshTimer=null; +function openBmsDashboard(deviceId){ + window._currentDashDeviceId=deviceId; + const dev=state.btDevices?.find(d=>d.id===deviceId); + if(!dev)return; + document.getElementById('bms-dash-title').textContent='⚡ '+(dev.name||'Bateria'); + renderBmsDashboard(); + openModal('bms-dashboard-modal'); + // Auto-refresh a cada 5s enquanto modal aberto + if(_dashRefreshTimer)clearInterval(_dashRefreshTimer); + _dashRefreshTimer=setInterval(()=>{ + if(document.getElementById('bms-dashboard-modal')?.classList.contains('show')){ + bmsManualRead(deviceId); + setTimeout(renderBmsDashboard,2000); + }else{ + clearInterval(_dashRefreshTimer);_dashRefreshTimer=null; + } + },10000); +} + +function renderBmsDashboard(){ + const id=window._currentDashDeviceId; + const dev=state.btDevices?.find(d=>d.id===id); + const body=document.getElementById('bms-dash-body'); + if(!dev||!body)return; + const b=dev.bms||{}; + if(!b.voltage){ + body.innerHTML=` +
+
+
Aguardando dados da bateria...
+
O BMS deve responder em alguns segundos. Se demorar, toque 🔄 Re-ler abaixo.
+
`; + return; + } + const isCharging=b.current>0; + const isDischarging=b.current<0; + const power=Math.abs(b.voltage*b.current).toFixed(0); + const flowText=isCharging?'⚡ CARREGANDO':isDischarging?'↓ DESCARGA':'— REPOUSO'; + const flowColor=isCharging?'#10b981':isDischarging?'#f59e0b':'#7d97ad'; + const socColor=b.soc<20?'#ef4444':b.soc<50?'#f59e0b':'#10b981'; + // Tempo restante (descarga) ou tempo até cheia (carga) + let timeRemaining=''; + if(isDischarging&&b.remainCap){ + const hours=b.remainCap/Math.abs(b.current); + timeRemaining=hours>1?`~${hours.toFixed(1)}h restantes`:`~${Math.round(hours*60)}min restantes`; + }else if(isCharging&&b.totalCap&&b.remainCap){ + const hoursToFull=(b.totalCap-b.remainCap)/b.current; + timeRemaining=hoursToFull>0?`~${hoursToFull.toFixed(1)}h até cheia`:'Quase cheia'; + } + const cellsBlock=b.cells&&b.cells.length>0?` +
+
Células (${b.cells.length}S)
+
+ ${b.cells.map((v,i)=>{ + const c=v<3.0?'#ef4444':v<3.3?'#f59e0b':v>3.6?'#10b981':'#06b6d4'; + return `
+
C${i+1}
+
${v.toFixed(3)}V
+
`; + }).join('')} +
+
`:''; + body.innerHTML=` + +
+
+ + + + +
+
${b.soc||'?'}%
+
Estado de Carga
+
+
+
+ + +
${flowText}${timeRemaining?' · '+timeRemaining:''}
+ + +
+
+
Tensão Total
+
${b.voltage.toFixed(2)} V
+
+
+
Corrente
+
${b.current.toFixed(2)} A
+
+
+
Potência
+
${power} W
+
+
+
Capacidade
+
${b.remainCap?b.remainCap.toFixed(1):'?'} /${b.totalCap?b.totalCap.toFixed(0):'?'}Ah
+
+
+ + +
+ ♻ ${b.cycles||0} ciclos + ${b.temps&&b.temps.length>0?'🌡 '+b.temps.map(t=>t+'°C').join(', '):''} + v${b.swVersion||'?'} +
+ + ${cellsBlock} +
Última leitura: ${new Date(b.lastRead).toLocaleTimeString('pt-BR')} · auto-refresh 10s
+ `; +} + // ============ RAYMARINE / NMEA 2000 GATEWAY ============ // Slot pra quando Karlão tiver gateway NMEA 2000 → WiFi (Yacht Devices YDWG-02, etc) diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle index 2214bc1..5de84f2 100644 --- a/mobile/android/app/build.gradle +++ b/mobile/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "br.com.pontualtech.shivao" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 16 - versionName "1.10.0" + versionCode 17 + versionName "1.10.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/mobile/package.json b/mobile/package.json index 6c500e2..590f518 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -1,6 +1,6 @@ { "name": "shivao-mobile", - "version": "1.10.0", + "version": "1.10.1", "description": "Shivao app nativo (Capacitor wrapper Android/iOS)", "main": "index.js", "type": "module", diff --git a/server/public/index.html b/server/public/index.html index f7ec915..cf51dbe 100644 --- a/server/public/index.html +++ b/server/public/index.html @@ -2542,6 +2542,21 @@ Hora: {HORA} + + + + ${d.isJBD?``:''} ${!isConnected?``:''} + ${d.isJBD?``:''} ${bmsBlock} @@ -6196,6 +6240,123 @@ function renderBluetoothCard(){ // Re-render quando entra na aba Mais function refreshBluetoothCard(){renderBluetoothCard()} +// ============ BMS DASHBOARD (monitor de bordo full-screen) ============ +let _dashRefreshTimer=null; +function openBmsDashboard(deviceId){ + window._currentDashDeviceId=deviceId; + const dev=state.btDevices?.find(d=>d.id===deviceId); + if(!dev)return; + document.getElementById('bms-dash-title').textContent='⚡ '+(dev.name||'Bateria'); + renderBmsDashboard(); + openModal('bms-dashboard-modal'); + // Auto-refresh a cada 5s enquanto modal aberto + if(_dashRefreshTimer)clearInterval(_dashRefreshTimer); + _dashRefreshTimer=setInterval(()=>{ + if(document.getElementById('bms-dashboard-modal')?.classList.contains('show')){ + bmsManualRead(deviceId); + setTimeout(renderBmsDashboard,2000); + }else{ + clearInterval(_dashRefreshTimer);_dashRefreshTimer=null; + } + },10000); +} + +function renderBmsDashboard(){ + const id=window._currentDashDeviceId; + const dev=state.btDevices?.find(d=>d.id===id); + const body=document.getElementById('bms-dash-body'); + if(!dev||!body)return; + const b=dev.bms||{}; + if(!b.voltage){ + body.innerHTML=` +
+
+
Aguardando dados da bateria...
+
O BMS deve responder em alguns segundos. Se demorar, toque 🔄 Re-ler abaixo.
+
`; + return; + } + const isCharging=b.current>0; + const isDischarging=b.current<0; + const power=Math.abs(b.voltage*b.current).toFixed(0); + const flowText=isCharging?'⚡ CARREGANDO':isDischarging?'↓ DESCARGA':'— REPOUSO'; + const flowColor=isCharging?'#10b981':isDischarging?'#f59e0b':'#7d97ad'; + const socColor=b.soc<20?'#ef4444':b.soc<50?'#f59e0b':'#10b981'; + // Tempo restante (descarga) ou tempo até cheia (carga) + let timeRemaining=''; + if(isDischarging&&b.remainCap){ + const hours=b.remainCap/Math.abs(b.current); + timeRemaining=hours>1?`~${hours.toFixed(1)}h restantes`:`~${Math.round(hours*60)}min restantes`; + }else if(isCharging&&b.totalCap&&b.remainCap){ + const hoursToFull=(b.totalCap-b.remainCap)/b.current; + timeRemaining=hoursToFull>0?`~${hoursToFull.toFixed(1)}h até cheia`:'Quase cheia'; + } + const cellsBlock=b.cells&&b.cells.length>0?` +
+
Células (${b.cells.length}S)
+
+ ${b.cells.map((v,i)=>{ + const c=v<3.0?'#ef4444':v<3.3?'#f59e0b':v>3.6?'#10b981':'#06b6d4'; + return `
+
C${i+1}
+
${v.toFixed(3)}V
+
`; + }).join('')} +
+
`:''; + body.innerHTML=` + +
+
+ + + + +
+
${b.soc||'?'}%
+
Estado de Carga
+
+
+
+ + +
${flowText}${timeRemaining?' · '+timeRemaining:''}
+ + +
+
+
Tensão Total
+
${b.voltage.toFixed(2)} V
+
+
+
Corrente
+
${b.current.toFixed(2)} A
+
+
+
Potência
+
${power} W
+
+
+
Capacidade
+
${b.remainCap?b.remainCap.toFixed(1):'?'} /${b.totalCap?b.totalCap.toFixed(0):'?'}Ah
+
+
+ + +
+ ♻ ${b.cycles||0} ciclos + ${b.temps&&b.temps.length>0?'🌡 '+b.temps.map(t=>t+'°C').join(', '):''} + v${b.swVersion||'?'} +
+ + ${cellsBlock} +
Última leitura: ${new Date(b.lastRead).toLocaleTimeString('pt-BR')} · auto-refresh 10s
+ `; +} + // ============ RAYMARINE / NMEA 2000 GATEWAY ============ // Slot pra quando Karlão tiver gateway NMEA 2000 → WiFi (Yacht Devices YDWG-02, etc) diff --git a/server/src/index.js b/server/src/index.js index 811ae72..f364012 100644 --- a/server/src/index.js +++ b/server/src/index.js @@ -347,7 +347,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.0/Shivao-v1.10.0.apk'; +const LATEST_APK_URL = 'https://git.pontualtech.work/karlao/shivao-projeto/releases/download/v1.10.1/Shivao-v1.10.1.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)