Skip to content

Signal K output

An output with the signalk encoding sends Signal K delta messages built from the vessel state instead of NMEA 0183 sentences, one JSON document per line (or per WebSocket text frame). A WebSocket server output greets every client with the Signal K hello message first, so a Signal K server or a web instrument can treat the simulator as a Signal K source. The design is recorded in ADR 0014 and the how-to guide walks through connecting a server.

Hello message

{"name":"NMEASimulatorX","version":"0.5.0","self":"vessels.urn:mrn:imo:mmsi:239000001","roles":["master","main"],"timestamp":"2026-09-22T12:34:56.780Z"}

self is the context of the deltas that follow; timestamp is the wall-clock time the client connected.

Delta message

{"context":"vessels.urn:mrn:imo:mmsi:239000001","updates":[{"source":{"label":"nmeasim","type":"simulator"},"timestamp":"2026-09-22T12:34:56.780Z","values":[{"path":"navigation.datetime","value":"2026-09-22T12:34:56.780Z"},{"path":"navigation.position","value":{"longitude":23.7275,"latitude":37.9838,"altitude":12.3}},{"path":"navigation.speedOverGround","value":3.3438889}]}]}

One delta is sent per output period (see the profile reference) with one update whose timestamp is the simulated clock. The context is configurable per output: the default vessels.urn:mrn:imo:mmsi:<MMSI> uses the AIS MMSI, and any other Signal K context such as aircraft.urn:mrn:signalk:uuid:... can be given. The output's sentence filter applies to paths: a filter entry admits the path it names and every path below it, so navigation, environment.wind sends only those groups. Entries name whole path segments, so navigation.speed does not admit navigation.speedThroughWater, and case is ignored.

Paths

Every value uses the units of the Signal K specification: metres, metres per second, radians, kelvin, hertz. Relative angles are in the range -π to π, positive to starboard.

Path Value Condition
navigation.datetime Simulated UTC time, ISO 8601 always
navigation.position {longitude, latitude, altitude} in degrees and metres with a fix
navigation.courseOverGroundTrue rad with a fix
navigation.courseOverGroundMagnetic rad with a fix
navigation.speedOverGround m/s with a fix
navigation.headingTrue rad always
navigation.headingMagnetic rad, true heading minus variation (deviation not applied) always
navigation.magneticVariation rad, east positive always
navigation.magneticDeviation rad, east positive always
navigation.speedThroughWater m/s always
navigation.rateOfTurn rad/s, starboard positive always
navigation.gnss.type "GPS" always
navigation.gnss.methodQuality "GNSS Fix", "DGNSS fix" or "no GPS" always
navigation.gnss.satellites satellites in use, 0 without a fix always
navigation.gnss.horizontalDilution, positionDilution HDOP, PDOP with a fix
navigation.gnss.antennaAltitude, geoidalSeparation m with a fix
navigation.courseRhumbline.nextPoint.position destination {longitude, latitude} with a destination
navigation.courseRhumbline.nextPoint.bearingTrue rad with a destination
navigation.courseRhumbline.nextPoint.distance m with a destination
navigation.courseRhumbline.nextPoint.velocityMadeGood m/s towards the destination with a destination
navigation.courseRhumbline.previousPoint.position leg origin with a destination
navigation.courseRhumbline.bearingTrackTrue rad, origin to destination with a destination
navigation.courseRhumbline.crossTrackError m, positive to the right of the leg with a destination
environment.depth.belowTransducer m always
environment.depth.surfaceToTransducer, belowSurface m transducer offset ≥ 0
environment.depth.transducerToKeel, belowKeel m transducer offset < 0
environment.water.temperature K always
environment.wind.speedTrue m/s always
environment.wind.directionTrue rad, direction the wind comes from always
environment.wind.angleTrueWater rad relative to the bow always
environment.wind.speedApparent m/s always
environment.wind.angleApparent rad relative to the bow always
steering.rudderAngle rad, starboard positive always
propulsion.<id>.revolutions Hz (revolutions per second), 0 when stopped per engine
propulsion.<id>.temperature coolant temperature, K per engine
propulsion.<id>.state "started" or "stopped" per engine

The engine <id> is the engine label lower-cased with the word engine and all punctuation removed: Port engine becomes port. A label that leaves nothing becomes engine1, engine2, ... in profile order.

Checking the output

The repository ships tools/check_signalk_stream.py, which reads deltas from standard input, checks that every line is a JSON document of the shape above and that every path is one of the paths listed here with a value of the right JSON type. CI runs it on every platform.

nmeasim run --stdout --encoding signalk --quiet --duration 3 | python3 tools/check_signalk_stream.py