@sailingrotevista/rotevista-dash 4.0.12 → 4.0.14

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 (3) hide show
  1. package/app.js +47 -35
  2. package/index.js +21 -6
  3. package/package.json +1 -1
package/app.js CHANGED
@@ -17,7 +17,7 @@ let CONFIG = {
17
17
  depthWarning: 5.0
18
18
  },
19
19
  // Gestione parametri di stabilità e medie
20
- averages: {
20
+ averaging: {
21
21
  smoothWindow: 2000, // Smoothing puntatori (2s)
22
22
  longWindow: 30000, // Finestra per i valori MEAN (30s)
23
23
  stabilityTolerance: 2000, // Millisecondi per considerare il buffer "pieno"
@@ -146,7 +146,7 @@ function getCircularAverageFromBuffer(bufferArray, windowMs, signed = false) {
146
146
  let historyDuration = (validData.length > 2) ? (validData[validData.length - 1].time - validData[0].time) : 0;
147
147
 
148
148
  // Un dato è stabile se abbiamo abbastanza storia e la coerenza vettoriale R è alta
149
- let isStable = (historyDuration > 10000) && (R > CONFIG.averages.stabilityThreshold);
149
+ let isStable = (historyDuration > 10000) && (R > CONFIG.averaging.stabilityThreshold);
150
150
  let avgRad = Math.atan2(sSin, sCos);
151
151
 
152
152
  // Calcolo della Deviazione Standard Circolare (±) in gradi
@@ -401,7 +401,7 @@ const upUI = (el, obj, instantRaw, isCompass = false) => {
401
401
 
402
402
  let diff = Math.abs((radToDeg(instantRaw) - radToDeg(obj.val) + 540) % 360 - 180);
403
403
  // 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');
404
+ if (isNavigating && (!obj.stable || obj.dev > CONFIG.averaging.stabilityBreakout || diff > CONFIG.averaging.stabilityBreakout)) el.classList.add('unstable-data');
405
405
  else el.classList.remove('unstable-data');
406
406
  }
407
407
  };
@@ -420,7 +420,7 @@ function startDisplayLoop() {
420
420
  const sogKts = msToKts(store.raw["navigation.speedOverGround"] || 0);
421
421
 
422
422
  // Verifica stato navigazione basato su soglia impostata
423
- isNavigating = stwKts > CONFIG.averages.minSpeed || sogKts > CONFIG.averages.minSpeed;
423
+ isNavigating = stwKts > CONFIG.averaging.minSpeed || sogKts > CONFIG.averaging.minSpeed;
424
424
 
425
425
  // --- TIER LIVE (1s): CONTROLLO TIMEOUT DATI ---
426
426
  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 +488,7 @@ function startDisplayLoop() {
488
488
  if (store.raw["navigation.courseOverGroundTrue"] !== undefined && store.raw["navigation.headingTrue"] !== undefined) {
489
489
  let driftDeg = radToDeg((store.raw["navigation.courseOverGroundTrue"] - store.raw["navigation.headingTrue"] + Math.PI * 3) % (Math.PI * 2) - Math.PI);
490
490
  // Azzeramento sotto soglia minima impostata
491
- smoothedLeeway = (sogKts < CONFIG.averages.minSpeed) ? 0 : (smoothedLeeway * 0.9) + (driftDeg * 0.1);
491
+ smoothedLeeway = (sogKts < CONFIG.averaging.minSpeed) ? 0 : (smoothedLeeway * 0.9) + (driftDeg * 0.1);
492
492
  curTrackRot = getShortestRotation(curTrackRot, smoothedLeeway); ui.track.setAttribute('transform', `rotate(${curTrackRot}, 200, 200)`);
493
493
  ui.leewayVal.style.color = (Math.abs(sogKts - stwKts) > 0.5 && Math.abs(smoothedLeeway) > 7) ? "#e67e22" : "";
494
494
  updateLeewayDisplay(Math.max(-20, Math.min(20, smoothedLeeway)));
@@ -504,11 +504,11 @@ function startDisplayLoop() {
504
504
 
505
505
  // TIER SLOW (3s) - Medie Lunghe e Calcolo TACK
506
506
  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);
507
+ let hObj = getCircularAverageFromBuffer(store.longBuf.hdg, CONFIG.averaging.longWindow * 2, false);
508
+ let cObj = getCircularAverageFromBuffer(store.longBuf.cog, CONFIG.averaging.longWindow, false);
509
+ let awObj = getCircularAverageFromBuffer(store.longBuf.awa, CONFIG.averaging.longWindow, true);
510
+ let twObj = getCircularAverageFromBuffer(store.longBuf.twa, CONFIG.averaging.longWindow, true);
511
+ let twdObj = getCircularAverageFromBuffer(store.longBuf.twd, CONFIG.averaging.longWindow, false);
512
512
 
513
513
  upUI(ui.hdg, hObj, store.raw["navigation.headingTrue"], true);
514
514
  upUI(ui.cog, cObj, store.raw["navigation.courseOverGroundTrue"], true);
@@ -519,7 +519,7 @@ function startDisplayLoop() {
519
519
  // --- LOGICA TACK STRATEGICA (Riflessione geometrica su TWD) ---
520
520
  if (hObj && twdObj) {
521
521
  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;
522
+ const unstableH = !hObj.stable || !twdObj.stable || hObj.dev > CONFIG.averaging.stabilityBreakout || twdObj.dev > CONFIG.averaging.stabilityBreakout;
523
523
 
524
524
  if (!isNavigating) {
525
525
  ui.tackHdg.innerHTML = "---&deg;"; ui.tackHdg.classList.remove('unstable-data');
@@ -532,7 +532,7 @@ function startDisplayLoop() {
532
532
 
533
533
  if (cObj) {
534
534
  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;
535
+ const unstableC = !cObj.stable || !twdObj.stable || cObj.dev > CONFIG.averaging.stabilityBreakout || twdObj.dev > CONFIG.averaging.stabilityBreakout;
536
536
 
537
537
  if (!isNavigating) {
538
538
  ui.tackCog.innerHTML = "---&deg;"; ui.tackCog.classList.remove('unstable-data');
@@ -559,45 +559,57 @@ function startDisplayLoop() {
559
559
  // ==========================================================================
560
560
  // 8. CONFIGURAZIONE E GRAFICI UTILS
561
561
  // ==========================================================================
562
-
563
- /**
564
- * Recupera la configurazione dal server Signal K.
565
- * Prova i percorsi API ufficiali e quelli scoped (@sailingrotevista).
566
- * Converte i testi in numeri per garantire la precisione dei calcoli.
567
- */
568
562
  /**
569
- * Recupera la configurazione dal server Signal K.
570
- * Utilizza un approccio semplificato e converte i dati in numeri reali.
563
+ * Recupera la configurazione dal server con log di debug estesi.
571
564
  */
572
565
  async function fetchServerConfig() {
573
566
  try {
574
- // Puntiamo al percorso config del plugin
575
- const response = await fetch('/plugins/rotevista-dash/config');
576
- if (!response.ok) throw new Error(`Status: ${response.status}`);
577
-
578
- const actual = await response.json();
567
+ const response = await fetch('/rotevista-config');
568
+ if (!response.ok) throw new Error(`HTTP Error: ${response.status}`);
569
+
570
+ const data = await response.json();
571
+
572
+ // DEBUG 1: Visualizza i dati esattamente come arrivano dal server
573
+ console.log("📥 [DEBUG] Dati grezzi ricevuti dal server:", data);
579
574
 
580
- // FUNZIONE DI PARSING: Trasforma eventuali "20" (stringhe) in 20 (numeri)
581
575
  const parse = (obj) => {
582
576
  for (let k in obj) {
583
- if (typeof obj[k] === 'object') parse(obj[k]);
577
+ if (typeof obj[k] === 'object' && obj[k] !== null) parse(obj[k]);
584
578
  else if (!isNaN(obj[k]) && typeof obj[k] === 'string' && obj[k] !== "")
585
579
  obj[k] = parseFloat(obj[k]);
586
580
  }
587
581
  return obj;
588
582
  };
589
583
 
590
- const data = parse(actual.configuration || actual);
584
+ const actual = parse(JSON.parse(JSON.stringify(data))); // Cloniamo per sicurezza
585
+
586
+ // DEBUG 2: Visualizza i dati dopo la conversione numerica
587
+ console.log("⚙️ [DEBUG] Dati convertiti (numeric):", actual);
591
588
 
592
- // ASSEGNAZIONE DINAMICA: Aggiorna tutti i blocchi del CONFIG
593
- if (data.alarms) Object.assign(CONFIG.alarms, data.alarms);
594
- if (data.graphs) Object.assign(CONFIG.graphs, data.graphs);
595
- if (data.averaging) Object.assign(CONFIG.averages, data.averaging);
596
- if (data.scales) Object.assign(CONFIG.scales, data.scales);
589
+ // ASSEGNAZIONE E FUSIONE (Mappatura dei blocchi)
590
+ if (actual.alarms) Object.assign(CONFIG.alarms, actual.alarms);
591
+ if (actual.graphs) Object.assign(CONFIG.graphs, actual.graphs);
592
+
593
+ // Gestione specifica per averaging (il blocco più critico)
594
+ if (actual.averaging) {
595
+ Object.assign(CONFIG.averaging, actual.averaging);
596
+ // DEBUG 3: Tabella comparativa per verificare minSpeed e soglie
597
+ console.table({
598
+ "Parametro": ["longWindow", "minSpeed", "stabilityThreshold", "stabilityBreakout"],
599
+ "Valore Attuale": [
600
+ CONFIG.averaging.longWindow,
601
+ CONFIG.averaging.minSpeed,
602
+ CONFIG.averaging.stabilityThreshold,
603
+ CONFIG.averaging.stabilityBreakout
604
+ ]
605
+ });
606
+ }
607
+
608
+ if (actual.scales) Object.assign(CONFIG.scales, actual.scales);
597
609
 
598
- console.log("✅ Configurazione server caricata e sincronizzata.");
610
+ console.log("✅ [SUCCESS] Configurazione sincronizzata correttamente.");
599
611
  } catch (err) {
600
- console.warn("⚠️ Impossibile caricare config server, uso default locali.");
612
+ console.warn("⚠️ [WARNING] Utilizzo default locali. Motivo:", err.message);
601
613
  }
602
614
  }
603
615
 
package/index.js CHANGED
@@ -2,8 +2,8 @@
2
2
  * ==========================================================================
3
3
  * Rotevista Dash Configuration Plugin
4
4
  * ==========================================================================
5
- * Definisce l'interfaccia di configurazione in Signal K Admin.
6
- * Le descrizioni sono ottimizzate per riflettere l'utilizzo tattico e strategico.
5
+ * Definisce l'interfaccia di configurazione in Signal K Admin e crea
6
+ * l'endpoint pubblico per la comunicazione con la Dashboard.
7
7
  */
8
8
 
9
9
  module.exports = function (app) {
@@ -12,9 +12,25 @@ module.exports = function (app) {
12
12
  plugin.name = 'Rotevista Dash Configuration';
13
13
  plugin.description = 'Configure boat-specific tactical and safety parameters for the Dashboard';
14
14
 
15
- plugin.start = function (options) { };
16
- plugin.stop = function () { };
15
+ /**
16
+ * plugin.start: Inizializza il plugin e crea la rotta API per la Dashboard.
17
+ */
18
+ plugin.start = function (options) {
19
+ // Esponiamo i settings su un endpoint dedicato per bypassare i blocchi 401.
20
+ app.get('/rotevista-config', (req, res) => {
21
+ res.json(options);
22
+ });
17
23
 
24
+ app.debug('Rotevista Dashboard Config Endpoint active at /rotevista-config');
25
+ };
26
+
27
+ plugin.stop = function () {
28
+ // Pulizia risorse allo spegnimento del plugin.
29
+ };
30
+
31
+ /**
32
+ * plugin.schema: Definisce l'interfaccia grafica in Signal K Admin.
33
+ */
18
34
  plugin.schema = {
19
35
  type: 'object',
20
36
  title: 'Rotevista Dashboard Settings',
@@ -62,7 +78,6 @@ module.exports = function (app) {
62
78
  title: 'Strategic Timeline (Minutes)',
63
79
  description: "Total duration shown in the charts. Vertical grid lines mark 1-minute intervals for short durations and 5-minute intervals for long ones.",
64
80
  default: 5,
65
- // Menu a tendina per evitare inserimenti errati
66
81
  enum: [5, 10, 15, 30, 60]
67
82
  }
68
83
  }
@@ -76,7 +91,7 @@ module.exports = function (app) {
76
91
  longWindow: {
77
92
  type: 'number',
78
93
  title: 'Decision Stability Window (ms)',
79
- description: "The time range used to calculate MEAN values. A longer window (e.g. 30s) provides a solid base for strategy, while a shorter one reacts faster to ogni oscillation.",
94
+ description: "The time range used to calculate MEAN values. A longer window (e.g. 30s) provides a solid base for strategy, while a shorter one reacts faster to every oscillation.",
80
95
  default: 30000
81
96
  },
82
97
  smoothWindow: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sailingrotevista/rotevista-dash",
3
- "version": "4.0.12",
3
+ "version": "4.0.14",
4
4
  "description": "Public Wind Dashboard with navigation and course aids",
5
5
  "main": "index.js",
6
6
  "publishConfig": {