Skip to content

Reference ​

Everything the five tools expose, in tables. Nothing here is a procedure; the chapters before it are.

Common to all five ​

Defaults ​

SettingValueApplies to
MQTT host127.0.0.1io, voltage, data-explorer, sfsp
MQTT port1883the same four
MQTT client id<tool-name>-<hostname>-<pid>the same four
CAN interfacecan0devices, sfsp
Redraw period50 msio, voltage, devices
Redraw period100 msdata-explorer

muxen-diag-sfsp has no redraw: it writes lines as they arrive.

The client identifier is qualified with the host name and the process id so that several tools, on several machines, can hold connections to the same broker at once without the broker closing one for the other.

Behaviour shared by every option parser ​

RuleEffect
-V, --versionprint the build version and exit 0
--helpprint the usage block and exit 0
unknown optionprint the usage block and exit 1
-p not a whole number, or outside 1…65535error: invalid port '<v>', exit 1

The version string is git describe --tags --always --dirty captured at build time, not the Debian package version.

--help is written to standard error by muxen-diag-io, muxen-diag-voltage, muxen-diag-data-explorer and muxen-diag-devices; muxen-diag-sfsp writes it to standard output.

MQTT connection ​

Parameteriovoltagedata-explorersfsp
Keepalive5 s5 s5 s60 s
Authenticationnonenonenonenone
QoS on subscribe0000

A failed initial connection is fatal: the tool prints error: cannot connect to MQTT broker at <host>:<port> and exits 1. There is no reconnection from that state.

Signals ​

In the four full-screen tools, SIGINT and SIGTERM leave the main loop cleanly, restore the terminal and exit 0. Q does the same. muxen-diag-sfsp runs on the loop supplied by libstdmuxen and is stopped with Ctrl-C.

Colour pairs ​

Used by muxen-diag-io, muxen-diag-voltage and muxen-diag-devices through the shared TUI layer:

ColourMeaning
greenlive, healthy, or equal
redfault, or an update available
yellowstale, warning, or a pre-release firmware
grey backgroundthe selected row

On a terminal without colour support the selected row is drawn in reverse video and everything else in the default attributes.


muxen-diag-devices ​

Scan the CAN bus, list boards with their firmware version, act on one.

muxen-diag-devices [OPTIONS]

Options ​

ShortLongArgumentDefaultMeaning
-i--interfacecanXcan0CAN interface to scan
-V--version——print the version and exit 0
--help——print the usage block and exit 0

No MQTT options. This tool does not use the broker.

Keys ​

KeyAction
up / downmove the selection
PgUp / PgDnmove ten rows
Home / Endfirst / last row
Uupdate the selected board's firmware
Cclear the selected device's configuration
Rreset the selected device — no confirmation
Ppark the selected device (instance → 63)
Iset the selected device's instance number
Sre-read the selected board's configuration
Erescan the bus and read only unknown boards
Qquit

There is no ? overlay; the action keys are listed in the footer.

Columns ​

ColumnContent
UID16 hex characters, shown on the first row of each board group
Functionfunction name and code, e.g. Power output (1)
Instinstance 0…62, or P for instance 63
Productproduct name, or (same hw) on a non-first row, or read failed
Versionfirmware version the board reports
Latestnewest compatible firmware on disk, with a comparison marker

Latest markers:

