Skip to content

Reference ​

Everything the daemon and its tools expose, in tables. For what any of it means, see the topic chapters.

Every value here was read out of the software itself. Where a --help string and the code disagree, the code is what is documented; the discrepancies are listed in internal/open-questions.md.

Programs ​

ProgramRole
/usr/bin/muxen-nmea2000the daemon, one per CAN bus
/usr/bin/muxen-nmea2000-confignavigation source configuration, full-screen terminal
/usr/bin/muxen-nmea2000-inventoryprints the bus device list from MQTT
/usr/bin/muxen-nmea2000-generate-namebuilds a J1939 NAME from its fields
/usr/bin/muxen-nmea2000-simulatortransmits synthetic NMEA 2000 traffic

The four tools are each built behind a Meson option — tool_config, tool_inventory, tool_name, tool_simulator — all on by default.

muxen-nmea2000 ​

General ​

OptionArgumentDefaultEffect
-v, --versionprint version, exit
-i, --interfaceINTERFACEcan1CAN interface
--state-dirDIR/var/lib/muxen-nmea2000state file directory
--data-dirDIR/usr/share/muxen-nmea2000read-only data tables
--deploy-configPATH/etc/muxen/deploy.jsondeploy configuration file
--no-deploy-configoffskip the deploy layer
--ipc-socketPATHsee belowIPC socket path
--show-stateprint the state file, exit
--clear-statedelete the state file, exit

--data-dir, when not given, is searched for in order: /usr/share/muxen-nmea2000, ./data, . — the first that contains manufacturers.json wins.

J1939 identity ​

OptionArgumentDefaultEffect
-n, --nameNAME(required)64-bit J1939 NAME, hex, 0x prefix optional
-a, --addressADDR128preferred source address, 0–253
--min-addrMIN100lowest address for dynamic claiming, 0–253
--max-addrMAX200highest address for dynamic claiming, 0–253
--nmea-versionVERSION3000NMEA 2000 database version reported in PGN 126996
--product-codeCODE123product code
--model-idID:)model id, max 31 characters, refused if longer
--product-nameNAMEMuxen Brain 20product name, max 31 characters, refused if longer
--serial-numberSERIAL00:00:00serial code, max 31 characters, refused if longer
--cert-levelLEVEL20 certified, 1 type approved, 2 not applicable
--load-equivVALUE0load equivalency number
--install-desc1TEXTMUXen Brain 20installation description 1, max 31 characters, silently truncated

The software version reported in PGN 126996 is the daemon's own version and is not settable.

MQTT ​

OptionArgumentDefaultEffect
--no-mqttMQTT ondisable MQTT entirely
--mqtt-hostHOST127.0.0.1broker host
--mqtt-portPORT1883broker port
--mqtt-usernameUSERnonebroker username
--mqtt-passwordPASSnonebroker password
--mqtt-client-idIDauto-generatedMQTT client id
--mqtt-topic-prefixPREFIXnmeaprefix for every topic
--mqtt-publish-pgnoffpublish raw decoded PGNs to …/device/<addr>/pgn/<pgn>

The broker keep-alive is 60 s and the session is clean.

Report modules ​

OptionArgumentDefaultEffect
--enable-alarmsoffNMEA 2000 alert subsystem
--report-alloffenable nav, AIS, motor, route and thruster; applied last
--report-navoffpublish <prefix>/navigation
--nav-high-speedoff10 Hz instead of 1 Hz
--nav-configPATHsee belownavigation source configuration file
--wind-dampingLEVEL70–9, 0 = off
--report-aisoffpublish <prefix>/ais
--ais-track-depthDEPTH10track points per target, clamped 0–100
--report-motoroffpublish <prefix>/motor
--motor-high-speedoff10 Hz instead of 1 Hz
--report-thrusteroffpublish <prefix>/thruster
--report-routeoffpublish <prefix>/route
--route-max-waypointsCOUNT500waypoints kept per route
--timezone-dbPATH<data-dir>/timezone16.binZoneDetect database
--datetime-offsetMODEnmeanmea or auto
--report-metadata-sourceoffinclude source device information in report metadata

