Appearance
muxen-sensors — Overview
muxen-sensors turns a raw electrical reading into a named quantity the boat can display. A float sender in the fresh-water tank, a pressure probe in a diesel tank, a temperature sensor, a shunt on a solar array — each is wired to an input of a MUXEN device, and each of them reports on the bus nothing more than a channel and a number. muxen-sensors gives that channel a name, applies the calibration curve of the tank or probe it is connected to, and publishes the result once a second as a variable: FreshWaterPortside, 143, litres.
That variable is what the boat's screens draw as a tank gauge or a temperature, and what muxen-energy reads when a current comes from a shunt rather than from a bus device. The daemon has no user interface of its own.
The problem it solves
A MUXEN I/O device reports channels, not meanings. A Bloc 8 broadcasts analogInput0 = 2.71, and nothing on the wire says that this channel is the port fresh-water tank, that the tank holds 250 litres, or that 2.71 corresponds to 143 of them. The sender's own curve is rarely a straight line, two tanks of the same nominal size rarely read alike, and the number an owner wants to see is litres, not volts.
muxen-sensors holds that missing half. For each entry in the boat's configuration file it knows:
- which channel of which device to listen to,
- the range the sender is expected to produce, so a reading outside it is clamped rather than published as nonsense,
- the curve that converts the reading into the physical quantity — a straight line, a polynomial, a table of measured points, or a staircase,
- the range the result may occupy, so a tank never reports more than it holds,
- the name and the unit the rest of the boat knows it by.
The result is a single, stable topic per quantity. Everything downstream — screens, alarms, the energy page, the logger — reads that topic and never has to know which device the sensor was wired to.
Where it sits
/etc/muxen/deploy.json
│ sensors[]
▼
CAN bus (can0) ──────► muxen-sensors ──────► MQTT app/sensor/<name>
▲ (1 Hz) ├──► screens
MQTT device/<f>/<i>/… ────────┘ └──► muxen-energy| It reads | From | Purpose |
|---|---|---|
/etc/muxen/deploy.json | disk, once at startup | the sensors array: which channel, which curve, which name |
| MUXEN broadcast frames | can0 | the live channel readings |
device/<function>/<instance>/… | MQTT | the same readings, when started with --mqtt instead of a CAN interface |
app/sensor/calibration/request | MQTT | a candidate curve to evaluate live, from raken |
device/<function>/<instance>/… | MQTT | the channel a calibration session is watching, subscribed for the length of the session — in CAN mode too |
| It writes | To | Purpose |
|---|---|---|
app/sensor/<name> | MQTT, 1 Hz | the scaled value, its unit, its limits and the raw input it came from; the app/sensor part is --prefix, see below |
app/sensor/calibration/response | MQTT, up to 4 Hz | what a candidate curve makes of the live reading, and what the deployed one makes of it |
| an RTR request for the Bloc 8 I/O frame | can0 | asks a Bloc 8 to report its inputs |
device/<function>/<instance>/rtr/2 | MQTT, 1 Hz | asks a Bloc 8 to report, for a calibration session on a quiet channel |
app/sensor/info | MQTT, retained, on each connection | the daemon's identity, whether it is online, and its features; fixed, not under --prefix |
Those RTR requests are the only thing the daemon ever asks of a device. A Bloc 8 does not broadcast its input frame spontaneously — it answers a request — so the daemon issues one for every Bloc 8 variable it holds, each time the CAN interface comes up, and one a second for a channel a calibration session is watching while it stays quiet. Everything else is read-only: no command is ever sent to a device, and nothing a session does changes what the boat publishes.
Two ways in, one way out
The daemon takes its input either from the CAN bus directly or from the MQTT topics another service already publishes.
| Mode | Started with | Input | Notes |
|---|---|---|---|
| CAN | --interface can0 | broadcast frames on the bus | the default, and what the systemd unit uses |
| MQTT | --mqtt | device/… topics | needs a service publishing them; the package Recommends: muxen-boat for exactly this |
The output is identical in both modes. What changes is where the numbers come from and, in MQTT mode, that this daemon issues no CAN traffic at all — including the Bloc 8 request above.
A calibration session is the one exception. It always reads the device/… topics, in CAN mode as well, because it has to measure a channel that no configured variable reads — and often one no variable has ever been written for. See Calibration and filtering.
What a variable is
One entry in the configuration produces one variable, and the entry's name is the last element of the topic. "name": "FreshWaterPortside" publishes on app/sensor/FreshWaterPortside. Renaming a sensor therefore renames a topic, and everything that subscribed to the old one stops seeing it — which is why names are worth choosing once, at commissioning.
The part in front of the name is --prefix, app/sensor by default. It used to be variable, and 5.0.0 moved it — every consumer moved with it, and no install pins the old value. The option remains because it makes the next rename a configuration change rather than another migration: set MUXEN_TOPIC_PREFIX in a systemd drop-in rather than editing the unit.
The published payload carries the finished value, the unit and limits declared for it, and the raw device reading it was derived from, so a wrong number on a screen can be traced back to the input without touching the bus. Reference has the full shape.
Supported inputs
Three MUXEN device functions can feed a variable:
| Function code | Device | Channels available |
|---|---|---|
| 1 | Power output Bloc 8 | 6 digital inputs, 3 analogue inputs |
| 3 | Power source interconnection | 4 source currents |
| 17 | Generic I/O | 2 digital inputs, 2 relays, 2 analogue inputs |
Any other function code in a configuration entry is refused when the file is read, and the entry is skipped.
Document map
| Document | Content |
|---|---|
| Getting started | install, start, the first variable, how to tell it works |
| Configuration | the anatomy of a sensor entry, key by key |
| Calibration and filtering | the four curves, the filter, how to calibrate a tank, and live sessions from raken |
| Troubleshooting | symptom → cause → check → fix, plus FAQ and tips |
| Reference | CLI, unit, configuration keys, MQTT and CAN interfaces, paths, exit codes |
