• Creato un nuovo file CSS per gli stili del chiosco (kiosk) con variabili, stili per le schede (card) e animazioni. • Aggiunto un file HTML per l'interfaccia della mappa utilizzando Mapbox, inclusi gli stili e il JavaScript per le funzionalità della mappa. • Introdotto un file JSON per i riferimenti ai sensori, definendo percorsi ed elementi per i dati di temperatura, vento, onde, posizione, batteria, motore e sistema. Co-authored-by: Copilot <copilot@github.com>
172 lines
5.3 KiB
JavaScript
172 lines
5.3 KiB
JavaScript
let skApp = null;
|
|
|
|
/**
|
|
* Inizializza il modulo con l'istanza dell'app Signal K.
|
|
* Da chiamare una sola volta nel plugin.start()
|
|
* @param {Object} app - l'istanza dell'applicazione Signal K
|
|
*/
|
|
function init(app) {
|
|
skApp = app;
|
|
}
|
|
|
|
/**
|
|
* Pubblica un set di dati nel data browser di Signal K tramite i delta.
|
|
* @param {Object} data - Oggetto JSON dove le chiavi sono i percorsi e i valori sono i dati da pubblicare
|
|
*/
|
|
function publish(data) {
|
|
|
|
//TODO: Controlla se serve aggiungere typeof skApp.handleMessage !== 'function' (controlla che esista la funzione handleMessage, ma in teoria esiste sempre)
|
|
if (!skApp) {
|
|
console.error('[SKFLOW] skApp non inizializzato')
|
|
return;
|
|
}
|
|
|
|
if (!data || typeof data !== 'object') {
|
|
console.error('[SKFLOW] Dati non validi')
|
|
return;
|
|
}
|
|
|
|
const values = Object.entries(data).map(([path, value]) => {
|
|
return {
|
|
path: path,
|
|
value: value
|
|
};
|
|
});
|
|
|
|
//La funzione non continua se non ci sono dati
|
|
//TODO: Controllare se serve davvero, non dovrebbe interrompersi già al check di data?
|
|
if (values.length === 0) return;
|
|
|
|
// Viene creato un "Delta Update" con l'ID del plugin 'meb.plugin' e l'array di valori.
|
|
skApp.handleMessage('meb.plugin', {
|
|
updates: [
|
|
{
|
|
values: values
|
|
}
|
|
]
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Ottieni i dati dal Data-Browser di Signal K
|
|
* @param {String} path - Il path Signal K
|
|
* @returns {*} Il dato
|
|
*/
|
|
function get(path) {
|
|
if (!skApp) {
|
|
return null;
|
|
}
|
|
|
|
const valObj = skApp.getSelfPath(path);
|
|
return valObj ? valObj.value : null;
|
|
}
|
|
|
|
/**
|
|
* Ottieni tutti i dati nel databrowser di Signal K che corrispondono ad un ID o ad una sorgente specifica.
|
|
* @param {String} source - Il parametro da confrontare con il sorgente ($source o source) o ID del dato.
|
|
* @returns {Object} Un oggetto contenente path e valori trovati.
|
|
*/
|
|
function getBySource(source) {
|
|
if (!skApp) return {};
|
|
|
|
const results = {};
|
|
const self = skApp.signalk?.self || skApp.signalk?.retrieve()?.vessels?.[skApp.selfId] || {};
|
|
|
|
if (!self || Object.keys(self).length === 0) {
|
|
console.log('[SKFLOW] Nessun dato trovato nel databrowser');
|
|
return results;
|
|
}
|
|
|
|
const traverse = (obj, path = '') => {
|
|
if (!obj || typeof obj !== 'object') return;
|
|
|
|
// Se l'oggetto ha una proprietà 'value', verifichiamo la sorgente
|
|
if (Object.prototype.hasOwnProperty.call(obj, 'value')) {
|
|
const hasSource = obj.$source === source || obj.source === source || obj.id === source;
|
|
if (hasSource) {
|
|
results[path] = obj.value;
|
|
}
|
|
}
|
|
|
|
// Esplora i sotto-oggetti escludendo chiavi di sistema che non sono percorsi SK
|
|
const skip = ['value', 'timestamp', '$source', 'source', 'meta', 'sentence', 'talker'];
|
|
for (const key in obj) {
|
|
if (skip.includes(key)) continue;
|
|
const subPath = path ? `${path}.${key}` : key;
|
|
traverse(obj[key], subPath);
|
|
}
|
|
};
|
|
|
|
traverse(self);
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* Ottieni tutti i dati nel databrowser di Signal K il cui path inizia con la stringa specificata.
|
|
* @param {String} filterPath - La stringa con cui deve iniziare il path (es. "custom.plugin").
|
|
* @returns {Object} Un oggetto contenente path e valori trovati.
|
|
*/
|
|
function getWithFilter(filterPath) {
|
|
if (!skApp) return {};
|
|
|
|
const results = {};
|
|
const self = skApp.signalk?.self || skApp.signalk?.retrieve()?.vessels?.[skApp.selfId] || {};
|
|
|
|
if (!self || Object.keys(self).length === 0) {
|
|
return results;
|
|
}
|
|
|
|
const traverse = (obj, path = '') => {
|
|
if (!obj || typeof obj !== 'object') return;
|
|
|
|
// Se l'oggetto ha una proprietà 'value', verifichiamo se il path corrisponde al filtro
|
|
if (Object.prototype.hasOwnProperty.call(obj, 'value')) {
|
|
if (path.startsWith(filterPath)) {
|
|
results[path] = obj.value;
|
|
}
|
|
}
|
|
|
|
// Esplora i sotto-oggetti escludendo chiavi di sistema
|
|
const skip = ['value', 'timestamp', '$source', 'source', 'meta', 'sentence', 'talker'];
|
|
for (const key in obj) {
|
|
if (skip.includes(key)) continue;
|
|
const subPath = path ? `${path}.${key}` : key;
|
|
|
|
// Ottimizzazione: se `subPath` non inizia con `filterPath` E `filterPath` non inizia con `subPath`,
|
|
// possiamo evitare di scendere in rami completamente irrilevanti.
|
|
// (es. filter = "environment." e subPath = "navigation." -> skippa)
|
|
if (!subPath.startsWith(filterPath) && !filterPath.startsWith(subPath)) continue;
|
|
|
|
traverse(obj[key], subPath);
|
|
}
|
|
};
|
|
|
|
traverse(self);
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* Ottieni un oggetto con path e valori per una lista specifica di path.
|
|
* @param {Array<String>} data - Un array contenente i path di Signal K da recuperare.
|
|
* @returns {Object} Un oggetto JSON con elementi path: value.
|
|
*/
|
|
function getFrom(data) {
|
|
if (!Array.isArray(data)) return {};
|
|
|
|
const results = {};
|
|
for (const path of data) {
|
|
results[path] = get(path);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
module.exports = {
|
|
init,
|
|
publish,
|
|
get,
|
|
getBySource,
|
|
getWithFilter,
|
|
getFrom
|
|
};
|