Integraciones marinas: la puntuación de confianza en el puente
La puntuación de confianza marítima de Kshana (MARITIME-TRUST.md) es accesible desde software que los navegantes ya usan: un complemento para servidor Signal K y OpenCPN mediante NMEA en modo de puerta sobre TCP. Una compilación de referencia la pone en un ordenador pequeño junto al receptor.
Software de carácter consultivo. Kshana no es un equipo de navegación homologado (IEC 61108, IEC 61162) y no se ha evaluado frente a ninguna norma de rendimiento. Todo lo de esta página es una ayuda al criterio del navegante. El operador sigue siendo responsable de la navegación segura del buque y de cualquier decisión de fiarse, o de dejar de fiarse, de una posición. Nada de aquí transmite, y nada de aquí hace más exacta una posición.
| Pieza | Dónde | Estado en 0,35 |
|---|---|---|
| Plugin de Signal K | integrations/signalk/ |
entregado, con pruebas unitarias sobre salida sintética grabada; no publicado en npm |
| OpenCPN mediante NMEA en modo de puerta sobre TCP | integrations/opencpn/ |
entregado y probado (reproducción del lado del consumidor); ninguna prueba maneja la propia interfaz de usuario de OpenCPN |
| Complemento nativo de OpenCPN con panel de puntuación | integrations/opencpn/plugin/ |
compilado, con la lógica probada por unidades y ejecutado dentro de OpenCPN 5.8.4 bajo una pantalla virtual (evidencias en integrations/opencpn/evidence/); no empaquetado para el gestor de complementos; solo se entregará tras revisión |
| Compilación de referencia | deploy/reference-build/ |
piezas, pasos del sistema operativo, unidades systemd (comprobadas en simulación), una opción de contenedor; no probado en un buque |
Todo ello lee una sola cosa: la salida de kshana receiver-trust live (líneas JSON, la sentencia $PKSHT, la puerta). Los formatos de transmisión están en MARITIME-TRUST.md. El complemento de Signal K concentra su conocimiento de ellos en un solo archivo, integrations/signalk/lib/adapter.js; un cambio de formato es una edición de un solo archivo.
Plugin de Signal K#
Sin dependencias de npm. El complemento en sí se ejecuta en Node 18 o posterior; las versiones actuales de signalk-server requieren Node 22 o posterior, así que en la práctica use 22. Copie o enlace integrations/signalk/ en el node_modules del servidor (por ejemplo ~/.signalk/node_modules/signalk-kshana-trust), reinicie el servidor y active Kshana GNSS trust en Server, Plugin Config.
De dónde proceden las épocas (source)#
source |
Qué hace el complemento |
|---|---|
spawn-signalk-nmea (por defecto) |
Ejecuta kshana receiver-trust live <sessionFile> y escribe en su entrada estándar cada sentencia NMEA 0183 sin procesar que recibe el servidor (el evento nmea0183 del servidor). Lo reinicia, con espera creciente, si termina | Úselo solo en un servidor con una única fuente NMEA: introduce cada sentencia de cada proveedor, entremezcladas, de modo que un segundo receptor GNSS o un AIS parece un receptor cuya posición salta y puede puntuarse como suplantación. Con más de una fuente use spawn-args con el propio flujo --tcp de ese receptor, o tcp-pksht desde una puerta. |
spawn-args |
Ejecuta kshana receiver-trust live <sessionFile> <inputArgs...>, por ejemplo ["--tcp","192.0.2.10:10110"] o ["--udp","10110"] |
tcp-json |
Se conecta a un flujo de las líneas JSON que escribe kshana (por ejemplo desde el relé de integrations/opencpn/) |
tcp-pksht |
Se conecta a un flujo NMEA (como la salida de puerta del servicio o del contenedor de la compilación de referencia, puerto 10110) y lee solo sus sentencias $PKSHT |
Un flujo que ya está siendo suplantado cuando el monitor se conecta por primera vez no tiene una línea base limpia (los primeros calibration_s segundos nunca se puntúan). Inícielo antes de la travesía.
Rutas publicadas#
Cada época actualiza (fuente kshana-trust):
| Ruta | Valor |
|---|---|
navigation.gnss.kshana.band |
calibrating, nominal, degraded o untrusted |
navigation.gnss.kshana.score |
de 0 a 100, o null durante la calibración |
navigation.gnss.kshana.reasons |
[{monitor, points}], de mayor a menor: qué comprobaciones redujeron la puntuación |
navigation.gnss.kshana.alarms |
los monitores que superan actualmente su umbral |
navigation.gnss.kshana.gate |
off, passed o withheld (cuando hay una puerta en funcionamiento en otro lugar; null desde $PKSHT cuando está ausente) |
navigation.gnss.kshana.reportedPosition |
{latitude, longitude, altitude}: la posición que el receptor sometido a prueba notificó en esa época (esquema JSON 1,1 o posterior; no se publica cuando el flujo no la lleva, por ejemplo desde $PKSHT o un kshana anterior). Solo contexto de confianza: el complemento nunca escribe navigation.position, por lo que la ruta de posición propia del buque queda intacta |
notifications.navigation.gnss.kshana.trust |
se emite cuando cambia el estado: {state, method, message} |
El complemento también envía una vez al inicio metadatos de Signal K para estas rutas. score es la puntuación de confianza de Kshana de 0 a 100, una puntuación y no una razón ni una probabilidad, por lo que no lleva unidad SI; sus metadatos dan el intervalo, una descripción y zonas que siguen los umbrales de abajo. reasons[].points son puntos de puntuación restados de esa puntuación de 0 a 100.
La notificación es normal, alert, warn o alarm. Se borra publicando el estado normal, no null: un consumidor que solo trata null como borrado debe tratar también normal como borrado. Por defecto, la banda degraded da warn y la banda untrusted da alarm, con method: ["visual","sound"]. Se rebaja tras clearAfterEpochs épocas en un estado mejor. Si no llega ninguna época durante staleAfterS segundos, avisa de que la puntuación no se está actualizando. La calibración nunca genera una notificación. La fuente $PKSHT no lleva lista alarms (la sentencia solo contiene la banda, la puntuación y los dos motivos principales).
Configuración (cada umbral)#
| Clave | Valor por defecto | Significado |
|---|---|---|
source |
spawn-signalk-nmea |
véase más arriba |
command |
kshana |
el ejecutable (modos de ejecución). Ejecuta cualquier ejecutable con el usuario del servidor: solo un administrador del servidor Signal K debería poder cambiar la configuración del complemento |
sessionFile |
/etc/kshana/session.toml |
los límites, umbrales y pesos de puntuación del buque (modos de ejecución) |
inputArgs |
[] |
argumentos añadidos a kshana receiver-trust live <sessionFile> en ambos modos de ejecución: la entrada para spawn-args, indicadores adicionales como --replay (un registro almacenado alimentado más rápido que en tiempo real) para spawn-signalk-nmea. El complemento rechaza --gate, --listen, --json y --pksht (lee el JSON de kshana en la salida estándar) y, para spawn-signalk-nmea, también los indicadores de entrada (--stdin, --file, --tcp, --udp, --follow, --from-end) |
host, port |
127.0.0.1, 10111 |
Modos TCP (la puerta sirve en 10110: fije el puerto para tcp-pksht) |
thresholdMode |
band |
band: la banda que notifica Kshana, con los bordes en el archivo de sesión. score: las dos puntuaciones de abajo |
warnBelowScore |
90 |
modo score: por debajo de este valor el estado es degradedState (el borde por defecto de Kshana para nominal) |
alarmBelowScore |
55 |
modo score: por debajo de este valor el estado es alarm (el borde por defecto de Kshana para degraded) |
degradedState |
warn |
estado para la banda degraded: normal, alert o warn |
raiseAfterEpochs |
1 |
épocas consecutivas en un estado peor antes de emitir la notificación |
clearAfterEpochs |
10 |
épocas consecutivas en un estado mejor antes de rebajarla |
staleAfterS |
10 |
avisa cuando no llega ninguna época durante este tiempo; 0 lo desactiva |
method |
["visual","sound"] |
métodos de notificación |
El complemento no actúa como puerta: nunca altera una posición. Marcar una posición como no válida para un sistema de cartas es la puerta, más abajo.
Pruebas#
cd integrations/signalk && npm test
node:test, sin dependencias, sin red salvo 127.0.0.1. Las pruebas analizan y reproducen un extracto de 66 épocas de las líneas JSON y de las sentencias $PKSHT que kshana receiver-trust live escribió para la demostración sintética del Báltico (datos inventados, solo texto), comprueban la coincidencia entre los dos formatos, el comportamiento de retención y de borrado, el modo de puntuación, la obsolescencia y las tres vías de entrada frente a un flujo local y un proceso hijo sustituto. Esas pruebas no inician un servidor Signal K real; una ejecución con guion aparte sí lo hace, véase abajo.
Ejecución en un servidor Signal K real#
integrations/signalk/evidence/ contiene un guion que carga el complemento en el paquete signalk-server 2.33.0 fijado (en un espacio de nombres de red privado solo de bucle local) y registra lo que muestran las propias API REST y WebSocket del servidor. Las rutas de confianza aparecen, la notificación pasa por warn, alarm, normal (tras la retención) y warn de nuevo cuando cesan los datos, y con el kshana real alimentado por la propia entrada NMEA del servidor también publicó reportedPosition, nunca navigation.position. Una versión de servidor, una ejecución, ningún buque real; límites y reproducción en el README de las evidencias.
OpenCPN#
OpenCPN lee NMEA de la red, y kshana receiver-trust live --gate puede servir por sí mismo el flujo filtrado por la puerta en un puerto TCP.
Recomendado: la conexión directa.
some-nmea-source | kshana receiver-trust live session.toml --gate --listen tcp:10110
(some-nmea-source es el puerto serie del receptor leído con stty y cat, un multiplexor, o las entradas --tcp/--udp del propio kshana; el kshana-gate.service de la compilación de referencia lo hace bajo systemd.) --listen tcp:<port> se enlaza a la dirección de bucle local; puede conectarse cualquier número de clientes de solo lectura, y el que no pueda seguir el ritmo se descarta sin retrasar a los demás.
Alternativa: el relé. integrations/opencpn/nmea-tcp-relay.mjs es un distribuidor Node sin dependencias que hace lo mismo para un kshana sin --listen, o que sirve cualquier otro flujo de líneas (la opción de contenedor lo usa para las épocas JSON):
some-nmea-source | kshana receiver-trust live session.toml --gate --json trust.jsonl \
| node integrations/opencpn/nmea-tcp-relay.mjs --listen 10110
Reenvía los bytes sin cambios, solo líneas completas, y descarta a un cliente que no lee. Prefiera la conexión directa: un proceso menos en la cadena.
En OpenCPN: Options, Connections, Add Connection, Network, protocolo TCP, dirección 127.0.0.1, puerto 10110, sentido Input. Mientras la confianza no se haya hundido, el flujo es el propio del receptor, más una sentencia $PKSHT por ciclo. Mientras está hundida, la GGA reenviada tiene calidad 0, el estado de RMC V, y los indicadores de modo dicen que no hay solución, con las sumas de comprobación recalculadas: el equipo ve que el propio receptor declara la posición no válida y activa su propia alarma. Las sentencias $PKSHT son visibles en la ventana de depuración NMEA de OpenCPN (Options, Connections, "NMEA debug window"). Los campos de posición se dejan tal como se recibieron.
Lea "Gate mode" en MARITIME-TRUST.md antes de fiarse de esto: es opcional, añade latencia (un ciclo se retiene hasta que se puntúa su época), es un punto único en la cadena y puede retener una buena posición además de dejar pasar una falsificada.
Pruebas#
cd integrations/opencpn && npm test
test/relay.test.mjs reproduce un extracto grabado del flujo sintético filtrado por la puerta (186 sentencias en torno al momento en que se hunde la confianza, escritas por kshana receiver-trust live --gate) a través del relé sobre un socket TCP real y comprueba lo que recibe un consumidor: el flujo byte a byte con fragmentación arbitraria; sumas de comprobación válidas en cada sentencia, incluidas las reescritas; GGA y RMC coincidentes, válidas y luego no válidas sin parpadeo; una $PKSHT por ciclo con su campo de puerta W exactamente donde la posición no es válida; dos consumidores idénticos; una línea parcial nunca reenviada. Esto comprueba el flujo que se entrega a OpenCPN, no la pantalla propia de OpenCPN.
Una comprobación de extremo a extremo con el binario real, que no forma parte de las pruebas por defecto (necesita un kshana compilado):
KSHANA_BIN=target/release/kshana npm run e2e # kshana --gate --listen | TCP consumer; the consumer's bytes must equal the gate's stdout
KSHANA_BIN=target/release/kshana npm run e2e -- relay # kshana --gate | relay | TCP consumer
Ambas ejecutan la demostración sintética de una hora y comprueban que la posición pasa a válida y luego a no válida, con una $PKSHT por época.
Complemento nativo#
integrations/opencpn/plugin/ es un panel de puntuación para OpenCPN (puntuación, banda, puerta, motivos principales, una alerta cuando la confianza pasa a untrusted) que lee $PKSHT del propio flujo NMEA de OpenCPN, por lo que no necesita ninguna conexión más allá de la anterior. Se compila con CMake contra la cabecera de la API de complementos de OpenCPN (incluida, con su commit de origen) y wxWidgets; ctest ejecuta las pruebas de lógica sin wx y comprueba que la biblioteca exporta los puntos de entrada que busca OpenCPN. Se ha ejecutado dentro de OpenCPN 5.8.4 bajo una pantalla virtual con el flujo sintético filtrado por la puerta (OpenCPN entregó $PKSHT al complemento, el panel se puso en rojo y la propia posición de OpenCPN se congeló cuando se activó la puerta; capturas, registro y guion en integrations/opencpn/evidence/), pero no en un escritorio real, ni en otras versiones o plataformas, y no está empaquetado para el gestor de complementos de OpenCPN. Véase el README.md del complemento. Tiene licencia GPL-3.0-or-later, a diferencia del resto del repositorio (LICENSING.md).
Capturas de esa ejecución, en integrations/opencpn/evidence/ (una ejecución, OpenCPN 5.8.4 bajo una pantalla virtual, datos sintéticos; README.md da los límites):
Estas capturas muestran la instalación y la llegada de la posición filtrada por la puerta a OpenCPN, no que alguna alarma sea oportuna o correcta para un buque real. Software de carácter consultivo, no un equipo homologado.
Compilación de referencia#
deploy/reference-build/: una lista genérica de piezas, la configuración del sistema operativo, dos unidades systemd (el monitor consultivo y la puerta opcional), una opción de contenedor y el cableado de Signal K. deploy/reference-build/check-units.sh ejecuta systemd-analyze verify sobre las unidades sin iniciar nada.
Límites#
- La puntuación vale lo que valgan las comprobaciones que la respaldan, que examinan la física de un buque y sus demás sensores; una falsificación autoconsistente con un reloj coincidente no la ven los monitores solo de NMEA (
MARITIME-TRUST.md). La ausencia de una alarma no es evidencia de una buena posición. - Ninguna cifra de esta página es una tasa de detección o de falsa alarma medida. Las pruebas anteriores comprueban la instalación con texto sintético; no dicen nada sobre cómo se comporta ningún monitor frente a interferencias reales.
- No homologado; el operador sigue siendo responsable.