Intégrations maritimes : le score de confiance à la passerelle
Le score de confiance maritime de Kshana (MARITIME-TRUST.md) est accessible depuis des logiciels que les plaisanciers utilisent déjà : un module d'extension de serveur Signal K et OpenCPN via du NMEA en mode barrière sur TCP. Une construction de référence l'installe sur un petit ordinateur à côté du récepteur.
Logiciel à titre consultatif. Kshana n'est pas un équipement de navigation homologué (IEC 61108, IEC 61162) et n'a été évalué par rapport à aucune norme de performance. Tout ce qui figure sur cette page est une aide au jugement du navigateur. L'opérateur reste responsable de la sécurité de la navigation du navire et de toute décision de s'appuyer, ou de cesser de s'appuyer, sur un point de position. Rien ici n'émet, et rien ici ne rend un point de position plus précis.
| Élément | Où | État dans 0,35 |
|---|---|---|
| Module d'extension Signal K | integrations/signalk/ |
livré, testé unitairement sur une sortie synthétique enregistrée ; non publié sur npm |
| OpenCPN via du NMEA en mode barrière sur TCP | integrations/opencpn/ |
livré et testé (rejeu côté consommateur) ; l'interface utilisateur d'OpenCPN elle-même n'est pilotée par aucun test |
| Module d'extension natif OpenCPN à panneau de score | integrations/opencpn/plugin/ |
construit, logique testée unitairement, et exécuté dans OpenCPN 5.8.4 sous un affichage virtuel (preuves dans integrations/opencpn/evidence/) ; non empaqueté pour le gestionnaire de modules d'extension ; ne sera livré qu'après relecture |
| Construction de référence | deploy/reference-build/ |
pièces, étapes du système d'exploitation, unités systemd (vérifiées à blanc), une option conteneur ; non testé sur un navire |
Tout cela lit une seule chose : la sortie de kshana receiver-trust live (lignes JSON, la phrase $PKSHT, la barrière). Les formats de transmission sont décrits dans MARITIME-TRUST.md. Le module d'extension Signal K conserve ce qu'il en sait dans un seul fichier, integrations/signalk/lib/adapter.js ; un changement de format est une modification d'un seul fichier.
Module d'extension Signal K#
Aucune dépendance npm. Le module d'extension lui-même fonctionne sous Node 18 ou plus récent ; les versions actuelles de signalk-server exigent Node 22 ou plus récent, de sorte qu'en pratique il faut utiliser 22. Copiez ou liez integrations/signalk/ dans le node_modules du serveur (par exemple ~/.signalk/node_modules/signalk-kshana-trust), redémarrez le serveur et activez Kshana GNSS trust sous Server, Plugin Config.
D'où viennent les époques (source)#
source |
Ce que fait le module d'extension |
|---|---|
spawn-signalk-nmea (par défaut) |
Exécute kshana receiver-trust live <sessionFile> et écrit sur son entrée standard chaque phrase NMEA 0183 brute que le serveur reçoit (l'événement nmea0183 du serveur). Le relance, avec temporisation croissante, s'il se termine | Ne l'utilisez que sur un serveur à source NMEA unique : il transmet chaque phrase de chaque fournisseur, entrelacées, de sorte qu'un second récepteur GNSS ou l'AIS apparaît comme un récepteur dont la position saute et peut être noté comme leurrage. Avec plus d'une source, utilisez spawn-args avec le flux --tcp propre à ce récepteur, ou tcp-pksht depuis une barrière. |
spawn-args |
Exécute kshana receiver-trust live <sessionFile> <inputArgs...>, par exemple ["--tcp","192.0.2.10:10110"] ou ["--udp","10110"] |
tcp-json |
Se connecte à un flux des lignes JSON que kshana écrit (par exemple depuis le relais de integrations/opencpn/) |
tcp-pksht |
Se connecte à un flux NMEA (tel que la sortie de la barrière du service ou du conteneur de la construction de référence, port 10110) et ne lit que ses phrases $PKSHT |
Un flux déjà leurré au moment où le moniteur s'y connecte pour la première fois n'a pas de référence de base saine (les calibration_s premières secondes ne sont jamais notées). Démarrez-le avant la traversée.
Chemins publiés#
Chaque époque met à jour (source kshana-trust) :
| Chemin | Valeur |
|---|---|
navigation.gnss.kshana.band |
calibrating, nominal, degraded ou untrusted |
navigation.gnss.kshana.score |
0 à 100, ou null pendant l'étalonnage |
navigation.gnss.kshana.reasons |
[{monitor, points}], le plus important en premier : quels contrôles ont réduit le score |
navigation.gnss.kshana.alarms |
les moniteurs actuellement au-delà de leur seuil |
navigation.gnss.kshana.gate |
off, passed ou withheld (lorsqu'une barrière fonctionne ailleurs ; null d'après $PKSHT en son absence) |
navigation.gnss.kshana.reportedPosition |
{latitude, longitude, altitude} : la position que le récepteur sous test a rapportée à cette époque (schéma JSON 1,1 ou ultérieur ; non publiée lorsque le flux n'en porte aucune, par exemple depuis $PKSHT ou un kshana plus ancien). Contexte de confiance uniquement : le module d'extension n'écrit jamais navigation.position, de sorte que le chemin de position propre au navire reste intact |
notifications.navigation.gnss.kshana.trust |
émise lorsque l'état change : {state, method, message} |
Le module d'extension envoie aussi une fois au démarrage les métadonnées Signal K de ces chemins. score est le score de confiance de Kshana, de 0 à 100, un score et non un rapport ni une probabilité, de sorte qu'il ne porte aucune unité SI ; ses métadonnées donnent la plage, une description et des zones qui suivent les seuils ci-dessous. reasons[].points sont des points de score retirés de ce score de 0 à 100.
La notification est normal, alert, warn ou alarm. Elle est effacée en publiant l'état normal, et non null : un consommateur qui ne traite que null comme effacé devrait traiter normal comme effacé aussi. Par défaut, la bande degraded donne warn et la bande untrusted donne alarm, avec method: ["visual","sound"]. Elle est abaissée après clearAfterEpochs époques à un meilleur état. Si aucune époque n'arrive pendant staleAfterS secondes, elle avertit que le score n'est pas mis à jour. L'étalonnage ne déclenche jamais de notification. La source $PKSHT ne porte aucune liste alarms (la phrase ne contient que la bande, le score et les deux principales raisons).
Configuration (chaque seuil)#
| Clé | Valeur par défaut | Signification |
|---|---|---|
source |
spawn-signalk-nmea |
voir ci-dessus |
command |
kshana |
l'exécutable (modes spawn). Il exécute n'importe quel exécutable avec l'identité de l'utilisateur du serveur : seul un administrateur du serveur Signal K devrait pouvoir modifier la configuration du module d'extension |
sessionFile |
/etc/kshana/session.toml |
les limites du navire, les seuils et les pondérations du score (modes spawn) |
inputArgs |
[] |
arguments ajoutés à kshana receiver-trust live <sessionFile> dans les deux modes spawn : l'entrée pour spawn-args, des options supplémentaires telles que --replay (un journal stocké alimenté plus vite que le temps réel) pour spawn-signalk-nmea. Le module d'extension refuse --gate, --listen, --json et --pksht (il lit le JSON de kshana sur la sortie standard), et pour spawn-signalk-nmea aussi les options d'entrée (--stdin, --file, --tcp, --udp, --follow, --from-end) |
host, port |
127.0.0.1, 10111 |
Modes TCP (la barrière sert sur 10110 : réglez le port pour tcp-pksht) |
thresholdMode |
band |
band : la bande que Kshana rapporte, avec les bornes dans le fichier de session. score : les deux scores ci-dessous |
warnBelowScore |
90 |
mode score : en dessous de cette valeur, l'état est degradedState (borne par défaut de Kshana pour nominal) |
alarmBelowScore |
55 |
mode score : en dessous de cette valeur, l'état est alarm (borne par défaut de Kshana pour degraded) |
degradedState |
warn |
état pour la bande degraded : normal, alert ou warn |
raiseAfterEpochs |
1 |
époques consécutives à un état plus mauvais avant que la notification ne soit émise |
clearAfterEpochs |
10 |
époques consécutives à un meilleur état avant qu'elle ne soit abaissée |
staleAfterS |
10 |
avertir lorsqu'aucune époque n'arrive pendant cette durée ; 0 le désactive |
method |
["visual","sound"] |
méthodes de notification |
Le module d'extension ne fait pas barrière : il n'altère jamais un point de position. Marquer un point comme invalide pour un système de cartographie, c'est la barrière, ci-dessous.
Tests#
cd integrations/signalk && npm test
node:test, aucune dépendance, aucun réseau au-delà de 127.0.0.1. Les tests analysent et rejouent un extrait de 66 époques des lignes JSON et des phrases $PKSHT que kshana receiver-trust live a écrites pour la démonstration synthétique de la Baltique (données inventées, texte seulement), vérifient la concordance entre les deux formats, le comportement de maintien et d'effacement, le mode score, l'obsolescence et les trois chemins d'entrée par rapport à un flux local et à un processus enfant de substitution. Ces tests ne démarrent pas de véritable serveur Signal K ; une exécution scriptée distincte le fait, voir ci-dessous.
Exécution dans un véritable serveur Signal K#
integrations/signalk/evidence/ contient un script qui charge le module d'extension dans le paquet signalk-server 2.33.0 épinglé (dans un espace de noms réseau privé, limité au bouclage) et enregistre ce que montrent les propres API REST et WebSocket du serveur. Les chemins de confiance apparaissent, la notification passe de warn à alarm, à normal (après le maintien) et de nouveau à warn quand les données cessent ; et avec le véritable kshana alimenté par l'entrée NMEA propre au serveur, il a aussi publié reportedPosition, jamais navigation.position. Une seule version du serveur, une seule exécution, aucun navire réel ; limites et reproduction dans le README des preuves.
OpenCPN#
OpenCPN lit le NMEA depuis le réseau, et kshana receiver-trust live --gate peut lui-même servir le flux filtré par la barrière sur un port TCP.
Recommandé : la connexion directe.
some-nmea-source | kshana receiver-trust live session.toml --gate --listen tcp:10110
(some-nmea-source est le port série du récepteur lu avec stty et cat, un multiplexeur, ou les entrées --tcp/--udp de kshana lui-même ; le kshana-gate.service de la construction de référence fait cela sous systemd.) --listen tcp:<port> se lie à l'adresse de bouclage ; un nombre quelconque de clients en lecture seule peuvent s'y connecter, et celui qui ne suit pas est abandonné sans retarder les autres.
Alternative : le relais. integrations/opencpn/nmea-tcp-relay.mjs est une diffusion Node sans dépendance qui fait la même chose pour un kshana sans --listen, ou qui sert tout autre flux de lignes (l'option conteneur l'utilise pour les époques JSON) :
some-nmea-source | kshana receiver-trust live session.toml --gate --json trust.jsonl \
| node integrations/opencpn/nmea-tcp-relay.mjs --listen 10110
Il transmet les octets sans les modifier, par lignes entières seulement, et abandonne un client qui ne lit pas. Préférez la connexion directe : un processus de moins dans la chaîne.
Dans OpenCPN : Options, Connections, Add Connection, Network, protocole TCP, adresse 127.0.0.1, port 10110, direction Input. Tant que la confiance n'est pas effondrée, le flux est celui du récepteur lui-même, plus une phrase $PKSHT par cycle. Tant qu'elle est effondrée, la GGA transmise a la qualité 0, la RMC l'état V, et les indicateurs de mode disent pas de point de position, avec les sommes de contrôle recalculées : l'équipement voit le récepteur lui-même déclarer le point invalide et déclenche sa propre alarme. Les phrases $PKSHT sont visibles dans la fenêtre de débogage NMEA d'OpenCPN (Options, Connections, « NMEA debug window »). Les champs de position sont laissés tels que reçus.
Lisez « Gate mode » dans MARITIME-TRUST.md avant de vous y fier : il est facultatif, ajoute de la latence (un cycle est retenu jusqu'à ce que son époque soit notée), constitue un point unique dans la chaîne, et peut retenir un bon point de position aussi bien que laisser passer un point contrefait.
Tests#
cd integrations/opencpn && npm test
test/relay.test.mjs rejoue un extrait enregistré du flux synthétique filtré par la barrière (186 phrases autour du moment où la confiance s'effondre, écrites par kshana receiver-trust live --gate) à travers le relais sur un véritable socket TCP et vérifie ce que reçoit un consommateur : le flux octet pour octet quel que soit le découpage ; des sommes de contrôle valides sur chaque phrase, y compris celles réécrites ; GGA et RMC concordantes, valides puis invalides sans scintillement ; une $PKSHT par cycle avec son champ de barrière W exactement là où le point est invalide ; deux consommateurs identiques ; une ligne partielle jamais transmise. Cela vérifie le flux fourni à OpenCPN, non l'écran d'OpenCPN lui-même.
Une vérification de bout en bout avec le véritable binaire, ne faisant pas partie des tests par défaut (elle exige un kshana compilé) :
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
Les deux exécutent la démonstration synthétique d'une heure et vérifient que le point passe de valide à invalide, avec une $PKSHT par époque.
Module d'extension natif#
integrations/opencpn/plugin/ est un panneau de score pour OpenCPN (score, bande, barrière, principales raisons, une alerte lorsque la confiance devient untrusted) qui lit $PKSHT dans le propre flux NMEA d'OpenCPN, de sorte qu'il n'a besoin d'aucune connexion au-delà de celle ci-dessus. Il est construit avec CMake par rapport à l'en-tête de l'API de modules d'extension d'OpenCPN (embarqué, avec son commit source) et wxWidgets ; ctest exécute les tests de logique sans wx et vérifie que la bibliothèque exporte les points d'entrée qu'OpenCPN recherche. Il a été exécuté dans OpenCPN 5.8.4 sous un affichage virtuel sur le flux synthétique filtré par la barrière (OpenCPN a remis $PKSHT au module d'extension, le panneau est devenu rouge, et la position propre d'OpenCPN s'est figée lorsque la barrière s'est enclenchée ; captures d'écran, journal et script dans integrations/opencpn/evidence/), mais pas sur un véritable poste de travail, ni avec d'autres versions ou plateformes, et il n'est pas empaqueté pour le gestionnaire de modules d'extension d'OpenCPN. Voir le README.md du module d'extension. Il est placé sous licence GPL-3.0-or-later, contrairement au reste du dépôt (LICENSING.md).
Captures d'écran de cette exécution, dans integrations/opencpn/evidence/ (une seule exécution, OpenCPN 5.8.4 sous un affichage virtuel, données synthétiques ; README.md donne les limites) :
Ces captures montrent la tuyauterie et le point de position filtré par la barrière parvenant à OpenCPN, et non qu'une alarme soit opportune ou correcte pour un navire réel. Logiciel à titre consultatif, et non un équipement homologué.
Construction de référence#
deploy/reference-build/ : une liste de pièces générique, la configuration du système d'exploitation, deux unités systemd (le moniteur consultatif et la barrière facultative), une option conteneur et le câblage Signal K. deploy/reference-build/check-units.sh exécute systemd-analyze verify sur les unités sans rien démarrer.
Limites#
- Le score ne vaut que ce que valent les contrôles qui le sous-tendent, lesquels portent sur la physique d'un navire et sur ses autres capteurs ; une contrefaçon cohérente en elle-même, avec une horloge concordante, n'est pas vue par des moniteurs NMEA seuls (
MARITIME-TRUST.md). L'absence d'alarme n'est pas une preuve d'un bon point de position. - Aucun chiffre de cette page n'est un taux de détection ou de fausse alarme mesuré. Les tests ci-dessus vérifient la tuyauterie sur du texte synthétique ; ils ne disent rien de la façon dont un moniteur se comporte face à de véritables interférences.
- Non homologué ; l'opérateur reste responsable.