Skip to content

What is actually on the wire? ​

The table tools show you a chosen view of a chosen set of devices. Sooner or later a question falls outside all of them: a field a screen reads and no table shows, a tank sensor, an NMEA value, a payload that looks right in one tool and wrong in another.

muxen-diag-data-explorer is the answer to those. It subscribes to everything MUXEN publishes, arranges it as a tree, and shows the full pretty-printed payload of whatever you select.

For an owner: this is the raw data the boat's systems exchange. It is the last resort of diagnosis, and it changes nothing.

Running it ​

sh
muxen-diag-data-explorer                    # the local broker
muxen-diag-data-explorer -h 192.168.1.10    # a boat on the network
muxen-diag-data-explorer --no-deploy        # without the friendly names

The screen is split: a tree on the left, the selected topic's payload on the right. The tree pane takes 40 % of the width, never less than 20 columns and never more than the width minus 20, so it works on a narrow terminal without a warning.

What it subscribes to ​

Three families, and nothing else:

SubscriptionContains
device/+/+/+one topic per device per message type
app/sensor/#named sensors — tanks, temperatures, levels — and their calibration topics
nmea/#NMEA 2000 data and bus status

The three appear as the three top-level branches — device, app and nmea — expanded at start, with the sensors one level down under app > sensor. A branch that stays empty means nothing on that broker is publishing that family.

app/sensor/# also matches app/sensor/calibration/…, which the tool keeps: a calibration that has not been applied is exactly the kind of thing you come here to check. It groups under its own calibration branch rather than mixing with the sensor names.

muxen-sensors before 5.0.0 published on variable/… instead, and an install can still be pinned there with MUXEN_TOPIC_PREFIX. This tool no longer subscribes to it, so an empty sensor branch on a busy boat is worth checking against that pin.

Only retained and live messages appear: the tree is built from what arrives while the tool runs. A topic nobody has published since you started is not there.

The device branch is grouped, not flat ​

Under device, the tree is three levels deep and both of the middle levels are given readable names:

v device
  v Battery (code 5)
    v Bank port (0)
        life
        state
    v instance=1
        life
  v Power output (code 1)
    v Cabin lights (0)
        io
        life
        voltage
  • The function level shows the MUXEN function name with its code.
  • The instance level shows the device's configured name and its instance number in brackets, taken from /etc/muxen/deploy.json.
  • A device with no name in the deployment file shows instance=<n> instead.

--no-deploy skips the deployment file entirely, and then every device shows instance=<n>. Use it when the file is missing, unreadable, or you specifically want to see the raw addressing.

Functions are ordered by function code and instances by instance number, so the tree stays in bus order rather than alphabetical order. The app and nmea branches are alphabetical.

The instance shown here is the bus instance, counted from 0.Bank port (0) is device/5/0/…, and the same battery is Battery #1 in muxen-diag-voltage. This tool is the one that agrees with the topics.

Reading a payload ​

Selecting a leaf shows it on the right:

Topic: device/5/0/life
Updated: 2026-08-16 14:22:07

{
  "id": 5,
  "name": "Bank port",
  "data": {
    "voltage": 51.2,
    "current": -80.1,
    "soc": 78,
    "stateCode": 0
  },
  "metadata": {
    "rxdate": "2026-08-16T14:22:07Z",
    "expireAfterSec": 5
  }
}

Updated is the local time this tool last received the topic — not a timestamp from inside the payload. Watching it advance is how you tell a live topic from one that arrived once and stopped. A topic that is retained on the broker but no longer published shows a fixed Updated and a payload that never changes; that is exactly what a stopped publisher looks like to a screen, and it is why a frozen display can look like plausible data.

The payload is pretty-printed if it parses as JSON, and shown raw if it does not. j and k scroll it, for payloads taller than the pane.

This is the view that settles disagreements between tools: if the field a screen reads is absent from the payload, or holds a different value than another tool draws, you are looking at it here.

Moving around ​

KeyEffect
up / downmove the cursor
right / Enterexpand, or descend to the first child
leftcollapse, or jump to the parent
PgUp / PgDnpage the tree
Home / Endfirst / last
j / kscroll the payload pane
/search
n / Nnext / previous match
Escclear the search
ppause / resume
?help overlay
q, Ctrl-Cquit

/ starts a search, and Enter runs it. Matching is case-insensitive against both the node label and, on a leaf, the full topic — so device/5 finds the batteries and port finds anything with "port" in its configured name.

Enter does more than filter: it expands every collapsed ancestor of every match and jumps the cursor to the first one, so a match buried three levels down is reachable in one keystroke. n and N then step through the matches, wrapping around.

While a search is active the tree is filtered to matching subtrees, and the footer shows the needle. Esc clears it.

Pause ​

p freezes the tree.

Messages that arrive while paused are dropped, not queued. The title bar counts them:

[PAUSED - 1483 msg dropped]

That is deliberate. Queueing them would grow without bound on a busy broker, and resuming would then replay a burst of values that were already stale. Dropping keeps the paused view exactly as it was, and the counter tells you how much traffic went past while you were reading.

Pause is what makes a fast-moving payload readable. Resume, and the tree catches up with whatever arrives next.

The topics: figure in the footer counts distinct topics seen since the tool started, which is a reasonable measure of how much a boat is actually publishing.

When to reach for this tool ​

  • A field is wrong on a screen and right in a table, or the other way round. The payload is the arbiter.
  • A value has no table: tank levels, temperatures and anything else under app/sensor/, and everything under nmea/.
  • A topic is suspected of being retained but dead. Watch Updated.
  • A device name is wrong on a screen. The instance-level label comes from the same deployment file the screens read, so a wrong name here is a wrong name in the file.
  • Nothing is publishing at all. Three empty branches on a boat that should be busy is a broker or a decoder problem, not a device problem.

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