Appearance
The shipped automations
Six automations ship with muxen-synapse. They cover the jobs that recur on every boat: showing the right navigation lights at the right time, protecting a pump from running dry, dimming the cabin lighting as night falls, and asking before starting the watermaker.
None of them run until you deploy them. Each is a template: you create one or more instances of it in the boat's configuration, choose which button or output it drives, and it starts. The same template can run several times — one "sensor level detection" instance per tank, for example.
What they are
| Template | What it does on the boat |
|---|---|
anchor-light-night | Turns the anchor light on at night while you are lying at anchor, off at daybreak or once you get underway. |
masthead-light-motoring | Turns the masthead (steaming) light on when an engine starts and off when the engines stop. |
nav-lights-pilote | Makes the navigation lights follow the pilote (helm) button — nav on, lights on. |
dimming-lights | Dims a group of lights step by step as night falls and brightens them again at dawn. |
sensor-level-detection | Switches a circuit off (or on) when a tank or sensor value crosses a threshold — dry-run protection, over-fill cutoff, auto-start a transfer pump. |
watermaker-start-prompt | Asks the crew whether to start the watermaker when fresh water is low and the boat is well clear of harbour. |
Two behaviours are worth understanding before you deploy any of the light automations.
They act on the change, not continuously. An automation switches the light at the moment the condition changes — dusk falls, the engine starts, the pilote goes on — and then hands control back to you. If you flip the light afterwards, the automation does not fight you; it acts again only at the next transition.
The lights are driven through their keypad buttons. On these boats the nav, anchor and steaming lights are wired to keypad buttons rather than to a lighting controller, so the automations press the physical button. A press toggles, so each automation first reads the button's LED and presses only if the LED disagrees with what it wants. If the LED state is unknown or stale, it does not press at all — the safe choice.
anchor-light-night — anchor light at night, at anchor
An anchored vessel must show an all-round white anchor light between dusk and dawn. This automation presses the anchor-light button on when it is night and the boat is essentially stopped, and off at daybreak or once the boat gets underway.
Hysteresis between the two speed thresholds stops the light chattering as the boat sails around its anchor and the speed over ground wobbles: you are "at anchor" below anchor_kn and "underway" above underway_kn. Keep underway_kn above anchor_kn.
Night comes from muxen-sextant. It is tri-state — night, day, or unknown — and an unknown answer (no GPS fix, no sextant) never switches the light on by itself.
| Config key | Type | Default | Meaning |
|---|---|---|---|
light_button | button | required | Anchor-light keypad button |
anchor_kn | number | 1.0 | At anchor below this speed (kn), range 0–20 |
underway_kn | number | 2.0 | Underway above this speed (kn), range 0–20 |
nav_topic | string | nmea/navigation | Navigation report topic |
stale_sec | integer | 5 | Treat speed data older than this (s) as unknown, range 2–120 |
Needs muxen-sextant and muxen-nmea2000 (speed over ground from nmea/navigation).
masthead-light-motoring — masthead light while motoring
A vessel under engine power must show its masthead (steaming) light. This automation presses the light's button on when an engine starts — RPM rises above rpm_on — and off when all engines stop.
Engine speed comes from nmea/motor, which is published only while a motor is active and is not retained. "No fresh report" therefore means "not motoring", detected by a staleness watchdog rather than by waiting for an RPM-zero message that never arrives. On enable the light is set once to the correct state.
| Config key | Type | Default | Meaning |
|---|---|---|---|
light_button | button | required | Masthead / steaming-light keypad button |
motor_topic | string | nmea/motor | Motor report topic |
rpm_on | number | 50 | A motor counts as running above this RPM, range 0–6000 |
stale_sec | integer | 10 | Treat motor data older than this (s) as stopped, range 5–120 |
Needs muxen-nmea2000.
nav-lights-pilote — navigation lights follow the pilote
On these boats "navigation is on" is shown by the pilote (helm) button's LED going green. This automation mirrors that: pilote on, nav lights on; pilote off, nav lights off.
It reads the pilote LED from the keypad's own state topic — green codes count as on, exactly as the boat's header interface reads it — and presses the nav-lights button to follow.
| Config key | Type | Default | Meaning |
|---|---|---|---|
pilote_button | button | required | Pilote (navigation) button to read |
light_button | button | required | Navigation-lights button to drive |
Needs keypad state on device/0/<inst>/state. No other daemon.
dimming-lights — brightness follows the sky
Brightest by day, progressively dimmer as night falls, back up again at dawn — so cabin and deck lighting never dazzles at night nor looks murky by day, without anyone touching a dimmer.
Each twilight moment sets an absolute darkness level, 0 (full day) to 4 (deep night). Target brightness is 100 − level × step, never below min_dimming. With the defaults that walks down 100 % → 85 % → 70 % → 55 % → 40 % as night falls, and mirrors back up through dawn. Every change is ramped one point per second, so brightness glides rather than jumps. On start the level is seeded from the sun's current altitude, so an automation enabled at midnight comes up correctly dimmed.
Only the dimming is driven — on/off stays with whoever controls the lights. Each device clamps the requested level to its own configured safe range before applying it, so no value this automation asks for can drive a fixture outside its limits. On stop, brightness is restored to 100 %.
| Config key | Type | Default | Meaning |
|---|---|---|---|
outputs | outputs | required | The lights to dim (an array of output channels) |
step | integer | 15 | Brightness drop per twilight stage (%), range 1–100 |
min_dimming | integer | 20 | Floor brightness at deepest night (%), range 1–100 |
Needs muxen-boat ≥ 9.4.0 (the dimming field) and muxen-sextant.
sensor-level-detection — act on a threshold
Watches one numeric variable — a tank level, a temperature, anything published on app/sensor/<name> — and switches one circuit when the value crosses a threshold, by clicking a keypad button.
The classic uses are dry-run protection (cut the fresh-water pump when the tank runs low), over-level protection (cut a fill pump when a tank is full), and the inverse: auto-starting a transfer or fill pump when a tank runs low. action chooses which way the circuit is switched.
Either threshold may be left unset — set only lowLevel for a pure low-level cutoff, only highLevel for a high-level cutoff, or both (keep lowLevel below highLevel). At least one is required: an instance with neither faults and stops itself.
Two behaviours matter in practice. It acts on the crossing, not on every message, so a 1 Hz variable does not re-tap the button every second. And a stale value never triggers: freshness is measured against the payload's own publish time, so a retained reading replayed from a dead or idle sensor reads as unknown and is skipped, never misread as a live "tank empty".
| Config key | Type | Default | Meaning |
|---|---|---|---|
button | button | required | Keypad button to click |
variable | string | required | Variable name to watch (subscribes app/sensor/<name>) |
lowLevel | number | unset | Trigger below this value |
highLevel | number | unset | Trigger above this value |
action | enum off / on | off | Switch the circuit off or on when a threshold is reached |
Needs the named app/sensor/<name> publisher and keypad state on device/0/<inst>/state.
watermaker-start-prompt — ask before making water
Watches one or two fresh-water tanks. When either drops below low_level litres and the boat is at least harbour_nm nautical miles from the nearest harbour, a popup asks the crew whether to start the watermaker.
It never starts on its own — the crew must confirm. They can instead snooze the reminder for an hour or a day, and it will come back when the snooze expires if the water is still low.
The offshore condition is not cosmetic: a reverse-osmosis membrane fouls if it is run on harbour or marina water. Distance comes from muxen-sextant's tide stations (the nearest station is treated as the nearest harbour), falling back to a live 3D GPS fix once you are beyond the tide search radius.
| Config key | Type | Default | Meaning |
|---|---|---|---|
tank_a | string | required | First fresh-water tank variable, e.g. fresh-water-portside |
tank_b | string | unset | Second tank variable (optional — leave unset to watch one tank) |
low_level | number | 50 | Prompt when either tank is below this (L), range 0–5000 |
harbour_nm | number | 10 | Minimum distance from harbour to prompt (nm), range 0.1–200 |
instance | integer | 0 | Watermaker device instance, range 0–63 |
popup_description | string | see below | Popup message shown to the crew, in Markdown |
The default popup text is "Fresh water is low and you are offshore. Start the watermaker to refill the tanks?" — tune it per boat if you want different wording.
Needs muxen-sextant (tide stations) and muxen-nmea2000 ≥ 3.5.0 (nmea/navigation GPS fix).
Deploying one
Each template's config keys are the config object of its instance in /etc/muxen/deploy.json:
json
{
"synapse": {
"anchor-light": {
"template": "anchor-light-night",
"name": "Anchor light",
"config": {
"light_button": { "deviceId": 0, "index": 5 },
"anchor_kn": 1.0,
"underway_kn": 2.0
}
}
}
}A button or output value is an IOChannel — { deviceId, index }, where deviceId = functionCode × 64 + instance and index is the 0-based channel on that device. In raken these are picked from a device list rather than typed. outputs is an array of them.
Any key you omit falls back to the template's default; a value outside a declared range is clamped and logged rather than rejected. See Deploying automations for the full instance model, and Reference for the config field types.
Discovering them programmatically
A frontend does not read this chapter — it reads the generated manifest. The template library is served read-only over nginx:
| URL | Content |
|---|---|
/synapse/templates/ | JSON directory listing of the library |
/synapse/templates/index.json | Rich manifest: name, description, version and the full config schema of every template |
/synapse/templates/<name>.lua | The template source, used to seed an inline copy |
index.json is generated at package build time by loading each template in a stub environment and capturing its declared metadata, so it can never drift from the code. It is not regenerated at runtime: a template hand-copied into /usr/share/muxen-synapse will not appear in the manifest until the package is rebuilt.
