Appearance
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 themuxenuser and group and ownsmuxen.target. Also a hard dependency.
Recommended, and needed by individual templates rather than by the daemon itself:
| Package | Needed for |
|---|---|
muxen-boat ≥ 9.4.0 | output dimming (dimming-lights) |
muxen-nmea2000 ≥ 3.5.0 | nmea/navigation speed and GPS fix, nmea/motor RPM |
muxen-sensors | app/sensor/<name> tank and sensor values |
muxen-energy | battery and converter data |
Install
sh
sudo apt install muxen-synapseOne 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.serviceThe 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 = 30sAt 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 topicsynapse/fresh-water-port-cutoff. templatenames a file in/usr/share/muxen-synapse/without the.luasuffix.configsupplies 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-synapseOn 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:03ZENABLED 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 -fEvery 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=yesA 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
- The shipped automations and their settings — The shipped automations
- Declaring instances, config validation, persisted state — Deploying automations
- Writing your own automation — Writing an automation
- When something does not work — Troubleshooting
