- Added rulesets manager to handle various data types and updates via HTTP and WebSocket. - Introduced layout store for managing kiosk layouts with caching and server synchronization. - Enhanced dashboard and data routes to support new layout and ruleset features. - Updated kiosk HTML and JavaScript to utilize new layout rendering and data binding. - Removed obsolete map route and integrated map functionality into the new tile renderer. - Improved Telegram commands to reflect changes in data structure and logging. - Refactored weather fetching intervals to prevent multiple instances. - Added SSE stream for real-time layout updates in the kiosk.
73 lines
2.9 KiB
JavaScript
73 lines
2.9 KiB
JavaScript
/**
|
|
* data-binder.js — apre una singola sottoscrizione SignalK delta locale
|
|
* e smista i valori ai tile per path.
|
|
*
|
|
* Espone window.dataBinder con:
|
|
* subscribe(path, fn) → unsubscribe()
|
|
* getLatest(path) → ultimo valore visto (o null)
|
|
* onConnState(fn) → notifica connesso/disconnesso
|
|
*/
|
|
(function () {
|
|
const subs = new Map(); // path -> Set<fn>
|
|
const latest = new Map(); // path -> { value, ts }
|
|
const stateListeners = new Set();
|
|
let ws = null;
|
|
let reconnectTimer = null;
|
|
|
|
function notify(path, value) {
|
|
latest.set(path, { value, ts: Date.now() });
|
|
const ss = subs.get(path);
|
|
if (!ss) return;
|
|
for (const fn of ss) { try { fn(value); } catch (e) { console.warn(e); } }
|
|
}
|
|
|
|
function notifyState(s) { for (const fn of stateListeners) { try { fn(s); } catch (_) {} } }
|
|
|
|
function connect() {
|
|
const url = `ws://${location.host}/signalk/v1/stream?subscribe=all`;
|
|
try { ws = new WebSocket(url); }
|
|
catch (err) { console.error('[BINDER] WS create:', err); scheduleReconnect(); return; }
|
|
|
|
ws.onopen = () => { notifyState({ connected: true }); console.log('[BINDER] WS connected'); };
|
|
ws.onerror = (e) => console.warn('[BINDER] WS error', e);
|
|
ws.onclose = () => { notifyState({ connected: false }); scheduleReconnect(); };
|
|
ws.onmessage = (ev) => {
|
|
let msg;
|
|
try { msg = JSON.parse(ev.data); } catch { return; }
|
|
if (!msg.updates) return;
|
|
for (const u of msg.updates) {
|
|
if (!u.values) continue;
|
|
for (const v of u.values) {
|
|
if (!v.path) continue;
|
|
notify(v.path, v.value);
|
|
// espandi position in lat/lon per chi si iscrive a quelli
|
|
if (v.path === 'navigation.position' && v.value && typeof v.value === 'object') {
|
|
if (v.value.latitude != null) notify('navigation.position.latitude', v.value.latitude);
|
|
if (v.value.longitude != null) notify('navigation.position.longitude', v.value.longitude);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
function scheduleReconnect() {
|
|
if (reconnectTimer) return;
|
|
reconnectTimer = setTimeout(() => { reconnectTimer = null; connect(); }, 3000);
|
|
}
|
|
|
|
function subscribe(path, fn) {
|
|
if (!subs.has(path)) subs.set(path, new Set());
|
|
subs.get(path).add(fn);
|
|
const last = latest.get(path);
|
|
if (last) { try { fn(last.value); } catch (_) {} }
|
|
return () => subs.get(path)?.delete(fn);
|
|
}
|
|
|
|
function getLatest(path) { return latest.get(path)?.value ?? null; }
|
|
function onConnState(fn) { stateListeners.add(fn); return () => stateListeners.delete(fn); }
|
|
|
|
connect();
|
|
|
|
window.dataBinder = { subscribe, getLatest, onConnState };
|
|
})();
|