<prefix>/datetime and <prefix>/status are always published and have no enabling flag.

GNSS source ​

Present only when the daemon was built with libgps.

OptionArgumentDefaultEffect
--source-gpsdoffenable the gpsd client
--source-gpsd-hostHOSTlocalhostgpsd server
--source-gpsd-portPORT2947gpsd port
--source-gpsd-devicePATHallrestrict to one receiver
--source-gpsd-transmit[MODE]offon or failover; bare flag means on
--source-gpsd-transmit-high-speedoffalso transmit the 10 Hz rapid-update PGNs
--source-gpsd-transmit-failover-delaySECONDS60time without a valid GNSS on the bus before failover starts; 1–4 behave as 5, 0 as 60

Tweaks ​

Workarounds for chartplotter compatibility and bus recovery tuning.

OptionArgumentDefaultEffect
--fp-delayUSEC1000Fast Packet inter-frame delay
--pgn-list-fp-onlyofflimit the PGN List to Fast Packet size, 74 PGNs, no ISO-TP
--recovery-initial-delayMS1000first bus-recovery retry delay
--recovery-max-delayMS30000backoff ceiling
--recovery-max-attemptsN00 = retry forever

Verbosity ​

All are off by default and all write to standard error.

OptionCovers
--verbose-datadecoded PGN JSON
--verbose-controladdress claim and lifecycle
--verbose-requestISO requests
--verbose-pgn-proprietaryproprietary PGNs
--verbose-navnavigation source selection; also adds sources and unavailableTypes to <prefix>/navigation
--verbose-aisAIS target lifecycle
--verbose-ipcIPC server
--verbose-gpsdgpsd connection
--verbose-mqttMQTT connection
--verbose-motormotor report
--verbose-routeroute report
--verbose-datetimedatetime report
--verbose-allall of the above

Signals ​

SignalEffect
SIGHUPreload the navigation source configuration and republish <prefix>/config
SIGINT, SIGTERMgraceful shutdown
SIGPIPEignored — an IPC client that disconnects mid-reply must not kill the daemon

Exit status ​

StatusMeaning
0clean shutdown, or --version / --show-state / --clear-state completed
1startup refused: bad options, wrong bitrate, no NAME, lock not acquired, CAN monitor failed, --clear-state could not delete the file

muxen-nmea2000-config ​

OptionArgumentEffect
-s, --socketPATHIPC socket
-I, --instanceNAMEuse /run/muxen-nmea2000-<NAME>/sources.sock
-r, --read-onlymonitor without editing
-h, --helpusage, exit 0
-V, --versionversion, exit 0

Exit status is 1 on a UI error, 0 otherwise. The device list refreshes every 2 s. Key bindings are in Navigation.

muxen-nmea2000-inventory ​

OptionArgumentDefault
-H, --hostHOSTlocalhost
-p, --portPORT1883
-I, --instanceNAME—
-P, --prefixPREFIXnmea
-T, --timeoutSEC5
-j, --jsonformatted table
-c, --csvsemicolon-delimited
-h, --help

muxen-nmea2000-generate-name ​

Builds a 64-bit J1939 NAME from its constituent fields.

OptionArgumentField
-i, --identityNUMIdentity Number
-m, --manufacturerNUMManufacturer Code
-e, --ecu-instanceNUMECU Instance
-f, --func-instanceNUMFunction Instance
-F, --functionNUMFunction
-v, --vehicle-systemNUMVehicle System
-V, --vs-instanceNUMVehicle System Instance
-g, --industry-groupNUMIndustry Group
-a, --arbitraryset the Arbitrary Address Capable bit
-h, --help

Field meanings and their ranges are in Address claiming.

muxen-nmea2000-simulator ​

muxen-nmea2000-simulator [OPTIONS] [MODULE] [INTERFACE]
muxen-nmea2000-simulator --all [INTERFACE]

