@sailingrotevista/rotevista-dash 4.0.13 → 4.0.15

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.
Files changed (2) hide show
  1. package/app.js +44 -46
  2. package/package.json +1 -1
package/app.js CHANGED
@@ -12,36 +12,23 @@
12
12
  // 1. CONFIGURAZIONE E DEFAULT
13
13
  // ==========================================================================
14
14
  let CONFIG = {
15
- alarms: {
16
- depthDanger: 2.5,
17
- depthWarning: 5.0
18
- },
19
- // Gestione parametri di stabilità e medie
20
- averages: {
21
- smoothWindow: 2000, // Smoothing puntatori (2s)
22
- longWindow: 30000, // Finestra per i valori MEAN (30s)
23
- stabilityTolerance: 2000, // Millisecondi per considerare il buffer "pieno"
24
- stabilityThreshold: 0.85, // Soglia coerenza R per il lampeggio (0.7 - 0.98)
25
- minSpeed: 0, // Nodi minimi per attivare gli allarmi di instabilità
15
+ alarms: { depthDanger: 2.5, depthWarning: 5.0 },
16
+ averaging: {
17
+ smoothWindow: 2000,
18
+ longWindow: 30000,
19
+ stabilityTolerance: 2000,
20
+ stabilityThreshold: 0.85,
21
+ minSpeed: 0.5,
26
22
  stabilityBreakout: 15
27
23
  },
28
- // Parametri per i grafici sparkline
29
- graphs: {
30
- reef1: 15.0, // Soglia primo reef (Orange)
31
- reef2: 20.0, // Soglia secondo reef (Red)
32
- historyMinutes: 5, // Finestra temporale visualizzata
33
- samples: 60 // Numero di punti di campionamento
34
- },
35
- // Configurazioni scale automatiche
24
+ graphs: { reef1: 15.0, reef2: 20.0, historyMinutes: 5, samples: 60 },
36
25
  scales: {
37
26
  stw: { stdMax: 12, hercSpan: 4, step: 2 },
38
27
  sog: { stdMax: 12, hercSpan: 4, step: 2 },
39
28
  tws: { stdMax: 25, hercSpan: 10, step: 5 },
40
29
  depth: { stdMax: 20, hercSpan: 10, step: 10 }
41
30
  },
42
- server: {
43
- fallbackIp: "192.168.111.240:3000"
44
- }
31
+ server: { fallbackIp: "192.168.111.240:3000" }
45
32
  };
46
33
 
47
34
  const RENDER_INTERVAL_MS = 1000;
@@ -146,7 +133,7 @@ function getCircularAverageFromBuffer(bufferArray, windowMs, signed = false) {
146
133
  let historyDuration = (validData.length > 2) ? (validData[validData.length - 1].time - validData[0].time) : 0;
147
134
 
148
135
  // Un dato è stabile se abbiamo abbastanza storia e la coerenza vettoriale R è alta
149
- let isStable = (historyDuration > 10000) && (R > CONFIG.averages.stabilityThreshold);
136
+ let isStable = (historyDuration > 10000) && (R > CONFIG.averaging.stabilityThreshold);
150
137
  let avgRad = Math.atan2(sSin, sCos);
151
138
 
152
139
  // Calcolo della Deviazione Standard Circolare (±) in gradi
@@ -401,7 +388,7 @@ const upUI = (el, obj, instantRaw, isCompass = false) => {
401
388
 
402
389
  let diff = Math.abs((radToDeg(instantRaw) - radToDeg(obj.val) + 540) % 360 - 180);
403
390
  // Allarme lampeggio solo se in navigazione E (R bassa O deviazione alta O salto istantaneo brusco)
404
- if (isNavigating && (!obj.stable || obj.dev > CONFIG.averages.stabilityBreakout || diff > CONFIG.averages.stabilityBreakout)) el.classList.add('unstable-data');
391
+ if (isNavigating && (!obj.stable || obj.dev > CONFIG.averaging.stabilityBreakout || diff > CONFIG.averaging.stabilityBreakout)) el.classList.add('unstable-data');
405
392
  else el.classList.remove('unstable-data');
406
393
  }
407
394
  };
@@ -420,7 +407,7 @@ function startDisplayLoop() {
420
407
  const sogKts = msToKts(store.raw["navigation.speedOverGround"] || 0);
421
408
 
422
409
  // Verifica stato navigazione basato su soglia impostata
423
- isNavigating = stwKts > CONFIG.averages.minSpeed || sogKts > CONFIG.averages.minSpeed;
410
+ isNavigating = stwKts > CONFIG.averaging.minSpeed || sogKts > CONFIG.averaging.minSpeed;
424
411
 
425
412
  // --- TIER LIVE (1s): CONTROLLO TIMEOUT DATI ---
426
413
  const watch = { "navigation.speedThroughWater": ui.stw, "navigation.speedOverGround": ui.sog, "navigation.headingTrue": ui.hdg, "navigation.courseOverGroundTrue": ui.cog, "environment.wind.speedApparent": ui.awsSvg, "environment.depth.belowTransducer": ui.depth, "environment.wind.speedTrue": ui.tws };
@@ -488,7 +475,7 @@ function startDisplayLoop() {
488
475
  if (store.raw["navigation.courseOverGroundTrue"] !== undefined && store.raw["navigation.headingTrue"] !== undefined) {
489
476
  let driftDeg = radToDeg((store.raw["navigation.courseOverGroundTrue"] - store.raw["navigation.headingTrue"] + Math.PI * 3) % (Math.PI * 2) - Math.PI);
490
477
  // Azzeramento sotto soglia minima impostata
491
- smoothedLeeway = (sogKts < CONFIG.averages.minSpeed) ? 0 : (smoothedLeeway * 0.9) + (driftDeg * 0.1);
478
+ smoothedLeeway = (sogKts < CONFIG.averaging.minSpeed) ? 0 : (smoothedLeeway * 0.9) + (driftDeg * 0.1);
492
479
  curTrackRot = getShortestRotation(curTrackRot, smoothedLeeway); ui.track.setAttribute('transform', `rotate(${curTrackRot}, 200, 200)`);
493
480
  ui.leewayVal.style.color = (Math.abs(sogKts - stwKts) > 0.5 && Math.abs(smoothedLeeway) > 7) ? "#e67e22" : "";
494
481
  updateLeewayDisplay(Math.max(-20, Math.min(20, smoothedLeeway)));
@@ -504,11 +491,11 @@ function startDisplayLoop() {
504
491
 
505
492
  // TIER SLOW (3s) - Medie Lunghe e Calcolo TACK
506
493
  if (lastAvgUIUpdate % 3 === 0) {
507
- let hObj = getCircularAverageFromBuffer(store.longBuf.hdg, CONFIG.averages.longWindow * 2, false);
508
- let cObj = getCircularAverageFromBuffer(store.longBuf.cog, CONFIG.averages.longWindow, false);
509
- let awObj = getCircularAverageFromBuffer(store.longBuf.awa, CONFIG.averages.longWindow, true);
510
- let twObj = getCircularAverageFromBuffer(store.longBuf.twa, CONFIG.averages.longWindow, true);
511
- let twdObj = getCircularAverageFromBuffer(store.longBuf.twd, CONFIG.averages.longWindow, false);
494
+ let hObj = getCircularAverageFromBuffer(store.longBuf.hdg, CONFIG.averaging.longWindow * 2, false);
495
+ let cObj = getCircularAverageFromBuffer(store.longBuf.cog, CONFIG.averaging.longWindow, false);
496
+ let awObj = getCircularAverageFromBuffer(store.longBuf.awa, CONFIG.averaging.longWindow, true);
497
+ let twObj = getCircularAverageFromBuffer(store.longBuf.twa, CONFIG.averaging.longWindow, true);
498
+ let twdObj = getCircularAverageFromBuffer(store.longBuf.twd, CONFIG.averaging.longWindow, false);
512
499
 
513
500
  upUI(ui.hdg, hObj, store.raw["navigation.headingTrue"], true);
514
501
  upUI(ui.cog, cObj, store.raw["navigation.courseOverGroundTrue"], true);
@@ -519,7 +506,7 @@ function startDisplayLoop() {
519
506
  // --- LOGICA TACK STRATEGICA (Riflessione geometrica su TWD) ---
520
507
  if (hObj && twdObj) {
521
508
  const tH = radToDeg((2 * twdObj.val - hObj.val + Math.PI * 2) % (Math.PI * 2));
522
- const unstableH = !hObj.stable || !twdObj.stable || hObj.dev > CONFIG.averages.stabilityBreakout || twdObj.dev > CONFIG.averages.stabilityBreakout;
509
+ const unstableH = !hObj.stable || !twdObj.stable || hObj.dev > CONFIG.averaging.stabilityBreakout || twdObj.dev > CONFIG.averaging.stabilityBreakout;
523
510
 
524
511
  if (!isNavigating) {
525
512
  ui.tackHdg.innerHTML = "---&deg;"; ui.tackHdg.classList.remove('unstable-data');
@@ -532,7 +519,7 @@ function startDisplayLoop() {
532
519
 
533
520
  if (cObj) {
534
521
  const tC = radToDeg((2 * twdObj.val - cObj.val + Math.PI * 2) % (Math.PI * 2));
535
- const unstableC = !cObj.stable || !twdObj.stable || cObj.dev > CONFIG.averages.stabilityBreakout || twdObj.dev > CONFIG.averages.stabilityBreakout;
522
+ const unstableC = !cObj.stable || !twdObj.stable || cObj.dev > CONFIG.averaging.stabilityBreakout || twdObj.dev > CONFIG.averaging.stabilityBreakout;
536
523
 
537
524
  if (!isNavigating) {
538
525
  ui.tackCog.innerHTML = "---&deg;"; ui.tackCog.classList.remove('unstable-data');
@@ -560,37 +547,48 @@ function startDisplayLoop() {
560
547
  // 8. CONFIGURAZIONE E GRAFICI UTILS
561
548
  // ==========================================================================
562
549
  /**
563
- * Recupera la configurazione tramite l'endpoint dedicato /rotevista-config.
564
- * Questo bypassa i blocchi di sicurezza standard di Signal K.
550
+ * Recupera la configurazione e forza la sovrascrittura di ogni parametro.
565
551
  */
566
552
  async function fetchServerConfig() {
567
553
  try {
568
554
  const response = await fetch('/rotevista-config');
569
- if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
570
-
555
+ if (!response.ok) throw new Error(`Server offline o rotta non trovata`);
571
556
  const data = await response.json();
572
557
 
573
- // Funzione di utilità per garantire che i valori siano numeri (evita bug nei grafici)
558
+ // 1. Funzione di pulizia: trasforma stringhe in numeri
574
559
  const parse = (obj) => {
575
560
  for (let k in obj) {
576
- if (typeof obj[k] === 'object') parse(obj[k]);
561
+ if (typeof obj[k] === 'object' && obj[k] !== null) parse(obj[k]);
577
562
  else if (!isNaN(obj[k]) && typeof obj[k] === 'string' && obj[k] !== "")
578
563
  obj[k] = parseFloat(obj[k]);
579
564
  }
580
565
  return obj;
581
566
  };
582
-
583
567
  const actual = parse(data);
584
568
 
585
- // Fondiamo i dati del server con il CONFIG locale
569
+ // 2. Mappatura Forzata (Deep Merge)
586
570
  if (actual.alarms) Object.assign(CONFIG.alarms, actual.alarms);
587
- if (actual.graphs) Object.assign(CONFIG.graphs, actual.graphs);
588
- if (actual.averaging) Object.assign(CONFIG.averages, actual.averaging);
589
- if (actual.scales) Object.assign(CONFIG.scales, actual.scales);
571
+
572
+ if (actual.graphs) {
573
+ Object.assign(CONFIG.graphs, actual.graphs);
574
+ console.log(`📈 GRAFICI: Durata ${CONFIG.graphs.historyMinutes}m | Reef1: ${CONFIG.graphs.reef1}kts | Reef2: ${CONFIG.graphs.reef2}kts`);
575
+ }
576
+
577
+ if (actual.averaging) {
578
+ Object.assign(CONFIG.averaging, actual.averaging);
579
+ console.log(`⏱️ STABILITÀ: MinSpeed ${CONFIG.averaging.minSpeed}kts | Breakout: ${CONFIG.averaging.stabilityBreakout}°`);
580
+ }
581
+
582
+ if (actual.scales) {
583
+ // Per le scale facciamo un merge profondo per ogni box
584
+ for (let key in actual.scales) {
585
+ if (CONFIG.scales[key]) Object.assign(CONFIG.scales[key], actual.scales[key]);
586
+ }
587
+ }
590
588
 
591
- console.log("✅ Configurazione sincronizzata via /rotevista-config");
589
+ console.log("✅ Configurazione sincronizzata con successo.");
592
590
  } catch (err) {
593
- console.warn("⚠️ Utilizzo default locali (Endpoint non ancora attivo o server offline).");
591
+ console.warn("⚠️ Utilizzo default locali. Motivo:", err.message);
594
592
  }
595
593
  }
596
594
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sailingrotevista/rotevista-dash",
3
- "version": "4.0.13",
3
+ "version": "4.0.15",
4
4
  "description": "Public Wind Dashboard with navigation and course aids",
5
5
  "main": "index.js",
6
6
  "publishConfig": {