Appearance
muxen-synapse — Overview
muxen-synapse is the automation layer of the MUXEN Brain. It runs small, self-contained rules on board — "show the anchor light when it gets dark and we are lying at anchor", "cut the fresh-water pump when the tank runs low", "ask before starting the watermaker" — without anyone touching a switch and without new software being written for the boat.
Each rule is called an automation. An automation is a piece of Lua code that watches the boat's data, decides something, and either acts on a device or asks the crew first. Automations are turned on and off one at a time from the interface, and each one reports its own state, so you can always see which are running and which have a problem.
The problem it solves
The Brain already publishes everything the boat knows — tank levels, battery state, engine RPM, position — on MQTT, and every actuator on board already accepts a command on MQTT. What was missing was somewhere for the rules to live. Before synapse there was no scene engine, no rule engine and no macro system anywhere in the MUXEN stack: "if the bilge is high, run the pump" had no home.
Synapse is that home. Adding or changing an automation is a configuration change, not a software release.
Templates and instances
Reusable automations ship inside the package as a template library. A boat's deployed configuration then declares the instances it actually runs — which templates, how many of each, and with what settings.
/usr/share/muxen-synapse/ template library, shipped read-only
├── anchor-light-night.lua
├── sensor-level-detection.lua
└── …
/etc/muxen/deploy.json per boat: which instances run, and how
"synapse": {
"fresh-water-port": { "template": "sensor-level-detection", … }
"fresh-water-stbd": { "template": "sensor-level-detection", … }
"custom": { "script": "<inline lua>", … }
}An instance takes its code one of two ways:
| Mode | Where the code lives | Effect of a package update |
|---|---|---|
template | the shipped .lua file, read at load time | the instance follows the improved template automatically |
script | inline Lua stored in deploy.json | frozen — a private copy, unaffected by package updates |
The same template can run several times under different instance ids with different settings, which is how one "sensor level detection" template covers four tanks.
The six shipped templates are described in The shipped automations.
Where it sits
Synapse owns no data and no device. It reads what other MUXEN daemons publish and writes commands the same daemons already accept.
| Talks to | Over | For |
|---|---|---|
Mosquitto on 127.0.0.1:1883 | MQTT | everything — there is no other interface |
muxen-boat, muxen-sensors, muxen-energy | app/sensor/<name>, device/<fc>/<inst>/… | boat data in, device commands out |
muxen-nmea2000 | nmea/… | speed, heading, engine RPM, GPS fix |
muxen-sextant (hard dependency, ≥ 2.2.0) | sextant/sun, …/moon, …/tides, …/magnetic | sunrise, dusk, tides, nearest harbour |
the config daemon | /etc/muxen/deploy.json | the instance list — synapse only ever reads it |
| a frontend (raken) | synapse/… topics + an nginx JSON index | listing automations, toggling them, answering popups |
It is not a UI: it publishes popup requests and a frontend renders them. It is not a data hub or a logger. It does not evaluate device-internal faults — that stays with muxen-alarms.
What ships
One Debian package, muxen-synapse, containing:
| Component | Path |
|---|---|
| The daemon | /usr/bin/muxen-synapsed |
| The operator CLI | /usr/bin/muxen-synapse-ctl |
| Template library + manifest | /usr/share/muxen-synapse/ |
| systemd unit | /usr/lib/systemd/system/muxen-synapse.service |
| nginx snippets | /etc/nginx/snippets/muxen-synapse-*.conf, muxen-ws-synapse.conf |
| Bash completion | /usr/share/bash-completion/completions/ |
Lua 5.5 is vendored and statically linked, so no system Lua runtime is needed on any target.
The safety properties
Three guarantees hold whatever an automation does:
- One automation cannot take down the others. Each runs in its own isolated Lua interpreter. A script's variables and functions are invisible to every other script, and tearing one down frees only that one.
- No automation can freeze the boat's automation engine. Every callback runs under a hard 50 ms CPU budget. A runaway loop is aborted, logged, and counted; it cannot stall the daemon.
- A broken automation stops itself. Five consecutive faults and the engine stops that instance rather than let it spin. Fixing the code and restarting recovers it automatically.
The scripting environment has no shell, no filesystem, no process control and no way to load code at runtime. How the engine runs automations covers all of this in operational detail.
Document map
| Document | Content |
|---|---|
| Getting started | install, start the service, run a first automation, verify it |
| The shipped automations | the six shipped automations, what each does and how to set it up |
| Deploying automations | declaring instances in deploy.json, config, enable/disable, persisted state |
| Writing an automation | authoring an automation in Lua |
| How the engine runs automations | how the engine runs automations: isolation, watchdog, faults, popups, edge cases |
| muxen-synapse-ctl — the operator CLI | muxen-synapse-ctl — the operator CLI |
| Troubleshooting | symptom → cause → check → fix, plus FAQ and Tips |
| Reference | CLI flags, environment, paths, units, limits, exit codes |
| Lua API reference | the synapse.* Lua binding reference — for script authors |
| MQTT interface | the synapse/ topic tree and payload shapes — for client implementers |
Glossary
| Term | Meaning |
|---|---|
| Template | A reusable .lua automation in the shipped library. Instantiated, never run directly. |
| Instance | A running automation declared in deploy.json, sourced from a template or from an inline script. |
| Instance id | The deploy.json key. Matches [a-zA-Z0-9-]+, and names the instance's synapse/<id> topic. |
| Engine | The muxen-synapsed daemon: resolves instances, loads them, runs and supervises them. |
| Hook | A function the engine calls on a script: onStart, onStop. |
| Popup | A confirmation request an automation raises, carried in its status until the crew answers. |
| Feedback | The crew's answer to a popup, returned over MQTT. |
| Snooze | A feedback choice that suppresses re-prompting for a set duration. |
| FSM | An optional small state machine a script uses for stateful behaviour, with per-state triggers. |
| Config | Read-only per-instance tuning from deploy.json. The script receives it. |
| State | The script-owned key/value store persisted in state.json. The script writes it. |
| Watchdog | The per-callback CPU-time cap that stops any script from blocking the engine. |
