Appearance
muxen-nmea2000 — Overview
muxen-nmea2000 is what puts position, heading, wind, depth, engine data and AIS traffic on the boat's screens.
Almost none of that data belongs to MUXEN. It comes from the boat's own instruments — a GPS antenna, a masthead wind vane, a depth transducer, an autopilot, an engine gateway, an AIS transponder — and they all speak NMEA 2000, the marine bus every manufacturer agrees on. That bus is a single yellow cable running the length of the boat, and everything on it shouts its readings into the void several times a second.
muxen-nmea2000 listens. It joins the bus as an ordinary device, decodes the traffic, decides which instrument to believe when two of them disagree, and republishes the result as a small number of tidy summaries the boat's screens subscribe to. It also works the other way round: data the Brain has and the bus does not — a position from a USB GPS receiver, for instance — is transmitted onto the bus so that a chartplotter from any manufacturer sees it.
The daemon has no user interface of its own. What the crew sees is the navigation page, the engine page and the AIS overlay drawing themselves from what it publishes.
The problem it solves
An NMEA 2000 bus is a crowd, not a source of truth.
- Several instruments answer the same question. A boat routinely carries two GPS receivers, a fluxgate compass and a satellite compass, a paddlewheel log and a Doppler log. Each broadcasts position or heading with equal confidence, and nothing on the wire says which one to trust.
- Nothing has a name. A device identifies itself by a 64-bit J1939 NAME and an address it negotiates at power-up. That address can change between one trip and the next. "The masthead unit" is not a concept the bus has.
- The units are the standard's, not yours. Angles arrive in radians, speeds in metres per second, temperatures in kelvin, positions in ten-millionths of a degree.
- Data goes stale silently. An instrument that stops transmitting leaves its last value on the wire in every reader's memory. A frozen depth reading looks exactly like a correct one.
muxen-nmea2000 resolves all four. It maintains a registry of every device it has seen, with its NAME, its manufacturer and its product information; it lets the installer rank sources per data type, so the satellite compass wins heading and the paddlewheel loses to the Doppler; it converts everything into degrees, knots, metres and Celsius; and it ages every field out, so a field that stops arriving becomes null rather than a lie.
Where it sits on the boat
masthead GPS depth autopilot engines AIS
│ │ │ │ │ │
└────────┴────────┴──── can1 ┴──────────┴────────┘ NMEA 2000, 250 kbit/s
│
muxen-nmea2000
(one per CAN bus)
│
┌────────────┼─────────────┐
│ │ │
MQTT nmea/… gpsd (optional) NMEA 2000 transmit
│ (back onto can1)
boat screens, @muxen/nmea,
other muxen-* services| It reads | From | Purpose |
|---|---|---|
| NMEA 2000 / J1939 frames | the CAN interface, can1 by default | every instrument reading on the bus |
/etc/muxen/deploy.json | disk, at startup | which report modules the boat wants |
nav-sources.json | the state directory | per-source priorities and friendly names |
gpsd | TCP localhost:2947, optional | a GPS receiver wired to the Brain, not to the bus |
{prefix}/alarm/… | MQTT | alarm acknowledge and mute commands from the HMI |
| It writes | To | Purpose |
|---|---|---|
nmea/navigation, nmea/motor, nmea/ais, … | MQTT, retained | the summaries the screens draw |
nmea/device/…, nmea/devices, nmea/interface | MQTT, retained | per-device raw data, bus inventory, link health |
| NMEA 2000 frames | the CAN interface | address claim, product information, GNSS PGNs, alerts |
It is a full participant on the bus, not a listener: it claims an address, answers ISO requests about itself, and emits a heartbeat. See Address claiming.
What it publishes
Everything the daemon produces lands under one MQTT prefix, nmea by default. There are two layers.
The reports are the ones a screen subscribes to. Each is a single retained JSON document, rebuilt on a timer, with a data object and a metadata object carrying the time it was built and how long it stays meaningful.
| Topic | Content | Chapter |
|---|---|---|
nmea/navigation | position, heading, COG/SOG, wind, depth, autopilot | 03 |
nmea/motor | per-engine RPM, temperatures, pressures, fuel, warnings | 04 |
nmea/thruster | bow and stern thruster state | 04 |
nmea/ais | AIS targets, aids to navigation, SAR aircraft, safety messages | 05 |
nmea/route | the active route or GoTo, cross-track error, waypoints | 06 |
nmea/datetime | UTC and local date and time | 11 |
nmea/status | one summary of every module's health | 10 |
The bus view is the raw layer underneath: nmea/devices (who is on the bus), nmea/device/<addr>/infos (what each of them says it is), nmea/device/<addr>/pgn/<pgn> (decoded messages, off by default) and nmea/interface (CAN link health and error counters). Full topic list and payload shapes: Reference.
Report modules are opt-in
Out of the box the daemon claims an address, publishes the bus view and nothing else. Each report is enabled deliberately — on the boat by the commissioning file /etc/muxen/deploy.json, on the bench by a command line flag. That is why a fresh install can look silent: it is doing exactly what it was asked.
The two exceptions are nmea/datetime and nmea/status, which are always on.
Configuration covers the layering: built-in defaults, then deploy.json, then the command line, with --report-all on top.
More than one bus
Some boats have more than one NMEA 2000 segment, and some maintenance work needs a daemon on a bus that is not the commissioned one. muxen-nmea2000@.service is a templated unit whose instance name is the CAN interface:
sh
systemctl start muxen-nmea2000@can0An instance deliberately ignores /etc/muxen/deploy.json, publishes under nmea-can0/ instead of nmea/, and carries a J1939 NAME that always loses arbitration to the commissioned daemon. It can therefore never disturb the boat's own gateway. This is the part installers get wrong most often — More than one bus.
What it does not do
- It does not steer, and it does not command. The daemon transmits its own identity, GNSS data when configured to, and alert acknowledgements. It never sends an autopilot command, an engine command or a device configuration write. Configuring MUXEN devices is
muxen-uds's job. - It does not persist history. Everything is current state. The one thing it keeps across restarts is the address it claimed, in a 32-byte state file (The state file).
- It does not authenticate. Anyone who can reach the MQTT broker sees every report and can send alarm commands. The broker and the reverse proxy are the access boundary.
- It does not tolerate the wrong bitrate. NMEA 2000 is 250 kbit/s. The daemon reads the interface's configured bitrate at startup and refuses to run on anything else, because a mismatched node is worse for the bus than an absent one.
Document map
| Document | Content |
|---|---|
| Getting started | install, verify, first data, a real templated instance |
| Configuration | the three configuration layers, deploy.json, environment files |
| Navigation | the navigation report, source selection, muxen-nmea2000-config |
| Engines and thrusters | the motor and thruster reports |
| AIS | AIS targets, aids to navigation, safety messages |
| Routes and waypoints | the active route, GoTo, cross-track error |
| GNSS and gpsd | a GPS on the Brain: reading it, and transmitting it to the bus |
| Alarms | the NMEA 2000 alert subsystem |
| More than one bus | muxen-nmea2000@<iface>, second buses, the tools |
| Troubleshooting | symptom → cause → check → fix, FAQ, tips |
| Reference | CLI, MQTT topics and payloads, units, paths, exit status |
| Address claiming | the J1939 NAME, preferred address, address ranges |
| The address claim state machine | the address claim state machine, in detail |
| The state file | the persisted address, its format and its management commands |
| PGN reference | every PGN decoded and transmitted, Fast Packet, proprietary ranges |
JSON Schemas for the published payloads: MQTT payloads, AIS targets, with an AIS sample.
