Integracje morskie: wskaźnik zaufania na mostku
Morski wskaźnik zaufania Kshana (MARITIME-TRUST.md) jest dostępny z oprogramowania, z którego żeglarze już korzystają: wtyczki serwera Signal K oraz OpenCPN przez NMEA w trybie bramki po TCP. Wersja referencyjna umieszcza go na małym komputerze obok odbiornika.
Oprogramowanie wyłącznie doradcze. Kshana nie jest sprzętem nawigacyjnym z zatwierdzeniem typu (IEC 61108, IEC 61162) i nie została oceniona względem żadnej normy działania. Wszystko na tej stronie jest pomocą dla osądu nawigatora. Za bezpieczną nawigację statku oraz za każdą decyzję o poleganiu na pozycji lub o zaprzestaniu polegania na niej odpowiada nadal operator. Nic tu niczego nie nadaje i nic tu nie czyni pozycji dokładniejszą.
| Element | Gdzie | Stan w 0,35 |
|---|---|---|
| Wtyczka Signal K | integrations/signalk/ |
dostarczone, testowane jednostkowo na zapisanym syntetycznym wyniku; nieopublikowane w npm |
| OpenCPN przez NMEA w trybie bramki po TCP | integrations/opencpn/ |
dostarczone i przetestowane (odtworzenie po stronie odbiorcy); sam interfejs użytkownika OpenCPN nie jest sterowany przez żaden test |
| Natywna wtyczka panelu wskaźnika dla OpenCPN | integrations/opencpn/plugin/ |
zbudowana, logika testowana jednostkowo i uruchomiona wewnątrz OpenCPN 5.8.4 pod wirtualnym ekranem (dowody w integrations/opencpn/evidence/); nie spakowana dla menedżera wtyczek; zostanie wydana dopiero po przeglądzie |
| Wersja referencyjna | deploy/reference-build/ |
części, kroki dla systemu operacyjnego, jednostki systemd (sprawdzone na sucho), opcja kontenera; nie testowane na statku |
Wszystko to czyta jedną rzecz: wyjście kshana receiver-trust live (wiersze JSON, zdanie $PKSHT, bramka). Formaty przesyłania opisuje MARITIME-TRUST.md. Wtyczka Signal K trzyma swoją wiedzę o nich w jednym pliku, integrations/signalk/lib/adapter.js; zmiana formatu to edycja jednego pliku.
Wtyczka Signal K#
Brak zależności npm. Sama wtyczka działa na Node 18 lub nowszym; bieżące wydania signalk-server wymagają Node 22 lub nowszego, więc w praktyce używaj 22. Skopiuj lub podlinkuj integrations/signalk/ do node_modules serwera (na przykład ~/.signalk/node_modules/signalk-kshana-trust), zrestartuj serwer i włącz Kshana GNSS trust w Server, Plugin Config.
Skąd pochodzą epoki (source)#
source |
Co robi wtyczka |
|---|---|
spawn-signalk-nmea (domyślnie) |
Uruchamia kshana receiver-trust live <sessionFile> i zapisuje na jego standardowe wejście każde surowe zdanie NMEA 0183, które otrzymuje serwer (zdarzenie nmea0183 serwera). Restartuje go z odczekaniem, jeśli się zakończy | Używaj tylko na serwerze z jednym źródłem NMEA: podaje każde zdanie od każdego dostawcy, przemieszane, więc drugi odbiornik GNSS lub AIS wygląda jak jeden odbiornik, którego położenie skacze, i może zostać oceniony jako spoofing. Przy więcej niż jednym źródle użyj spawn-args ze strumieniem --tcp tego odbiornika albo tcp-pksht z bramki. |
spawn-args |
Uruchamia kshana receiver-trust live <sessionFile> <inputArgs...>, na przykład ["--tcp","192.0.2.10:10110"] lub ["--udp","10110"] |
tcp-json |
Łączy się ze strumieniem wierszy JSON, które zapisuje kshana (na przykład z przekaźnika w integrations/opencpn/) |
tcp-pksht |
Łączy się ze strumieniem NMEA (takim jak wyjście bramki usługi lub kontenera w wersji referencyjnej, port 10110) i odczytuje tylko jego zdania $PKSHT |
Strumień, który jest już poddawany spoofingowi w chwili pierwszego połączenia monitora, nie ma czystego punktu odniesienia (pierwsze calibration_s sekund nigdy nie jest oceniane). Uruchom go przed rejsem.
Publikowane ścieżki#
Każda epoka aktualizuje (źródło kshana-trust):
| Ścieżka | Wartość |
|---|---|
navigation.gnss.kshana.band |
calibrating, nominal, degraded lub untrusted |
navigation.gnss.kshana.score |
0 do 100 albo null podczas kalibracji |
navigation.gnss.kshana.reasons |
[{monitor, points}], od największych: które kontrole obniżyły wskaźnik |
navigation.gnss.kshana.alarms |
monitory, które aktualnie przekraczają swój próg |
navigation.gnss.kshana.gate |
off, passed lub withheld (gdy bramka działa gdzie indziej; null z $PKSHT, gdy jej brak) |
navigation.gnss.kshana.reportedPosition |
{latitude, longitude, altitude}: położenie zgłoszone w danej epoce przez badany odbiornik (schemat JSON 1,1 lub nowszy; nie jest publikowane, gdy strumień go nie zawiera, na przykład z $PKSHT lub starszego kshana). Wyłącznie kontekst zaufania: wtyczka nigdy nie zapisuje navigation.position, więc ścieżka własnego położenia statku pozostaje nietknięta |
notifications.navigation.gnss.kshana.trust |
zgłaszane przy zmianie stanu: {state, method, message} |
Wtyczka wysyła także metadane Signal K dla tych ścieżek jednorazowo przy starcie. score to wskaźnik zaufania Kshana od 0 do 100, wskaźnik, a nie stosunek ani prawdopodobieństwo, więc nie ma jednostki SI; jego metadane podają zakres, opis i strefy zgodne z progami poniżej. reasons[].points to punkty wskaźnika odjęte od tego wskaźnika od 0 do 100.
Powiadomienie ma wartość normal, alert, warn lub alarm. Jest kasowane przez publikację stanu normal, a nie null: odbiorca, który uznaje za skasowane tylko null, powinien uznać za skasowane także normal. Domyślnie pasmo degraded daje warn, a pasmo untrusted daje alarm, z method: ["visual","sound"]. Jest obniżane po clearAfterEpochs epokach w lepszym stanie. Jeśli przez staleAfterS sekund nie nadejdzie żadna epoka, ostrzega, że wskaźnik nie jest aktualizowany. Kalibracja nigdy nie wywołuje powiadomienia. Źródło $PKSHT nie zawiera listy alarms (zdanie ma tylko pasmo, wskaźnik i dwa główne powody).
Konfiguracja (każdy próg)#
| Klucz | Wartość domyślna | Znaczenie |
|---|---|---|
source |
spawn-signalk-nmea |
zob. wyżej |
command |
kshana |
plik wykonywalny (tryby spawn). Uruchamia dowolny plik wykonywalny jako użytkownik serwera: konfigurację wtyczki powinien móc zmieniać tylko administrator serwera Signal K |
sessionFile |
/etc/kshana/session.toml |
limity statku, progi i wagi wskaźnika (tryby spawn) |
inputArgs |
[] |
argumenty dodawane do kshana receiver-trust live <sessionFile> w obu trybach spawn: wejście dla spawn-args, dodatkowe flagi, takie jak --replay (zapisany dziennik podawany szybciej niż w czasie rzeczywistym) dla spawn-signalk-nmea. Wtyczka odrzuca --gate, --listen, --json i --pksht (czyta JSON z kshana ze standardowego wyjścia), a dla spawn-signalk-nmea także flagi wejścia (--stdin, --file, --tcp, --udp, --follow, --from-end) |
host, port |
127.0.0.1, 10111 |
Tryby TCP (bramka obsługuje na 10110: ustaw port dla tcp-pksht) |
thresholdMode |
band |
band: pasmo zgłaszane przez Kshana, z krawędziami w pliku sesji. score: dwa poniższe wskaźniki |
warnBelowScore |
90 |
tryb score: poniżej tej wartości stan to degradedState (domyślna krawędź Kshana dla nominal) |
alarmBelowScore |
55 |
tryb score: poniżej tej wartości stan to alarm (domyślna krawędź Kshana dla degraded) |
degradedState |
warn |
stan dla pasma degraded: normal, alert lub warn |
raiseAfterEpochs |
1 |
kolejne epoki w gorszym stanie przed wywołaniem powiadomienia |
clearAfterEpochs |
10 |
kolejne epoki w lepszym stanie przed jego obniżeniem |
staleAfterS |
10 |
ostrzegaj, gdy przez tak długo nie nadejdzie żadna epoka; 0 to wyłącza |
method |
["visual","sound"] |
metody powiadamiania |
Wtyczka nie działa jako bramka: nigdy nie zmienia pozycji. Oznaczanie pozycji jako nieważnej dla systemu mapowego to bramka, poniżej.
Testy#
cd integrations/signalk && npm test
node:test, bez zależności, bez sieci poza 127.0.0.1. Testy przetwarzają i odtwarzają 66-epokowy fragment wierszy JSON i zdań $PKSHT, które kshana receiver-trust live zapisał dla syntetycznego demo bałtyckiego (dane wymyślone, tylko tekst), sprawdzają zgodność obu formatów, zachowanie podtrzymania i kasowania, tryb wskaźnika, nieaktualność oraz trzy ścieżki wejścia względem lokalnego strumienia i zastępczego procesu potomnego. Te testy nie uruchamiają prawdziwego serwera Signal K; osobny skryptowy przebieg to robi, zob. niżej.
Uruchomienie w prawdziwym serwerze Signal K#
integrations/signalk/evidence/ zawiera skrypt, który ładuje wtyczkę do przypiętego pakietu signalk-server 2.33.0 (w prywatnej przestrzeni nazw sieci tylko z pętlą zwrotną) i rejestruje to, co pokazują własne API REST i WebSocket serwera. Ścieżki zaufania się pojawiają, powiadomienie przechodzi przez warn, alarm, normal (po podtrzymaniu) i ponownie warn, gdy dane ustają, a z prawdziwym kshana zasilanym własnym wejściem NMEA serwera opublikowało także reportedPosition, nigdy navigation.position. Jedna wersja serwera, jeden przebieg, żaden prawdziwy statek; ograniczenia i sposób odtworzenia w README dowodów.
OpenCPN#
OpenCPN czyta NMEA z sieci, a kshana receiver-trust live --gate może sam udostępnić strumień po bramce na porcie TCP.
Zalecane: połączenie bezpośrednie.
some-nmea-source | kshana receiver-trust live session.toml --gate --listen tcp:10110
(some-nmea-source to port szeregowy odbiornika odczytywany przez stty i cat, multiplekser albo wejścia --tcp/--udp samego kshana; kshana-gate.service z wersji referencyjnej robi to pod systemd.) --listen tcp:<port> wiąże się z adresem pętli zwrotnej; można podłączyć dowolną liczbę klientów tylko do odczytu, a klient, który nie nadąża, jest odłączany bez opóźniania pozostałych.
Alternatywa: przekaźnik. integrations/opencpn/nmea-tcp-relay.mjs to niezależny od zależności rozdzielacz w Node, który robi to samo dla kshana bez --listen lub udostępnia dowolny inny strumień wierszy (opcja kontenera używa go dla epok JSON):
some-nmea-source | kshana receiver-trust live session.toml --gate --json trust.jsonl \
| node integrations/opencpn/nmea-tcp-relay.mjs --listen 10110
Przekazuje bajty bez zmian, tylko całe wiersze, i odłącza klienta, który nie czyta. Preferuj połączenie bezpośrednie: o jeden proces mniej w łańcuchu.
W OpenCPN: Options, Connections, Add Connection, Network, protokół TCP, adres 127.0.0.1, port 10110, kierunek Input. Dopóki zaufanie nie załamało się, strumień jest własnym strumieniem odbiornika plus jedno zdanie $PKSHT na cykl. Gdy się załamało, przekazywane GGA ma jakość 0, RMC status V, a wskaźniki trybu mówią o braku pozycji, z przeliczonymi sumami kontrolnymi: sprzęt widzi, jak sam odbiornik uznaje pozycję za nieważną, i podnosi własny alarm. Zdania $PKSHT są widoczne w oknie debugowania NMEA w OpenCPN (Options, Connections, „NMEA debug window”). Pola położenia pozostają takie, jak odebrano.
Przeczytaj „Gate mode” w MARITIME-TRUST.md, zanim na tym polegniesz: jest opcjonalny, dodaje opóźnienie (cykl jest wstrzymywany do chwili oceny jego epoki), jest pojedynczym punktem w łańcuchu i może wstrzymać dobrą pozycję, a także przepuścić sfałszowaną.
Testy#
cd integrations/opencpn && npm test
test/relay.test.mjs odtwarza zapisany fragment syntetycznego strumienia po bramce (186 zdań wokół chwili załamania zaufania, zapisanych przez kshana receiver-trust live --gate) przez przekaźnik po prawdziwym gnieździe TCP i sprawdza, co otrzymuje odbiorca: strumień bajt po bajcie przy dowolnym dzieleniu na porcje; prawidłowe sumy kontrolne w każdym zdaniu, także przepisanych; zgodne GGA i RMC, ważne, a potem nieważne, bez migotania; jedno $PKSHT na cykl z polem bramki W dokładnie tam, gdzie pozycja jest nieważna; dwóch identycznych odbiorców; częściowy wiersz nigdy nieprzekazany. Sprawdza to strumień podawany OpenCPN, a nie własny ekran OpenCPN.
Test od początku do końca z prawdziwym plikiem binarnym, niebędący częścią testów domyślnych (wymaga zbudowanego kshana):
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
Oba uruchamiają jednogodzinne demo syntetyczne i sprawdzają, że pozycja staje się ważna, a potem nieważna, z jednym $PKSHT na epokę.
Wtyczka natywna#
integrations/opencpn/plugin/ to panel wskaźnika dla OpenCPN (wskaźnik, pasmo, bramka, główne powody, alert, gdy zaufanie staje się untrusted), który czyta $PKSHT z własnego strumienia NMEA OpenCPN, więc nie wymaga połączenia poza opisanym wyżej. Jest budowana za pomocą CMake względem nagłówka API wtyczek OpenCPN (dołączonego, z commitem źródłowym) i wxWidgets; ctest uruchamia testy logiki bez wx i sprawdza, że biblioteka eksportuje punkty wejścia, których szuka OpenCPN. Uruchomiono ją wewnątrz OpenCPN 5.8.4 pod wirtualnym ekranem na syntetycznym strumieniu po bramce (OpenCPN przekazał $PKSHT wtyczce, panel zaczerwienił się, a własne położenie OpenCPN zamarzło po uruchomieniu bramki; zrzuty ekranu, dziennik i skrypt w integrations/opencpn/evidence/), ale nie na prawdziwym pulpicie, innych wersjach ani platformach, i nie jest spakowana dla menedżera wtyczek OpenCPN. Zob. README.md wtyczki. Jest licencjonowana na GPL-3.0-or-later, inaczej niż reszta repozytorium (LICENSING.md).
Zrzuty ekranu z tego przebiegu, w integrations/opencpn/evidence/ (jeden przebieg, OpenCPN 5.8.4 pod wirtualnym ekranem, dane syntetyczne; README.md podaje ograniczenia):
Pokazują one okablowanie i dotarcie pozycji po bramce do OpenCPN, a nie to, że jakikolwiek alarm jest na czas lub poprawny dla prawdziwego statku. Oprogramowanie wyłącznie doradcze, nie jest to sprzęt z zatwierdzeniem typu.
Wersja referencyjna#
deploy/reference-build/: ogólna lista części, konfiguracja systemu operacyjnego, dwie jednostki systemd (monitor doradczy i opcjonalna bramka), opcja kontenera i okablowanie Signal K. deploy/reference-build/check-units.sh uruchamia systemd-analyze verify na jednostkach bez uruchamiania czegokolwiek.
Ograniczenia#
- Wskaźnik jest tak dobry, jak kontrole, które za nim stoją, a te patrzą na fizykę statku i jego inne czujniki; samospójna fałszywka z pasującym zegarem nie jest widoczna dla monitorów opartych wyłącznie na NMEA (
MARITIME-TRUST.md). Brak alarmu nie jest dowodem dobrej pozycji. - Żadna wartość na tej stronie nie jest zmierzoną częstością detekcji ani fałszywych alarmów. Powyższe testy sprawdzają okablowanie na tekście syntetycznym; nic nie mówią o tym, jak jakikolwiek monitor radzi sobie z prawdziwymi zakłóceniami.
- Nie jest to sprzęt z zatwierdzeniem typu; operator nadal ponosi odpowiedzialność.