Skip to content

Troubleshooting ​

This chapter is organised by what you see. The daemon has no control socket and no status command: everything it knows, it says in the journal at startup or publishes on MQTT, so those two are the whole toolbox.

sh
journalctl -u muxen-energy -n 100          # the startup log, and any errors
journalctl -u muxen-energy -f              # follow it
mosquitto_sub -h 127.0.0.1 -t 'app/energy/#' -v    # the published summaries
mosquitto_sub -h 127.0.0.1 -t 'app/energy/info' -v  # version, online, data source
systemctl status muxen-energy

No app/energy/… topic at all ​

Nothing is published for any zone.

Likely causeWhat to checkFix
The daemon is not runningsystemctl status muxen-energysee the service restarts every 30 seconds below
It is running but built no zoneszones: 0 zones in the journalnothing in the configuration binds a device or enables a sensor — see Energy zones
The broker refused the connectionno mqtt: connected linethe daemon exits when it cannot connect at startup; check the broker

Zones exist only because a device or a variable claims one. An EnergyZoneName<N> setting on its own creates nothing, and a zone with neither devices nor variables is skipped rather than published — so a setting for a zone that no device joined never produces a stray topic.

The service restarts every 30 seconds ​

Restart=always with RestartSec=30, so a daemon that fails at startup loops on that period. The journal names the reason on each attempt:

MessageCauseFix
config: configuration file is missingno --energy argumentthe unit supplies it from MUXEN_DEPLOY; check a drop-in has not overridden it to an empty value
config: select a CAN interface, or the MQTT sourceneither --interface nor --mqttthe unit passes --interface can0; check a drop-in has not replaced ExecStart
zone: failed to parse the JSONthe file is missing, unreadable, not valid JSON, or its root is not a JSON objectvalidate the deployment file
init: Failed to load the sensors configuration filefollows the line aboveas above
init: Failed to create dispatchersthe handler tables could not be builtrare; report it
no message, exits after config: linesthe MQTT connection or the CAN socket failedsee the next two entries

The first two exit with status 1 and print the usage block. The rest exit with status 255.

The daemon exits right after printing its configuration ​

Two silent failures land here, and which one it is depends on whether the journal shows a mqtt: connected line:

  • No mqtt: connected — the broker is not reachable on 127.0.0.1:1883. The daemon does not wait for it. Check systemctl status mosquitto.
  • mqtt: connected and then nothing — the CAN interface named by --interface does not exist. Check ip link show can0. The unit is bound to sys-subsystem-net-devices-can0.device, so on a Brain whose bus is not can0 both the binding and ExecStart need a drop-in.

A zone publishes, but every number is zero ​

The topic is there, the timestamp advances, and all the currents are 0.

Every device and variable is dropped from the sum if it has not reported within five seconds, so this is what an entire zone going quiet looks like.

  1. Is the bus alive? candump can0 for a few seconds. Nothing at all means the problem is upstream of this daemon.
  2. Did the daemon subscribe to anything? The journal prints can: dispatcher table size: N at startup. 0 means no device of a supported type was bound to any zone.
  3. Is the daemon reading the source you think? config: data source = says can or mqtt. In --mqtt mode the CAN table is empty by design, and the daemon depends entirely on another service publishing device/… topics.
  4. Are the instances right? The CAN table lists one row per subscription with the exact frame ID it matches. A device configured at the wrong instance produces a subscription that never fires, and looks exactly like a silent device.

One device contributes nothing, the rest of the zone is fine ​

Likely causeHow to confirm
It is a function the daemon does not consumecan: not supported device type <N> at startup, with <N> its function code
It is bound to a different zonethe -v zone tree lists each device under its zone
Its BindToParc is a JSON number, not a stringthe value is ignored and the device silently lands in zone 1
Its instance differs from the one on the buscompare the CAN table's frame IDs against candump
It reports less often than every five secondsit will flicker in and out of the sum

A device may also be missing from the tables entirely: an entry in devices[] whose function or instance is absent, or is not an integer, is skipped without a message.

Everything ended up in "Zone 1" ​

Devices with no BindToParc parameter — or with a negative one — join zone 1. On a boat where the parameter was never set, that is every device in the file, and zone 1 becomes a meaningless mixture while the other zones stay empty.

The -v zone tree shows it immediately. The fix is in the deployment file, one BindToParc per device.

A zone is called "Zone 3" instead of its real name ​

No setting named EnergyZoneName3 was found. Check the settings[] section for the exact spelling — the key is the literal string EnergyZoneName with the zone number appended, and the name is taken from the setting's value field.

socValid is false ​

Two causes, and the journal cannot tell them apart:

  • One of the batteries in the zone reports a state of charge of 255, the "not available" value. A single such module invalidates the whole zone.
  • No battery reported within five seconds. The soc field then still holds 0, which is exactly why the flag exists — otherwise a silent bus would publish a plausible flat bank.

Check mosquitto_sub -t 'device/5/+/life' -v (or candump can0) to see whether the batteries are talking and what state of charge they send.

autonomy is 0 while the bank is clearly discharging ​

In decreasing order of likelihood:

  1. capacity is 0. No battery in the zone carries a Capacity parameter, so the remaining capacity is zero and so is the estimate. This is the common one. Check the payload's capacity field.
  2. soc is 0, so remaining capacity is zero even with a capacity configured. Look at socValid.
  3. The filtered current is not negative. The estimate uses the filtered value, not the instantaneous one; a bank that has only just started discharging is still averaging in the previous minute.
  4. The daemon restarted less than a filter period ago. The history starts at zero and needs 20 to 60 seconds to fill.

