signalk-nightswimming-logger
v0.1.1
Published
SignalK plugin that buffers vessel data offline on the boat and pushes batched samples to the NightSwimming NAS backend. Custom built for my boat.
Maintainers
Readme
signalk-nightswimming-logger
Plugin SignalK per il diario di bordo della barca a vela NightSwimming. Vive sul Cerbo GX, sottoscrive i path SignalK, li bufferizza in SQLite locale, e li flusha a batch verso il backend NAS NightSwimming.
Componente A) dell'architettura del diario. Vedi
nightswimming-logbook-requirements.mde ADR-011 nel monorepo NightSwimming.
Filosofia
Plugin leggero per scelta progettuale. Trasporta dati, non li interpreta. Tutta la logica analitica (detection trip, classificazione stays, statistiche, reverse geocoding) sta sul NAS. Il plugin fa tre cose e basta:
- Subscribe ai path SignalK configurati
- Buffer in SQLite locale (
/data/nightswimming-logger.db) - Push batch HTTP al NAS quando connettività disponibile
ADR-011 vieta fork o dipendenza runtime da Saillogger. Saillogger resta come reference didattico: studiamo i loro path, le loro soglie, il loro pattern di buffer + flush, ma il codice è scritto da zero.
Installazione
Dal SignalK Admin UI (raccomandato)
- Builda localmente:
npm install && npm run build - Comprimi la cartella:
npm packproducesignalk-nightswimming-logger-X.Y.Z.tgz - SignalK Admin UI → Appstore → Install local plugin → carica il
.tgz
Da git clone direttamente
cd ~/.signalk/node_modules
git clone <repo-url> signalk-nightswimming-logger
cd signalk-nightswimming-logger
npm install
npm run build
# riavvia SignalK serverNota Cerbo Venus OS:
better-sqlite3è una dipendenza nativa. I prebuild upstream coprono Linux ARM64, ma su Venus OS specifico (basato su buildroot) potrebbe servire ricompilare. Se l'install fallisce con errori di link, vedi sezione Troubleshooting.
Configurazione
Tutti i parametri sono visibili e modificabili dall'admin UI di SignalK, sotto Server → Plugin Config → NightSwimming Logger.
| Campo | Default | Note |
|---|---|---|
| endpointUrl | https://api.teodorolio.com/api/logbook/ingest | Backend NAS |
| authToken | (vuoto) | Bearer token. Senza questo, il NAS rifiuterà i POST con 401. |
| sampleIntervalSec | 30 | Snapshot ogni N secondi. Min 5. |
| flushIntervalSec | 60 | Push batch ogni N secondi. Min 30. |
| flushBatchSize | 200 | Punti per POST. Min 10. |
| maxBufferSizeMb | 50 | Cap circular buffer SQLite. Min 10. ~30 giorni a 30s/snapshot. |
| pathsToSubscribe | (8 path nautici di base) | Vedi sotto. |
| pluginInstanceId | (auto) | UUID generato e persistito al primo start. |
Path sottoscritti di default
navigation.position
navigation.speedOverGround
navigation.courseOverGroundTrue
navigation.headingTrue
environment.wind.speedTrue
environment.wind.angleTrueWater
environment.depth.belowKeel
environment.outside.pressurePath mancanti (es. niente trasduttore di profondità, vento reale che richiede
signalk-derived-data) restano null nello snapshot — nessun errore.
Per aggiungerne altri (RPM motore, batterie, tank levels) basta inserirli
nel campo pathsToSubscribe dell'admin UI; il NAS li riceverà come campi
extra nel JSON.
Come funziona
SignalK delta stream ──► lastValues Map (in-memory, sticky)
│
▼ (ogni sampleIntervalSec)
takeSnapshot() ──► SQLite buffer
│
▼ (ogni flushIntervalSec)
POST /api/logbook/ingest ──► NAS
│
errore? backoff 60→900s
success? markFlushedIl subscribe handler aggiorna una mappa in memoria lastValues ad ogni
delta. Il timer di snapshot ogni N secondi prende l'ultimo valore noto
di ogni path e lo scrive come singolo record nel buffer SQLite. Il flusher
ogni M secondi tenta un POST batch al NAS. In caso di errore di rete, backoff
esponenziale capped a 15 minuti. In caso di 4xx (richiesta malformata o auth
errata) droppa il batch per non loopare e logga in modo molto visibile.
Il pluginInstanceId è un UUID generato al primo start e persistito (sia in
savePluginOptions se il server lo espone, sia in instance-id.json come
fallback). Serve al NAS come parte della chiave di idempotency
(pluginInstanceId, ts): un batch ricevuto due volte non duplica record.
Troubleshooting
NAS unreachable, retry in N min permanente
- Verifica connettività da Cerbo:
ping <NAS hostname o IP> - Verifica che il NAS sia in Tailscale e raggiungibile da bordo
- Verifica che
endpointUrlsia corretto (incluso/api/logbook/ingest) - Verifica certificato SSL valido se usi HTTPS
Auth/payload error 401
- Token vuoto o sbagliato. Sostituiscilo nell'admin UI e riavvia il plugin.
Auth/payload error 400
- Il backend ha rifiutato il payload. Disallineamento di schema fra plugin e backend (probabile bug). Il batch viene droppato per non loopare; controlla i log del backend per il dettaglio dell'errore.
Buffer non si svuota mai
- Conta righe pendenti via SQLite CLI:
sqlite3 /path/to/nightswimming-logger.db 'SELECT COUNT(*) FROM points;' - Se cresce indefinitamente: il flusher è in errore. Guarda i log SignalK.
Errori di build di better-sqlite3 su Venus OS
- Prova
npm install --build-from-source better-sqlite3 - Verifica di avere
python3,make,g++installati nell'environment di build - In ultima istanza, builda il
.tgzsu una macchina simile (Debian ARM64) e copialo sul Cerbo
Resettare l'instance ID
- Cancella
instance-id.jsondaapp.getDataDirPath()(di solito~/.signalk/plugin-config-data/signalk-nightswimming-logger/) e riavvia. - Effetto: il NAS tratterà i prossimi batch come da una nuova identità di logger. I dati esistenti restano, vengono solo deduplicati indipendentemente.
Riferimenti
- ADR-011 in
documentation/nightswimming-adr.md(monorepo NswmApp) — decisione "plugin custom da zero, no fork Saillogger" - Requirements completi in
documentation/nightswimming-logbook-requirements.md— sezioni 3 (architettura), 4.1 (path), 6.1 (questo plugin), 6.4 (riconciliazione con Livello 3 VRM) - SignalK Plugin API — https://demo.signalk.org/documentation/develop/plugins/server_plugin_api.html
- Saillogger (reference didattico, non dipendenza) — https://github.com/Saillogger/signalk-saillogger
Licenza
MIT — Teodoro Lio