MarkerColourMeaning
=greenthe board is at the newest available version
^reda newer version is available
= (Not released firmware, it's CE !)yellowthe board is ahead of anything on disk
-—no compatible firmware on disk

Addressing ​

function = deviceId / 64
instance = deviceId % 64

Instance 63 is the parking address and is displayed as P.

Commands it runs ​

Every one is executed directly, without a shell.

TriggerCommand
startup, [E]muxen-uds -i <iface> uid --scan-to-json <tmp>
startup, [E], [S]muxen-uds -i <iface> -d <id> readconfig --only-name ProductId --only-name SoftwareVersion --save-as-json <tmp>
[U]muxen-uds -i <iface> -d <id> firmware --srec <path>
[C]muxen-uds -i <iface> -d <id> factory --reset-device-configuration
[R]muxen-uds -i <iface> -d <id> reset
[P]muxen-uds -i <iface> -d <id> factory --reset-device-id
[I], on a parked board onlymuxen-uds -i <iface> uid --uds --uid <uid>
[I]muxen-uds -i <iface> -d <id> writeconfig --name InstanceNum --value <n>
[I]muxen-uds -i <iface> -d <id> reset

A non-zero exit status from any of them is reported in the status line.

[U], [C], [P] and [I] run with the table suspended and the command echoed; [U], [C] and [P] then wait for ENTER. The scan, the configuration read and [R] run silently with their output discarded.

Fixed waits: five seconds after a firmware update and after a park, for the board to reboot; one second between each step of [I].

Files ​

PathUse
/usr/lib/muxen/firmwarefirmware root. Not shipped by this package
/usr/lib/muxen/firmware/products.jsonproduct code → readable name
/usr/lib/muxen/firmware/<code>/<code>-v<version>-<name>.sreca firmware image
/tmp/muxen-diag-devices-scan-XXXXXXscan result, created with mkstemp, removed immediately
/tmp/muxen-diag-devices-cfg-XXXXXXconfiguration read result, same

products.json is an array of {"code": …, "name": …}. A product with no entry is displayed by its code.

Firmware selection ​

  • Only files whose name begins <productId>-v are considered.
  • The version is the text between -v and the next -.
  • Versions compare as <major>.<minor>, numerically on each part; a version that does not parse never sorts above one that does.
  • If the board's version parses, only the same major is considered. A board on 5.1 is never offered 6.0.
  • With no readable current version, the newest of any series wins.

Limits and exit codes ​

Device rows128, then [!] table full (128 max)
Products loaded from products.json128
Minimum terminal width105 columns
Status message lifetime10 s
ExitCause
0normal exit, --help, --version
1unknown option, or Error: bus scan failed (is muxen-uds installed?)

muxen-diag-io ​

Live table of Bloc 8 and Generic I/O outputs, digital inputs and analogue inputs.

muxen-diag-io [OPTIONS]

Options ​

ShortLongArgumentDefaultMeaning
-h--hostaddress127.0.0.1MQTT broker
-p--portport1883MQTT broker port
-V--version——print the version and exit 0
--help——print the usage block and exit 0

Keys ​

KeyAction
up / downmove the selection
PgUp / PgDnmove ten rows
Home / Endfirst / last row
F4filter by name
Escclear the filter
?legend
Qquit

Subscriptions ​

TopicFeeds
device/1/+/ioBloc 8 digital and analogue inputs
device/1/+/lifeBloc 8 output states and total current
device/17/+/lifeGeneric I/O relays, inputs and analogue inputs

Payload keys read ​

FunctionTopicKeyColumn
1iodigitalInput0…digitalInput5D0–D5
1ioanalogInput0…analogInput2A0–A2
1lifeout0Code…out7CodeOUT0–OUT7
1lifecurrentTotalread, not displayed
17liferelay0, relay1REL0, REL1
17lifeinput0, input1D0, D1
17lifeana0, ana1A0, A1

Keys are looked up under a data object if the payload has one, and at the top level otherwise.

Output state codes ​

CodeShownColourMeaning
0..plainpower off
1ONgreenpower on
2SCredshort circuit
3NCyellownot connected

Staleness ​

RuleValue
Row goes yellow after30 s without a live update
AGE shows * whenthe last update was 1 s ago or less
AGE shows - whenno live update has ever arrived

A payload carrying metadata.rxTimestamp is treated as expired when now - rxTimestamp exceeds metadata.expireAfterSec (default 30). An expired payload updates the displayed values but not the age, so the row goes stale while messages keep arriving.

Bloc 8 input columns age on the io topic, independently of the output columns.

Display conventions ​

Device labelBloc8 #<instance+1> or GenIO #<instance+1>
Sort orderfunction, then instance
Filtercase-insensitive substring of the label; the topic is matched only if the needle contains / or device
Device limit64, then [!] table full (64 max)
Minimum terminal width123 columns

Exit codes ​

ExitCause
0normal exit, --help, --version
1unknown option, invalid port, or the initial broker connection failed

muxen-diag-voltage ​

Live table of voltage, current and state for every power device.

muxen-diag-voltage [OPTIONS]

Options ​

Identical to muxen-diag-io: -h, -p, -V, --help.

Keys ​

KeyAction
up / downmove the selection
PgUp / PgDnmove ten rows
Home / Endfirst / last row
Dshow / hide the EXTRA column — on by default
F4filter by name
Escclear the filter
?legend
Qquit

Functions and labels ​

CodeLabelCodeLabel
1Bloc811WindTurb
3Interco24MagicTrim
4Group26CGS
5Battery27Alternat
6Converter30BatConc
7Motor
10Solar

Subscriptions ​

device/1/+/life     device/6/+/life     device/26/+/life
device/1/+/voltage  device/6/+/state    device/26/+/state
device/3/+/life     device/7/+/life     device/26/+/state2
device/4/+/life     device/10/+/life    device/27/+/life
device/4/+/state    device/10/+/state   device/27/+/state
device/5/+/life     device/11/+/life    device/30/+/life
device/24/+/life

Which topic fills which columns ​

VOLT/CURR is the primary side, VOLT2/CURR2 the secondary, and EXTRA neither. A topic declares which of the three it feeds, so a state topic that carries only rpm does not announce a secondary electrical side that would then be drawn as 0.0.

FunctionTopicFillsKeys read
1 Bloc 8lifeprimarycurrentTotal → CURR
1 Bloc 8voltageprimaryvoltage → VOLT
3 IntercolifeprimaryoutputTension, outputCurrent, countActiveBattery, countTotalBattery
4 Grouplifeprimaryvoltage, state, stateCode, temperature
4 Groupstatesecondaryvoltage, current, rpm, power
5 Batterylifeprimaryvoltage, current, soc, temperature, state, stateCode
6 Converterlifeprimaryvoltage, current, state, stateCode, temperature
6 Converterstatesecondaryvoltage, current
7 Motorlifeprimaryvoltage, current, state, stateCode, temperature, rpm
10 Solarlifeprimaryvoltage, current, state, stateCode, temperature
10 SolarstatesecondaryvoltagePanel, currentPanel
11 Wind turbinelifeprimaryvoltage, current, state, stateCode, temperature, rpm
24 MagicTrimlifeprimaryvoltage, current, temperature, rpm
26 CGSlifeprimaryvoltage, current, motorTemperature
26 CGSstateextra onlymotorRpm
26 CGSstate2secondarymotorLineToLineVoltage, motorPhaseCurrent
27 Alternatorlifeprimaryvoltage, current, state, stateCode
27 Alternatorstateextra onlyrpm, temperature
30 BatConclifeprimaryvoltage, current, soc, temperature, state, stateCode

Where both state and stateCode are listed, stateCode wins when both are present: devices publish state as a label and stateCode as the number the row colours by.

The battery's and the concentrator's state topics are deliberately not read — they carry charge limits, which are configuration rather than measurement.

Secondary sides ​

FamilyVOLT2/CURR2 is
Converterthe AC / inverter side
Solarthe panel side
Groupthe internal generator
CGSthe motor windings

Every other family shows -.

State names ​

FamilyCode → name
Battery, BatConc0 OK, 1 WARN, 2 ALARM
Converter0 OFF, 1 BULK, 2 ABSO, 3 FLOAT, 4 FAULT, 5 INV
Solar0 OFF, 1 BULK, 2 ABSO, 3 FLOAT, 4 FAULT
Group0 OFF, 1 CONTACT, 2 START, 3 ON, 4 STOP, 15 ERROR
Motor0 OFF, 1 REGEN, 2 DRIVE, 3 ERROR
Wind turbine0 OFF, 1 ON
Alternator0 OFF, 1 ON, 2 FAULT, 3 BULK, 4 ABSO, 5 FLOAT, 6 STOR, 7 EQUAL, 8 ASSIST, 9 LP

An unmapped code is shown as ?.

Colours: red on FAULT / ERROR / ALARM, yellow on WARN, green on any other non-zero state, plain on OFF / OK. The CGS has no state.

EXTRA per family ​

FamilyFields shown
Battery, BatConcstate, SOC:<n>%, T:<n>
Converter, Solarstate, T:<n>
Groupstate, T:<n>, <n>rpm, <n>W
Motor, Wind turbinestate, T:<n>, <n>rpm
MagicTrimT:<n>, <n>rpm
Interco<n>/<n> bat
CGST:<n>, <n>rpm
Alternatorstate, T:<n>, <n>rpm

Display conventions ​

Device label<Family> #<instance+1>
Sort orderfunction, then instance
Stale after30 s
Device limit64, then [!] table full (64 max)
Minimum terminal width87 columns

Exit codes as muxen-diag-io.


muxen-diag-sfsp ​

A running log of wireless switch activity. Line-oriented, not a table.

muxen-diag-sfsp [OPTION]

Options ​

ShortLongArgumentDefaultMeaning
-i--interfacecanXcan0CAN interface to read
-h--hostaddress127.0.0.1MQTT broker — giving this switches the tool into MQTT mode
-p--portport1883MQTT broker port
-V--version——print the version and exit 0
--help——print the usage block on stdout and exit 0

The two modes are exclusive: with -h the CAN interface is not opened; without it the broker is not contacted.

Output ​

All three lines go to standard output and are flushed immediately.

LineWhen
switch <n>: button <b> presseda button changed to pressed
switch <n>: button <b> releaseda button changed to released
receiver <n>: emulating <c> switchthe emulated-switch count changed
receiver <n>: unknown switch detected <d> (0x<h>)on every such frame, not only on change

<n> is the device instance plus one; <b> is the button index plus one. Only buttons 1 to 4 are reported.

CAN mode ​

Function 23SFSP interrupter — its life frame carries the buttons
Function 22SFSP receptor — life carries the emulated count, state the unknown switch id
Kernel filtersthree, one per frame above, matched on broadcast identifier and source function across all instances

A read error on the socket ends the program.

MQTT mode ​

TopicRead
device/23/+/lifebp0…bp7, of which the first four are reported
device/22/+/lifeNbEmulatedInter
device/22/+/stateid — the unknown switch identifier

Keys are looked up under a data object if present, at the top level otherwise. On connection it prints mqtt: connected to <host>:<port> on standard error; on failure, mqtt: connection failed (rc=<n>).

Limits ​

Instances tracked64 per family
Buttons reported4
MQTT keepalive60 s

muxen-diag-data-explorer ​

The whole MQTT topic tree with pretty-printed payloads.

muxen-diag-data-explorer [OPTIONS]

Options ​

ShortLongArgumentDefaultMeaning
-h--hostaddress127.0.0.1MQTT broker
-p--portport1883MQTT broker port
--no-deploy—offignore /etc/muxen/deploy.json, so no friendly device names
-V--version——print the version and exit 0
--help——print the usage block and exit 0

Keys ​

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

Subscriptions ​

TopicBranch
device/+/+/+device
app/sensor/#app > sensor
nmea/#nmea

All three branches are created at startup and expanded, as is the sensor level under app.

Tree shape ​

A topic of exactly the form device/<function>/<instance>/<leaf> is grouped three levels deep:

LevelLabel
function<function name> (code <n>), or code <n> if the name is unknown
instance<device name> (<instance>), or instance=<instance>
leafthe last topic segment

Any other topic under the three roots is split on / and each segment becomes a level, to a maximum of eight segments.

Function nodes sort by function code, instance nodes by instance number, everything else alphabetically.

Instances here are the bus instances, counted from 0.

Device names ​

Read from /etc/muxen/deploy.json at startup, unless --no-deploy was given.

Looked upSource
device entrydevices[], matched on function and instance
namethe Name parameter, falling back to Name.FR

A missing file, an unreadable file or a device with no name leaves the instance level showing instance=<n>.

The payload pane ​

LineContent
Topic:the full topic, or (branch) on a non-leaf node
Updated:local time of the last reception, YYYY-MM-DD HH:MM:SS, or -
belowthe payload, pretty-printed if it parses as JSON, raw otherwise

Scrolling is clamped so the last line cannot be pushed off the top.

Pause ​

Messages arriving while paused are dropped, not queued. The title bar shows [PAUSED], or [PAUSED - <n> msg dropped] once any have been dropped. The counter is reset each time pause is entered.

Layout ​

Tree pane width40 % of the terminal, minimum 20 columns, maximum width − 20
Redraw period100 ms
Footertopics: <n> — distinct topics seen since startup

No minimum-width warning; the layout reflows instead.

Exit codes as muxen-diag-io.


Packaging ​

FieldValue
Source packagemuxen-diagnostic-tools
Binary packagemuxen-diagnostic-tools
Architectureany, Multi-Arch: foreign
Sectionmisc
Dependsmuxen-uds (>= 9.8.2), plus the shared-library and misc substitutions
Homepagehttps://www.muxen.fr

The package installs no systemd unit, no configuration file, no maintainer script and no conffile.

Installed files ​

PathContent
/usr/bin/muxen-diag-devicesthe device manager
/usr/bin/muxen-diag-iothe I/O explorer
/usr/bin/muxen-diag-voltagethe voltage explorer
/usr/bin/muxen-diag-sfspthe wireless-switch log
/usr/bin/muxen-diag-data-explorerthe topic-tree explorer
<bash-completion completions dir>/muxen-diag-*one completion per tool

The bash-completion directory is taken from the bash-completion pkg-config file when it is available, and falls back to <datadir>/bash-completion/completions otherwise.

Files read, and not shipped ​

PathRead byShipped by
/usr/lib/muxen/firmware/muxen-diag-devicesanother package
/etc/muxen/deploy.jsonmuxen-diag-data-explorerthe boat's deployment

Building from source ​

sh
meson setup builddir
meson compile -C builddir
meson test -C builddir
CommandEffect
make debbuild the Debian package
make deva fresh build with the address sanitiser, then the tests
make lintreformat in place to .clang-format
make lint-checkreport formatting differences without changing anything
make mrproperremove every generated file, vendored libraries included

Two test binaries run under meson test:

TestCovers
firmware selectionversion comparison and the same-major firmware rule
view clampingthe shared list clamping used by every table view

Dependencies: ncursesw, glib-2.0, json-c (with a subproject fallback), and the MUXEN libcanmqtt, libstdmuxen and libmuxenfile, each resolved as an installed package if present and as a Meson subproject otherwise. bash-completion is optional.

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