Modules: motor, navigation (or nav), ais, route, thruster. With no module and no --all, every module runs. Default interface comes from the build; --interface beats the positional argument.

OptionArgumentEffect
-i, --interfaceIFNAMECAN interface
--allrun every simulator
--setupcreate the vcan interface first
--durationSECSrun time, 0 = forever
--cruisingcruising defaults for every module
--lat, --lonDEGREESstarting position
--cruisemotor: 3000 RPM forward
--maneuvermotor: cycling phases
--singlemotor: one engine instead of two
--anchorednavigation: anchored
--sailingnavigation: sailing
--harborAIS: harbour scenario
--offshoreAIS: offshore scenario
--trafficAIS: heavy traffic
--thruster-activethruster: cycling port/starboard
--coastalroute: 5 waypoints
--passageroute: 10 waypoints
-v, --verboselog every PGN sent
-h, --help

MQTT topics ​

<prefix> is nmea by default, nmea-<instance> for a templated instance. Every payload is {"data": …, "metadata": …} unless noted. metadata always carries rxDate (ISO 8601, UTC) and rxTimestamp (Unix seconds).

Published ​

TopicRateQoSRetainexpireAfterSecRequires
<prefix>/navigation1 Hz or 10 Hz0yes2--report-nav
<prefix>/motor1 Hz or 10 Hz0no5--report-motor
<prefix>/thruster1 Hz0no5--report-thruster
<prefix>/ais30 s0yes30--report-ais
<prefix>/route1 Hz active, 60 s idle0yes30 active, 70 idle--report-route
<prefix>/datetime1 Hz0yes5always
<prefix>/status30 s0yes60always
<prefix>/configat connect, at claim, on SIGHUP1yes3124137600always
<prefix>/interface10 s0yes10always
<prefix>/deviceson change0yes120always
<prefix>/device/<addr>/infoson change0yes120always
<prefix>/device/<addr>/pgn/<pgn>on receive0yes60--mqtt-publish-pgn
<prefix>/gpsdon change0yes10--source-gpsd
<prefix>/alarm/stateon transition0no—--enable-alarms
<prefix>/alarm/mute/requeston PGN 1269840no—--enable-alarms
<prefix>/alarm/unmute/requeston filter expiry0no—--enable-alarms
<prefix>/alarm/erroron error0no—--enable-alarms
app/nmea2000/infoat connect, at exit, last will1yes3124137600always (MQTT on)

Subscribed ​

TopicPurpose
<prefix>/alarm/activeraise or update an alarm
<prefix>/alarm/clearclear an alarm
<prefix>/alarm/mute/responseanswer a mute request
<prefix>/alarm/unmute/responseanswer an unmute request

All four require --enable-alarms; without it the daemon subscribes to nothing.

<prefix>/interface ​

json
{
  "data": {
    "interface": "can1",
    "state": "ERROR-ACTIVE",
    "up": true,
    "stats": { "tx_frames": 0, "tx_bytes": 0, "rx_frames": 0, "rx_bytes": 0,
               "tx_errors": 0, "rx_errors": 0, "bus_errors": 0, "restarts": 0 },
    "config": { "bitrate": 250000, "sample_point": 875, "tq": 500,
                "prop_seg": 6, "phase_seg1": 7, "phase_seg2": 2,
                "sjw": 1, "brp": 8, "restart_ms": 100, "ctrlmode": 0 },
    "recovery": { "state": "…", "stateCode": 0 }
  },
  "metadata": { "rxDate": "…", "rxTimestamp": 0, "expireAfterSec": 10 }
}

state is one of ERROR-ACTIVE, ERROR-WARNING, ERROR-PASSIVE, BUS-OFF, STOPPED, SLEEPING, UNKNOWN. An interface that is up but exposes no CAN state to the kernel — vcan — reports ERROR-ACTIVE.

<prefix>/devices ​

data carries count and peers[], each peer having addr (0–253) and name (the 64-bit J1939 NAME as a number).

<prefix>/device/<addr>/infos ​