chargingTime is 0 under the mirror-image conditions.

autonomy looks too pessimistic ​

It is meant to. The filter drops the extremes and then weights the remaining samples towards the most-discharging end, so a bank with an intermittent heavy load reports a shorter time than the arithmetic mean would give. Raising --filter-period lengthens the window — up to 60 seconds — but does not remove the bias.

dischargeOther is large ​

Not a fault. It is the boat's uninstrumented consumption: everything the configured equipment does not account for. Bloc 8 outputs and interconnections also land there, because they are collected but not yet published in their own right.

It becomes a symptom when it changes without the installation changing, or when it is large on a boat you believe to be fully instrumented — in which case a source or a load is missing from the zone, or is bound to the wrong one.

A converter's current appears on the wrong side ​

Check the -v zone tree: each converter prints Connected to: output or Connected to: input under the zone it belongs to.

  • BindToParc selects the output side, read from the life frame.
  • InputBindToParc selects the input side, read from the state frame.

A converter with no BindToParc at all lands in zone 1 and is read on its input side there, which is rarely what is wanted.

If the side is right but the sign is not, the device is sending a convention the daemon does not expect; capture the frame and report it.

The numbers on the screen are frozen ​

The app/energy/<zone> topics are retained. A stopped daemon leaves its last payload on the broker, and a screen that reads the retained message shows perfectly plausible figures forever.

sh
mosquitto_sub -h 127.0.0.1 -t 'app/energy/#' -v -W 3

If the payload arrives once and never repeats, the daemon is not publishing. Compare metadata.rxdate against the current time.

A decommissioned zone still shows up ​

Same cause, opposite direction: removing a zone from the configuration stops the daemon publishing it, but does not remove the retained message already on the broker. Clear it explicitly:

sh
mosquitto_pub -h 127.0.0.1 -t app/energy/7 -r -n

--filter-period did not take the value I gave ​

The value is clamped to 20…60 seconds, and the daemon says so:

config: filter period set to 60 seconds

An unparseable value is refused outright with config: invalid filter period '<value>' and the daemon exits with status 1.

FAQ ​

Why does the energy page say "Zone 2" instead of "Starboard bank"? The name comes from a setting in the boat's configuration file called EnergyZoneName2. If it is missing, the daemon falls back to the zone number. An installer needs to add it and restart the service.

Why is the remaining time shorter than my own calculation? On purpose. The estimate leans on the periods when the bank was discharging hardest, so it errs short rather than long. A number that promises more time than the boat has is worse than one that promises less.

Why does the remaining time disappear when I switch a load on? It does not disappear — it goes to zero because the filtered battery current has crossed into charging, at which point the daemon publishes chargingTime instead. Only one of the two is ever non-zero.

The batteries are fine, so why does the screen show no state of charge? One battery in that zone is reporting "not available" for its state of charge, which invalidates the figure for the whole zone. It is usually a module that has just been replaced or has not finished initialising.

What is "other" on the energy page? Everything on the boat that is not individually metered: cabin lighting, fridges, the autopilot, the electronics. The daemon works it out from the difference between what the known sources and loads do and what the battery actually does, so the page always adds up.

Do I have to restart anything after changing the configuration? The daemon reads the file only at startup. Changing /etc/muxen/deploy.json restarts the MUXEN deployment target, which restarts the daemon, so in normal use it happens by itself. Editing the file by another route needs systemctl restart muxen-energy.

Can it work without a CAN bus? Yes — --mqtt takes the same device data from the MQTT device/… topics instead of the bus. Sensor variables always come from MQTT regardless.

Why is there no zone 0? Devices never land in zone 0: an unbound device falls back to zone 1. Only a sensor variable can declare energy.zone: 0.

Why does an AC zone show 0 W? powerUsed is a current multiplied by the zone voltage, and the voltage comes from a battery. A zone with no battery has no voltage, so no power — the currents are still published.

Tips ​

At commissioning, work through the zone tree. Run the daemon by hand once with -v and read the tree it prints. Every device you expect should be there, under the right zone, with the right function name; each converter should show the side you intended. It is faster than diagnosing the published payload afterwards.

Set Capacity on every battery before anything else. Without it a zone publishes currents but no remaining time, which is the single most common commissioning complaint.

Record dischargeOther at handover. On a settled boat it is nearly constant. Knowing its normal value turns it into a diagnostic: a step change with no change to the installation means something new is drawing, or a metered load has stopped reporting.

Give the estimate a minute after a restart. The filter history starts empty, so the first 20 to 60 seconds of autonomy mean nothing.

Do not raise --filter-period to smooth a noisy display. The window is bounded at 60 seconds and the bias is by design; a display that flickers is better fixed by the screen's own smoothing.

Avoid leaving devices unbound. They land in zone 1 and either pollute it or fill the journal with not supported device type lines that mask the ones that matter.

Clear retained topics when you remove a zone, otherwise the old summary stays on the broker for the next screen that subscribes.

Check the clock. Every payload carries expireAfterSec: 5 and a timestamp; consumers that compare it against a Brain whose clock has jumped will treat live data as stale.

-vv on a live bus is a firehose. It dumps every CAN frame and every MQTT message the daemon sees — which is all of them, since it subscribes to #. Use it against a quiet bus or for a few seconds at a time.

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