Skip to content

Getting started ​

What you need ​

On the Brain:

  • Mosquitto running and reachable. Everything synapse does is MQTT; by default it connects to 127.0.0.1:1883.
  • muxen-sextant ≥ 2.2.0 — a hard dependency of the package. Every daylight, twilight, tide and nearest-harbour value comes from it. Four of the six shipped templates do nothing useful without it.
  • muxen-systemd, which creates the muxen user and group and owns muxen.target. Also a hard dependency.

Recommended, and needed by individual templates rather than by the daemon itself:

PackageNeeded for
muxen-boat ≥ 9.4.0output dimming (dimming-lights)
muxen-nmea2000 ≥ 3.5.0nmea/navigation speed and GPS fix, nmea/motor RPM
muxen-sensorsapp/sensor/<name> tank and sensor values
muxen-energybattery and converter data

Install ​

sh
sudo apt install muxen-synapse

One package carries the daemon, the operator CLI, the six templates and their generated manifest, the systemd unit, the nginx snippets and bash completion. Lua 5.5 is inside the binary — nothing else to install.

Start the service ​

The unit is muxen-synapse.service and it is wanted by muxen.target, so on a standard Brain it comes up with the rest of the MUXEN stack.

sh
sudo systemctl enable --now muxen-synapse.service
systemctl status muxen-synapse.service

The daemon runs as muxen:muxen under a strict hardening profile, and StateDirectory=muxen-synapse provisions its one writable directory, /var/lib/muxen-synapse.

The startup banner tells you the effective configuration:

console
$ journalctl -u muxen-synapse -n 20 --no-pager
config: verbose = 0
config: deploy = /etc/muxen/deploy.json
config: state = /var/lib/muxen-synapse/state.json
config: templates = /usr/share/muxen-synapse
config: mqtt = 127.0.0.1:1883 (id muxen-synapse)
config: time source = LOCAL
config: max_runtime_ms = 50, fault_threshold = 5, status_period = 30s

At this point the daemon is running but nothing is automated yet. A freshly installed synapse with no synapse section in deploy.json starts no automations — the template library on its own runs nothing.

Declare your first automation ​

Automations are declared in the synapse section of /etc/muxen/deploy.json, the standard MUXEN deployed-project file owned by the config daemon. On a commissioned boat you add them through raken; by hand, the section looks like this:

json
{
  "synapse": {
    "fresh-water-port-cutoff": {
      "template": "sensor-level-detection",
      "config": {
        "variable": "fresh-water-portside",
        "button":   { "deviceId": 0, "index": 3 },
        "lowLevel": 20,
        "action":   "off"
      }
    }
  }
}
  • The key (fresh-water-port-cutoff) is the instance id. It must match [a-zA-Z0-9-]+ and be unique, and it becomes the MQTT topic synapse/fresh-water-port-cutoff.
  • template names a file in /usr/share/muxen-synapse/ without the .lua suffix.
  • config supplies that template's tuning fields. Every field the template declares has a default except the ones marked required; see The shipped automations for each template's fields.

Synapse never writes deploy.json. It also has no live-reload path: it reads the file once at startup, so a config change is applied by restarting the daemon.

sh
sudo systemctl restart muxen-synapse

On a real deployment the config daemon does this for you — its deploy phase fires the muxen-restart-target trigger, which restarts the MUXEN services.

Verify it is working ​

console
$ muxen-synapse-ctl list
ID                       ENABLED  RUNNING  VERSION   LAST_RUN             NOTE
fresh-water-port-cutoff  yes      yes      1.0.0     2026-08-16T09:12:03Z

ENABLED is what you (or the deployment) asked for; RUNNING is what the engine actually has loaded. Both yes means the automation is live. NOTE carries a pending popup or the last error.

list reads the retained synapse/+ status topics straight off the broker — there is no round-trip to the daemon, so it works even if the daemon has just died (you would then see stale rows).

Check the effective settings the instance actually resolved, after schema defaults and any clamping:

console
$ muxen-synapse-ctl config fresh-water-port-cutoff
{
  "variable": "fresh-water-portside",
  "button": { "deviceId": 0, "index": 3 },
  "lowLevel": 20,
  "action": "off"
}

And watch what it does:

sh
muxen-synapse-ctl journal fresh-water-port-cutoff -f

Every line an automation logs is tagged [synapse:<id>], so this is a filtered view of journalctl -u muxen-synapse.

Turn one off and on ​

console
$ muxen-synapse-ctl stop fresh-water-port-cutoff
fresh-water-port-cutoff: enabled=no running=no

$ muxen-synapse-ctl start fresh-water-port-cutoff
fresh-water-port-cutoff: enabled=yes running=yes

A runtime stop calls the script's onStop() — which is where an automation returns devices to a safe state — tears down its subscriptions and timers, destroys its interpreter, and persists the choice to state.json so it survives a restart. The instance stays listed, showing enabled: false.

To force an automation off across the whole fleet regardless of what a user toggled, set "enabled": false on the instance in deploy.json. That is a hard force-off: the instance is not loaded at all and a runtime enable is refused. See Deploying automations.

Look inside a running automation ​

console
$ muxen-synapse-ctl debug fresh-water-port-cutoff --what wiring,config
{
  "id": "fresh-water-port-cutoff",
  "wiring": {
    "subscriptions": ["app/sensor/fresh-water-portside", "device/0/0/state"],
    "timers": [],
    "popup": null
  },
  "config": { … }
}

--- recent log (journalctl -u muxen-synapse | [synapse:fresh-water-port-cutoff]) ---
…

The debug dump is request/response over MQTT and never retained, so it costs nothing at rest. Sections are fsm, variables, config, state, wiring and commands; omitting --what returns all of them.

Where to go next ​

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