Appearance
Troubleshooting
Most muxen-uds failures come back as the same thing: silence. A device that is off, a device sharing its address with another, an interface that is down and a bus with no terminator all produce "no answer, ensure device is online". This chapter is organised by what you see.
Before anything else: nothing in this chapter is made worse by retrying. Reads are read-only, writes are skipped when the value already matches, and an aborted firmware transfer stops rather than leaves a device half-written.
Nothing answers at all
cmd: read stopped at id 0: no answer, ensure device is online
cmd: failed to initialize can receiverWork down this list; each step rules out everything above it.
| Check | Command |
|---|---|
| The interface exists and is up | ip -details link show can0 |
| The interface is the one you meant | muxen-uds -i canX …, or MUXEN_INTERFACE for the daemon |
| Anything at all is on the bus | candump can0 |
| Devices announce themselves | muxen-uds -i can0 scan --timeout 10 |
| Devices answer when asked | muxen-uds -i can0 uid --scan |
candump showing traffic while scan shows nothing means the frames on the bus are not MUXEN broadcast frames — a wrong bitrate, or the wrong bus.
Both scans silent while candump is silent too is a wiring or power problem, not a muxen-uds problem.
One device does not answer, the others do
| Cause | How to tell | Fix |
|---|---|---|
| Address collision | uid --scan marks the id with X | Assign a new instance by UID — Devices, addressing and discovery |
| Device parked | uid --scan shows instance 63 (parking) | Assign an instance, or activate it with uid --uid … --uds |
| Wrong device id | the id is absent from uid --scan entirely | Read the table again; prefer -F/-I if you know the function |
| Device genuinely off | absent from both scans, and candump never shows its address | Power and wiring |
The collision case is worth ruling out first, because nothing else in the tool can distinguish a contended address from a dead one.
In scan but not in uid --scan, or the reverse
The two scans answer different questions and disagreeing is normal.
- In
scan, not inuid --scan— the device transmits but did not answer the UID request. Re-run; the request is re-broadcast every second over a 4-second window, so a single missed frame is unusual. Persistent absence points at a firmware that does not implement the UID answer. - In
uid --scan, not inscan— normal. The passive scan only hears devices that broadcast on their own, and a device can be perfectly healthy and quiet during the window. Lengthen--timeout, or trust the active scan.
uid --instance times out or writes the wrong unit
Two preconditions, both easy to miss:
- The parking address must be free. The sequence parks the target at instance 63 of its function. If a device with an unassigned instance is already sitting there, the write lands on it — or on neither. Give unassigned units real instances one at a time, before fixing collisions.
- The target must be uniquely reachable by UID. The UID is unique even when the device id is not, which is exactly why this works on a colliding pair. But
--uidis mandatory: without it the command prints its help and does nothing.
writeconfig reports success but nothing changed
At the default log level a skipped parameter is silent. Run it again with -vv and the reason appears:
skipping: #004 VbatMin = 2800
cmd: parameter name 'VbatMinimum' do not exists, skipping...
cmd: parameter 'VbatMin' value out of range; skippingThree distinct causes:
- Already equal. A no-op write is skipped by design.
- Unknown name. The name is not in the device's table — check the exact spelling with
readconfig. - Out of range. The value does not fit the type the device declared for that parameter, so it is skipped rather than truncated.
A read-only name (ProductId, HardwareId, SoftwareId, SoftwareVersion, FonctionGroup) is dropped without comment. Those are identity fields; there is no way to write them.
writeconfig refuses to start
| Message | Cause |
|---|---|
Property must be selected by id and name, use one selector | neither --name nor --id was given |
Can't target the property by id and name, use only one selector | both were given |
value is missing, or clear flag | no --value and no --clear |
Do not use the property selector id or name, when you restore a configuration from json | --from-json combined with --name/--id |
failed to load configuration from <file> | the file is missing, unreadable, or has no parameters array |
readconfig fails partway
cmd: read stopped at id 12: answers kept echoing another identifier
cmd: read stopped at id 12: answer could not be parsed
cmd: device answered but holds no parameter
cmd: none of the requested parameters exist on this deviceThe walk only ends successfully on a negative response. Anything else is a failure, and no file is written — a truncated dump would otherwise be restored later, or deployed, as if it were complete.
Answers kept echoing another identifier is the signature of a bus busy enough that answers arrive after their own request timed out. It resolves itself on a quieter bus; if it does not, look for a device flooding the segment.
A firmware upload fails
| Symptom | Likely cause | Action |
|---|---|---|
cmd: srec filepath is missing | neither --srec nor --name was given | — |
cmd: firmware with name (X) is missing | no .srec with that exact name under the firmware store | muxen-uds listfirmware and copy the name from there |
cmd: can not read the srec file: <path> | wrong path, or not readable by this user | — |
cmd: failed to read '/usr/lib/muxen/firmware/products.json' | the muxen-firmware package is not installed | sudo apt install muxen-firmware |
step 2: download request failed | the device never accepted the transfer | Check the device answers readconfig at all; check the image's major version matches the device's SoftwareVersion |
| the transfer stops partway | a block was refused after ten retries | See below |
A transfer that dies partway is almost always bus contention: the upload competes with normal traffic, and each block has a bounded retry budget. Retry it on a quieter bus, and do not run two uploads — or an upload and a deploy — at the same time.
An image from the wrong major version is refused before any data is written, so a failure at step 2 costs nothing. Match the image to the device's SoftwareVersion — see Firmware.
deploy skips every device
json
{ "deviceId": 320, "deployed": false, "error": "offline" }deploy and checkconfig both gate on the UID scan: a device the scan did not see is skipped. That is deliberate — deploying onto an address whose owner is unknown is how a configuration lands on the wrong box.
If you know the device is there:
- Re-run
uid --scanand look for anXor a parked instance. - If the device is genuinely present and simply did not answer,
--forcebypasses the gate.
checkconfig reporting "online": false for a device that the scan did see means the configuration read itself failed — treat it as a readconfig failure above.
deploy --check-only changed my devices
It no longer does. Up to and including 9.8.4 it did: the flag reached the write step, so nothing was written — but the factory reset that precedes every write ran first, unconditionally, and every device the deploy walked was left at its defaults.
Since that was fixed, --check-only skips the factory reset, the 3-second flash wait and the deployed.json update, and the write step only compares. The bus is left exactly as it was found.
If you are on an older build, recovery is a normal deploy (without the flag), which re-applies the project.
For a detailed comparison, still prefer checkconfig: it lists every parameter that differs, where deploy --check-only stops at the first one. See Deploying a boat configuration.
A web interface cannot connect
| Check | How |
|---|---|
| The daemon is running | systemctl status muxen-uds.service |
| It is listening | ss -ltnp | grep 12345 |
| Locally reachable | curl -i -N -H 'Connection: Upgrade' -H 'Upgrade: websocket' -H 'Sec-WebSocket-Version: 13' -H 'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==' http://127.0.0.1:12345/ |
| The proxy is wired | the nginx site includes snippets/muxen-ws-uds.conf |
The daemon serves plain WebSocket only. A page served over HTTPS cannot open a ws:// socket, so an HTTPS interface must go through the proxy, which terminates TLS and forwards to 127.0.0.1:12345.
The unit sets RestrictNetworkInterfaces=lo, so a browser on another machine cannot reach the daemon directly whatever the firewall says — the proxy is the way in.
A WebSocket request is rejected
Validation failures come back as { "type": "error", "uuid": …, "error": … }:
| Error | Meaning |
|---|---|
Invalid JSON document | the message did not parse |
UUID parameter is missing / UUID parameter is not a string | no correlation id; the daemon logs it and answers without a uuid |
command parameter is missing / unknown command | see the command list in WebSocket protocol |
deviceId parameter is missing | the command needs a target |
deviceId out of range | not a JSON integer in 0–0xFFF |
failed to parse parameter for the command | the parameters object did not validate |
aborted | the client cancelled the job while it was still queued |
A message larger than 1 MiB is dropped without an answer — requests are small JSON documents, and firmware is referenced by path, never streamed.
Requests seem to be queued behind each other
They are, and mostly on purpose. The daemon serves requests with two worker threads:
- one for passive commands (
scan,listfirmware), which do not drive the bus; - one for active commands — everything else.
So a 30-second scan does not block a write, but two writes are serialised. A long deploy or firmware command holds the active worker for its whole duration; a UI should reflect that rather than fire more commands into it.
If a page is refreshed mid-burst, its still-queued requests are flushed rather than executed, so the reloaded page is not stuck behind the previous session's dead queries.
Getting more detail
sh
muxen-uds -v … # one summary line per command
muxen-uds -vv … # all diagnostic chatter
journalctl -u muxen-uds -f # the daemon's log
systemctl status muxen-uds.serviceThe CLI's last line always reports the command, the device and the return code:
cmd: reset device-id=0x280 rc=0Note that this line only appears at -v or above; the process exit status (0 success, 1 failure) is the reliable signal for a script.
FAQ
Why did my setting go back to what it was? Something re-applied the boat's configuration. A deploy replaces a device's settings wholesale with what the project file says, and a firmware update resets them. Both are deliberate acts by an installer, not something that happens on its own.
Is it safe to run a scan while we are under way?scan is: it only listens. uid --scan sends one broadcast request per second for four seconds, which every device is expected to answer and which changes nothing. Writes, resets, deploys and firmware uploads are the ones to keep for a quiet moment.
Can I use the tool while somebody is using the touchscreen? Yes. Both go through the same daemon, which serialises the work. The screen may feel slow while a long command runs.
How long does a firmware update take? It depends on the image size and how busy the bus is, and it is not predictable enough to promise a number — which is precisely why the client treats an upload as an idle-timeout operation rather than a timed one. Watch the percentage; if it is still moving, it is working.
The tool says my device is offline but its LEDs are on. The most likely explanation is an address collision: two boxes answering to the same number cancel each other out and both look dead to the tool. Run uid --scan and look for an X.
Which box is device 640?muxen-uds -i can0 -d 640 locate makes it blink.
Do I need to reboot a device after changing a setting? Some settings only take effect on restart. --reboot does it as part of the write, and only if the write succeeded.
Tips
- Run
uid --scanbefore any deploy or firmware session, and fix everyXand every parked instance first. Addressing problems masquerade as everything else. - Keep the parking address free. Instance 63 of each function is working space for UID-addressed operations; a device left sitting there breaks them.
- Dump a device's configuration before touching its firmware.
readconfig --save-as-jsoncosts seconds and turns a failed update into an inconvenience. - Use
checkconfigwhen you want to know what differs. Both it anddeploy --check-onlyare read-only, butcheckconfigreports every mismatched parameter, wheredeploy --check-onlyanswers yes/no per device and stops at the first difference. backupwrites into the current directory.cdsomewhere deliberate first, and remember it only covers devices the passive scan heard.- Avoid
--speedyfor anything that matters. It disables retries and shortens timeouts; it is for interactive polling, not for writes. - Prefer
--nameover--id. Identifiers move between firmware versions; names do not. -vvis the first diagnostic step, not the last. Most silent skips print their reason there.- Do not run two writing clients at once. The daemon serialises, but two operators deploying different projects onto the same bus will produce a result neither expected.
- Watch
/var/lib/muxen/deployed.jsonafter commissioning: it records which UID was found at which device id, and it is the fastest way to notice that a box was replaced.