Everything the daemon has learned about one device: addr, name, identityNumber, manufacturerCode, manufacturer, ecuInstance, functionInstance, deviceInstance, functionCode, functionName, classCode, vehicleSystemInstance, industryGroupCode, industryGroup, arbitraryAddressCapable, and — when the device has answered the corresponding request — productInfo, txPgns[] and rxPgns[].

deviceInstance is the 8-bit NMEA 2000 device instance, ecuInstance | (functionInstance << 3). It is the value PGN 126208 changes.

<prefix>/navigation ​

data sections: position, speed_course, wind_apparent, wind_true, wind (deprecated), depth_water, autopilot. Selection, the true wind computation and the deprecated wind section are in Navigation.

PathTypeUnitNotes
data.position.hasFixbooleanalways present in position
data.position.latitude, .longitudenumberdegreesonly when hasFix is true
data.speed_course.sognumber or nullknots
data.speed_course.cognumber or nulldegrees
data.speed_course.speedThroughWaternumberknotsonly when sent
data.speed_course.headingTruenumberdegreesonly when resolvable
data.wind_apparent.speednumber or nullknots
data.wind_apparent.anglenumber or nulldegrees, −180…180relative to the bow, starboard positive
data.wind_true.speednumber or nullknots
data.wind_true.anglenumber or nulldegrees, −180…180relative to the bow, starboard positive
data.wind_true.directionnumber or nulldegrees, 0…360relative to true north
data.wind_true.referencestringwater or ground
data.wind_true.computedbooleantrue when computed from apparent wind
data.wind.*m/s for speedsdeprecated, removed in the next release
data.<section>.sourceobjectonly with --report-metadata-source
metadata.expireAfterSecintegerseconds2

<prefix>/datetime ​

data carries now, date, time, localTime, utcOffset, timezone, offsetSource and a source object (name, friendlyName, pgn, age).

offsetSource follows --datetime-offset: nmea takes the local offset from the bus, auto derives it from the boat's position using the bundled ZoneDetect database.

<prefix>/status ​

One summary of every module, every 30 seconds: a reports object with navigation, motor, thruster, ais, route and datetime sub-objects carrying running, highSpeed, counts and per-data-type selected sources (navigation: position, heading, courseSpeed, wind, windTrue, depthWater, autopilot); and a bus object with peerCount.

<prefix>/config ​

The resolved configuration: modules (per-module enabled flags and their settings), navSources[] (each with name, sourceAddr, friendlyName and per-data-type priorities and block flags), mqtt (topicPrefix) and version.

app/nmea2000/info ​

The daemon info, retained, QoS 1, in the shape every MUXEN daemon uses on app/<daemon>/info — not the {"data", "metadata"} envelope. The topic does not carry <prefix>: the primary daemon (prefix nmea) publishes on app/nmea2000/info, a templated instance (prefix nmea-<instance>) on app/nmea2000-<instance>/info, and any other prefix p on app/nmea2000-p/info with unsafe characters replaced by _. The name is always a single topic level, so one app/+/info subscription lists every daemon and every instance.

json
{
  "name": "muxen-nmea2000",
  "version": "v3.7.0",
  "hostname": "brain-3",
  "features": ["config", "interface", "devices", "datetime", "status",
               "navigation", "alarms"],
  "online": true,
  "metadata": { "rxdate": "2026-09-22T08:04:07.966Z",
                "rxTimestamp": 1790064247, "expireAfterSec": 3124137600 }
}

online is true on every (re)connect, and false on a clean exit (published, then acknowledged by the broker, before disconnecting) and as the MQTT last will when the connection is lost. version is for display only: clients test features, and ignore features they do not know. The metadata key is rxdate, lowercase, unlike the envelope's rxDate: it is the fleet-wide info shape.

features lists the <prefix>/ topic families this process serves, from its resolved configuration:

FeatureTopicsListed when
config, interface, devices, datetime, status<prefix>/config, /interface, /devices and /device/<addr>/infos, /datetime, /statusalways
navigation<prefix>/navigation--report-nav
motor<prefix>/motor--report-motor
thruster<prefix>/thruster--report-thruster
ais<prefix>/ais--report-ais
route<prefix>/route--report-route
pgn<prefix>/device/<addr>/pgn/<pgn>--mqtt-publish-pgn
gpsd<prefix>/gpsd--source-gpsd, on a build with GPSD support
alarms<prefix>/alarm/*--enable-alarms

Deploy configuration parameters ​

Read from the NavigationInstruments device (function 12, instance 0, device id 768) in /etc/muxen/deploy.json.

ParameterTypeEquivalent flag
ReportNavbool--report-nav
NavHighSpeedbool--nav-high-speed
WindDampingint 0–9--wind-damping
ReportMotorbool--report-motor
MotorHighSpeedbool--motor-high-speed
ReportThrusterbool--report-thruster
ReportAisbool--report-ais
AisTrackDepthint--ais-track-depth
ReportRoutebool--report-route
RouteMaxWaypointsint--route-max-waypoints
DatetimeOffsetnmea | auto--datetime-offset

Booleans are the strings "0" / "1"; "true" / "false" are also accepted.

KeyTypeNotes
versionintfile format version
windDampingint 0–9same meaning as the flag
hysteresisobjectper data type, milliseconds
warmupobjectper data type, milliseconds
sources[]arrayat most 256 entries
sources[].namestringJ1939 NAME in hex
sources[].friendlyNamestringup to 64 characters
sources[].dataTypes[].typestringsee below
sources[].dataTypes[].priorityint 1–991 is highest; clamped
sources[].dataTypes[].instanceint 0–7motor type only
sources[].dataTypes[].blockedbool

Data types: position, heading, course_speed (speed_course is accepted as a synonym on read), wind (apparent wind), wind_true, depth_water, autopilot, date, motor. A source with a wind entry and no wind_true entry gets the same settings for wind_true.

Per-data-type defaults:

TypeTTLHysteresisWarm-up
position5 s1000 ms10000 ms
heading5 s500 ms10000 ms
course_speed5 s500 ms10000 ms
wind2 s300 ms5000 ms
wind_true2 sthe wind valuethe wind value
depth_water5 s500 ms10000 ms
autopilot5 s500 ms5000 ms

Selection thresholds: an unconfigured priority counts as 50; at least 2 consecutive valid messages are needed; the expiration counter excludes a source at 5; a source unheard for 60 minutes is removed. The file is refused above 1 MB.

IPC ​

Newline-delimited JSON over a Unix stream socket.

PropertyValue
Default path/run/muxen-nmea2000/sources.sock
Path when RUNTIME_DIRECTORY is set$RUNTIME_DIRECTORY/sources.sock
Path for a non-root user$XDG_RUNTIME_DIR/muxen-nmea2000/sources.sock
Last-resort path/tmp/muxen-nmea2000-<uid>/sources.sock
Socket mode0666 — any local user can connect
Directory mode0750
Concurrent clients8
Per-connection deadline5 s
Request and response limit64 KiB each

Verbs: ping, list_sources, get_nav_config, set_config, reload_config, command_instance, command_field, get_command_status. Envelope and semantics in Navigation.

Files and directories ​

PathContent
/usr/bin/muxen-nmea2000*the daemon and the four tools
/usr/lib/systemd/system/muxen-nmea2000*.servicethe four units
/usr/share/muxen-nmea2000/manufacturers.jsonNMEA manufacturer code to name
/usr/share/muxen-nmea2000/functionNames.jsonJ1939 function code to name
/usr/share/muxen-nmea2000/pgn.jsonPGN number to name
/usr/share/muxen-nmea2000/timezone16.binZoneDetect timezone database
/usr/share/bash-completion/completions/muxen-nmea2000*completion, one file per binary
/etc/nginx/snippets/muxen-ws-nmea.confreverse-proxy snippet
/etc/muxen/deploy.jsonthe boat's commissioning file
/etc/muxen/env.<instance>MUXEN_NMEA_INSTANCE_NAME, MUXEN_NMEA_INSTANCE_ADDRESS
/var/lib/muxen-nmea2000/state directory, mode 0750
/var/lib/muxen-nmea2000/statethe claimed-address state file
/var/lib/muxen-nmea2000/nav-sources.jsonnavigation source configuration, under systemd
/run/muxen-nmea2000/runtime directory, mode 0755
/run/muxen-nmea2000/sources.sockIPC socket

The daemon reads no environment variables of its own beyond systemd's RUNTIME_DIRECTORY and STATE_DIRECTORY.

systemd units ​

UnitEnabled at installNotes
muxen-nmea2000.serviceyesthe commissioned daemon; WantedBy=muxen.target, PartOf=muxen.target, alias muxen-nmea.service
muxen-nmea2000@.servicenoone instance per CAN interface, started on demand
muxen-nmea2000-simulator.servicenothe synthetic bus generator
muxen-nmea2000-from-simulator.servicenoa daemon on vcan0 with --report-all; Conflicts=muxen-nmea2000.service

muxen-nmea2000.service: After=sys-subsystem-net-devices-can1.device mosquitto.service, Wants= the same device, Restart=always, RestartSec=10, TimeoutStopSec=5, StartLimitIntervalSec=300, StartLimitBurst=5, ExecReload=/bin/kill -HUP $MAINPID.

muxen-nmea2000@.service adds ConditionPathExists=/sys/class/net/%i, has no [Install] section, and passes --no-deploy-config --mqtt-topic-prefix=nmea-%i --mqtt-client-id=muxen-nmea2000-%i --state-dir=%S/muxen-nmea2000-%i --enable-alarms.

All units run as User=muxen / Group=muxen with AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN, the same bounding set, ProtectSystem=strict, ProtectHome=yes, NoNewPrivileges=yes, PrivateTmp=yes, MemoryDenyWriteExecute=yes, SystemCallFilter=@system-service, SystemCallArchitectures=native, DevicePolicy=closed and RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_CAN AF_INET AF_INET6.

Packaging ​

Debian package muxen-nmea2000, section net, Architecture: any, Multi-Arch: foreign. Depends: muxen-systemd plus the shared-library dependencies. It ships a muxen-restart-target trigger, so an install or upgrade restarts muxen.target, and activates nginx-reload, so a running nginx reloads and serves a changed muxen-ws-nmea.conf at once.

nginx ​

/etc/nginx/snippets/muxen-ws-nmea.conf maps /ws/nmea to http://127.0.0.1:1884/ with WebSocket upgrade headers and a 15-day read timeout. That port is the MQTT broker's WebSocket listener, not the daemon: this is how a browser front end reaches the same topics.

TypeScript package ​

@muxen/nmea, in typescript/@muxen-nmea/, versioned and tagged together with the daemon. Entry points ., ./message-types, ./plugin. Peer dependencies: mqtt ^4.3.0 || ^5.0.0, and optionally vue ^3.3.0 and pinia ^2.1.0. Node 18 or later.

The store always subscribes to the daemon info of its topicPrefix (nmeaInfoTopic(), same derivation as the daemon) and exposes info, online and supports(feature), also on the useNmea() service; DaemonInfo, NMEA_INFO_TOPIC and isDaemonInfo() are exported.

Units and conventions ​

QuantityUnit in published payloads
anglesdegrees
speed over ground, through water, windknots (m/s in the deprecated navigation wind section)
depth, altitude, cross-track errormetres (distances to waypoints in nautical miles)
temperature°C
pressurekPa
fuel ratelitres per hour
fuel economylitres per nautical mile
engine speedRPM
timeISO 8601 UTC in rxDate, Unix seconds in rxTimestamp

A value the sender marks as not available is published as null, never as zero.

Schemas ​

FileDescribes
schemas/mqtt-schemas.jsonthe per-device PGN topics
schemas/ais-schema.json<prefix>/ais
schemas/ais-sample.jsona worked <prefix>/ais payload

Integration of multiplexed solutions
MUXEN and the MUXEN logo are trademarks of MUXEN SAS.