@sailingrotevista/rotevista-dash 7.0.31 → 7.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app.js +16 -11
- package/package.json +1 -1
- package/utils.js +7 -6
package/app.js
CHANGED
|
@@ -323,6 +323,11 @@ function getSourcePriorityScore(sourceName) {
|
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
function processIncomingData(path, val, source, timeMs) {
|
|
326
|
+
// 0. Filtro di validità assoluta: ignora all'istante pacchetti vuoti, null o non numerici
|
|
327
|
+
if (val === null || val === undefined || (typeof val === 'number' && isNaN(val))) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
326
331
|
// 1. Filtro anti-spike vento (> 100 nodi / 51.44 m/s)
|
|
327
332
|
if ((path === "environment.wind.speedApparent" || path === "environment.wind.speedTrue") && val > 51.44) {
|
|
328
333
|
return;
|
|
@@ -348,21 +353,22 @@ function processIncomingData(path, val, source, timeMs) {
|
|
|
348
353
|
} else {
|
|
349
354
|
const currentLock = sourceLocks[path];
|
|
350
355
|
const isSameSource = (currentLock.label === source);
|
|
351
|
-
|
|
356
|
+
// Tolleranza 5s: ignora il GPS Victron durante le micro-pause di Yacht Device per evitare imprecisioni
|
|
357
|
+
const isLockExpired = (now - currentLock.lastSeen > 5000);
|
|
352
358
|
const hasHigherPriority = (score > currentLock.score);
|
|
353
|
-
//
|
|
359
|
+
// Switch immediato tra apparati principali di pari priorità (es. YD e AP) se inattivi da > 1.5s
|
|
354
360
|
const isSamePriorityStale = (score === currentLock.score && (now - currentLock.lastSeen > 1500));
|
|
355
361
|
|
|
356
362
|
if (isSameSource) {
|
|
357
363
|
// Stessa sorgente: aggiorna il timestamp e mantiene il blocco
|
|
358
364
|
currentLock.lastSeen = now;
|
|
359
365
|
currentLock.score = score;
|
|
360
|
-
} else if (
|
|
361
|
-
//
|
|
366
|
+
} else if (hasHigherPriority || isLockExpired || isSamePriorityStale) {
|
|
367
|
+
// Passa a sorgenti secondarie (Victron) solo se Yacht Device è spento da > 5s
|
|
362
368
|
sourceLocks[path] = { label: source, score: score, lastSeen: now };
|
|
363
369
|
console.log(`🔌 [Smart Lock] Path "${path}" switched to: ${source} (Score: ${score})`);
|
|
364
370
|
} else {
|
|
365
|
-
//
|
|
371
|
+
// Scarta sorgenti imprecise di servizio mentre Yacht Device è la sorgente principale attiva
|
|
366
372
|
return;
|
|
367
373
|
}
|
|
368
374
|
}
|
|
@@ -799,16 +805,15 @@ function startDisplayLoop() {
|
|
|
799
805
|
}
|
|
800
806
|
|
|
801
807
|
// --- SLOW TIER (Salvataggio stato ogni 10 secondi) ---
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
808
|
+
if (lastAvgUIUpdate++ % 10 === 0) {
|
|
809
|
+
saveDashboardState();
|
|
810
|
+
}
|
|
805
811
|
|
|
806
|
-
|
|
812
|
+
// AGGIORNAMENTO FLUIDO MEDIE UI (Esecuzione a 1Hz costante ad ogni secondo)
|
|
807
813
|
const baseThreshold = CONFIG.averaging.stabilityThreshold || 0.95;
|
|
808
814
|
const breakout = CONFIG.averaging.stabilityBreakout || 15;
|
|
809
815
|
|
|
810
|
-
// CALCOLO DIFFERENZIALE: Tolleranza del vento proporzionale alla sensibilità di base
|
|
811
|
-
// Rilassiamo la soglia del vento di 0.13 rispetto alla prua (es. se la prua richiede 0.95, il vento richiede 0.82)
|
|
816
|
+
// CALCOLO DIFFERENZIALE: Tolleranza del vento proporzionale alla sensibilità di base
|
|
812
817
|
const windThreshold = Math.max(0.60, baseThreshold - 0.13);
|
|
813
818
|
|
|
814
819
|
let hObj = getCircularAverageFromBuffer(store.longBuf.hdg, CONFIG.averaging.longWindow * 2, false, now, baseThreshold, breakout);
|
package/package.json
CHANGED
package/utils.js
CHANGED
|
@@ -36,10 +36,9 @@ function getCircularAverageFromBuffer(bufferArray, windowMs, signed = false, now
|
|
|
36
36
|
const len = bufferArray.length;
|
|
37
37
|
if (len === 0) return null;
|
|
38
38
|
|
|
39
|
-
// RIFERIMENTO TEMPORALE IMMUNE DA DESINCRONIZZAZIONE
|
|
40
|
-
// Usiamo come 'ora attuale' l'ultimo timestamp presente nel buffer stesso,
|
|
41
|
-
// garantendo che la finestra di 2s sia sempre calcolata sui dati NMEA reali arrivati.
|
|
39
|
+
// RIFERIMENTO TEMPORALE IMMUNE DA DESINCRONIZZAZIONE (Usa l'ultimo dato del buffer)
|
|
42
40
|
const referenceTime = bufferArray[len - 1].time;
|
|
41
|
+
|
|
43
42
|
let sSin = 0, sCos = 0, count = 0;
|
|
44
43
|
let newestTime = 0, oldestTime = 0;
|
|
45
44
|
|
|
@@ -54,7 +53,7 @@ function getCircularAverageFromBuffer(bufferArray, windowMs, signed = false, now
|
|
|
54
53
|
|
|
55
54
|
for (let i = len - 1; i >= 0; i--) {
|
|
56
55
|
const item = bufferArray[i];
|
|
57
|
-
if ((referenceTime - item.time) > windowMs) break;
|
|
56
|
+
if ((referenceTime - item.time) > windowMs) break;
|
|
58
57
|
|
|
59
58
|
let diffRad = Math.atan2(Math.sin(item.val - pilotRad), Math.cos(item.val - pilotRad));
|
|
60
59
|
let finalSin, finalCos;
|
|
@@ -82,12 +81,14 @@ function getCircularAverageFromBuffer(bufferArray, windowMs, signed = false, now
|
|
|
82
81
|
const R = Math.hypot(sSin, sCos) / count;
|
|
83
82
|
const avgRad = Math.atan2(sSin, sCos);
|
|
84
83
|
const finalVal = signed ? avgRad : (avgRad + Math.PI * 2) % (Math.PI * 2);
|
|
85
|
-
const historyDuration = (count > 2) ? (newestTime - oldestTime) : 0;
|
|
86
84
|
const safeR = Math.max(R, 1e-9);
|
|
87
85
|
|
|
86
|
+
// Stabilità valida se ci sono almeno 2 campioni nel buffer e la varianza radiale supera la soglia
|
|
87
|
+
const isStable = (count >= 2) && (R > stabilityThreshold);
|
|
88
|
+
|
|
88
89
|
return {
|
|
89
90
|
val: finalVal,
|
|
90
|
-
stable:
|
|
91
|
+
stable: isStable,
|
|
91
92
|
dev: (R < 1) ? Math.round(Math.sqrt(-2 * Math.log(safeR)) * (180 / Math.PI)) : 0,
|
|
92
93
|
samples: count
|
|
93
94
|
};
|