• 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>
91 lines
3.6 KiB
JavaScript
91 lines
3.6 KiB
JavaScript
/**
|
|
* Kiosk plugin page bootstrap:
|
|
* 1) legge config dal <meta> iniettato dal server del plugin
|
|
* 2) carica template attivo via API
|
|
* 3) apre WS locale SignalK per i valori live
|
|
* 4) apre WS "leggero" al realtime server per comandi dalla console
|
|
*/
|
|
(async function () {
|
|
function cfg(name, fallback) {
|
|
const m = document.querySelector(`meta[name="${name}"]`);
|
|
return (m && m.content) || fallback;
|
|
}
|
|
|
|
const apiUrl = cfg('api-url', 'https://api.mebboat.it');
|
|
const realtimeUrl = cfg('realtime-url', 'https://realtime.mebboat.it');
|
|
const realtimeWsUrl = cfg('realtime-ws-url', 'wss://realtime.mebboat.it');
|
|
const sensorCode = cfg('sensor-code', '');
|
|
const sensorName = cfg('sensor-name', '');
|
|
|
|
window.kiosk.init({ apiUrl, sensorCode, sensorName });
|
|
|
|
// 1) template iniziale
|
|
await window.kiosk.loadTemplate();
|
|
|
|
// 2) WS locale SignalK
|
|
try {
|
|
const skWs = new WebSocket(`ws://${location.host}/signalk/v1/stream?subscribe=all`);
|
|
skWs.onmessage = (ev) => {
|
|
let msg; try { msg = JSON.parse(ev.data); } catch { return; }
|
|
for (const u of msg.updates || []) for (const v of u.values || []) {
|
|
window.kiosk.updateValue(v.path, v.value);
|
|
}
|
|
};
|
|
skWs.onclose = () => setTimeout(() => location.reload(), 5000);
|
|
} catch (e) { console.error('[kiosk] signalk ws error', e); }
|
|
|
|
// 3) WS controllo verso realtime server
|
|
if (!sensorCode || !sensorName) { window.kiosk.setStatus('no sensor config', true); return; }
|
|
|
|
let controlWs = null;
|
|
let reconnectTm = null;
|
|
|
|
async function fetchSocketToken() {
|
|
const r = await fetch(`${realtimeUrl}/connect`, {
|
|
method: 'POST', headers: { 'Content-Type':'application/json' },
|
|
body: JSON.stringify({ name: sensorName, code: sensorCode })
|
|
});
|
|
if (!r.ok) return null;
|
|
const j = await r.json();
|
|
return j.s === 'ok' ? j.t : null;
|
|
}
|
|
|
|
async function connectControl() {
|
|
clearTimeout(reconnectTm);
|
|
const token = await fetchSocketToken();
|
|
if (!token) { reconnectTm = setTimeout(connectControl, 5000); return; }
|
|
const url = `${realtimeWsUrl}/kiosk?role=device&sensor=${encodeURIComponent(sensorName)}&token=${encodeURIComponent(token)}`;
|
|
controlWs = new WebSocket(url);
|
|
controlWs.onopen = () => {
|
|
controlWs.send(JSON.stringify({ t:'hello', templateId: window.kiosk.currentTemplateId() }));
|
|
};
|
|
controlWs.onmessage = async (ev) => {
|
|
let m; try { m = JSON.parse(ev.data); } catch { return; }
|
|
let ok = true, err = null;
|
|
try {
|
|
switch (m.t) {
|
|
case 'patch_box': ok = window.kiosk.patchBox(m.boxId, m.patch || {}); break;
|
|
case 'add_box': ok = window.kiosk.addBox(m.box); break;
|
|
case 'remove_box': ok = window.kiosk.removeBox(m.boxId); break;
|
|
case 'load_template': {
|
|
const tpl = await window.kiosk.loadTemplate(m.templateId);
|
|
ok = !!tpl;
|
|
break;
|
|
}
|
|
case 'apply_inline': ok = window.kiosk.applyInline(m.content); break;
|
|
case 'persist': ok = true; break; // no-op locale, la persistenza è server-side
|
|
case 'reload': location.reload(); return;
|
|
default: ok = false; err = 'unknown cmd';
|
|
}
|
|
} catch (e) { ok = false; err = e.message; }
|
|
if (m.cmdId) controlWs.send(JSON.stringify({ t:'ack', cmdId: m.cmdId, ok, err }));
|
|
};
|
|
controlWs.onclose = () => { reconnectTm = setTimeout(connectControl, 5000); };
|
|
controlWs.onerror = () => { try { controlWs.close(); } catch {} };
|
|
|
|
setInterval(() => { if (controlWs && controlWs.readyState === 1) controlWs.send(JSON.stringify({ t:'heartbeat' })); }, 25000);
|
|
}
|
|
|
|
connectControl();
|
|
})();
|