View this page on MeshCore Docs.
Companion notification builder
Make a rule, preview it here, then copy the CLI commands or apply and test it over USB. The device needs firmware containing the new notification commands. The programmable alert engine is enabled on ESP32, nRF52 and RP2040 builds. Compact STM32WL Companions retain their existing alerts because the engine does not fit their 224 KiB application partition. Browser previews show one cycle; device tests use the configured repeat and stop policy. USB testing uses Binary Companion mode at 115200 baud.
Preview one cycle
Ready
Ready to play the melody
The melody plays on this device after a one-second audio warmup, then the timer and output indicators start together. No contact or room key is needed to preview an example. Sound set to off or inherit plays no melody here.
Timing here is a visual approximation. Firmware schedules outputs using millisecond timestamps without blocking radio work; loop and hardware latency can delay an edge. A haptic motor also takes time to start/stop.
Device commands
Notification DM or room post
The recipient must first grant your contact or room permission. Send the string as an ordinary DM or room post; it contains no GPIO action. Long patterns may need shortening to fit 159 characters for a DM, or 150 for a room post.
Try it on your device
No device connected
Save writes the generated commands in order and stops at the first device error; earlier successful settings remain saved. A test with a connection suffix selects that profile even over USB. Stop-on-connect still watches real subsequent connections. The silence-other-alerts option saves both the silent default and the selected channel rule. Deleting the selected rule does not delete that default. USB testing requires Chrome or Edge.
CLI reference
Settings apply immediately and survive reboot and filesystem-preserving
updates. They live in a separate checked file, /notify_prefs, with an atomic
replacement and backup. There are 12 rule slots. Existing alerts stay in use
until a rule or master control enables the new system. Unmatched messages keep
their existing alert behavior, subject to the master switches.
Master controls
get notify
set notify.enabled on
set notify.sound on
set notify.vibration on
set notify.led on
set notify.screen on
set notify.gpio off
get notify.gpio.pins
Each output has get notify.<output> and set notify.<output> on|off. Master
off cannot be overridden by a contact, channel or incoming notification DM.
set notify.enabled off disables custom rules and DM actions and returns to
the existing alert behavior. Supported-output bits in get notify are
vibration=1, sound=2, LED=4, screen=8 and GPIO=16. GPIO uses the same board pin
approval as repeater GPIO control and is inactive by default.
Rules
Targets are all, contact:<64 hexadecimal public-key digits>,
room:<64 hexadecimal room server public-key digits>, and
channel:<slot>. A channel's 32-digit key also works. Add @connected or
@disconnected to select the client state; no suffix matches either state.
set notify.vibration channel:3 50,300,40,20,500
set notify.sound channel:3 order:d=8,o=5,b=180:c,e,g,4c6
set notify.led channel:3 100,100,100,500
set notify.screen channel:3 on
set notify.gpio channel:3 22:50,300,50
set notify.repeat channel:3 forever
set notify.gap channel:3 2000
set notify.stop channel:3 button
get notify.vibration channel:3
notify.test channel:3
notify.stop
notify.delete channel:3
get notify.rules
get notify.rules 0
The GPIO example works only if pin 22 appears in get notify.gpio.pins.
Pulse lists have up to 12 positive durations of 1-60000 ms each. GPIO output is
active-high, inactive-low. Sound is one note at a time, not chords. RTTTL
requires name:d=<1|2|4|8|16|32>,o=<4..7>,b=<25..900>:notes; names use up to
12 ASCII letters/digits/underscores. Melodies are at most 63 characters and
60 seconds. Notes use a through g, p for rest, optional duration/octave,
# for sharps on a/c/d/f/g, and one . for a dotted duration. For example
16c#6 and 4g.5 are valid. Invalid melodies are rejected before the buzzer
library sees them. This ASCII format matches the installed NonBlockingRTTTL
driver's pitch table; musical staff symbols and polyphony are not supported.
For any rule output, off explicitly disables it and inherit removes that
field's override. Rules combine per field: shared all, shared state rule,
contact/channel rule, then contact/channel state rule. A matching rule replaces
the old message sound/vibration; unspecified outputs are off unless inherited
from a shared rule. An unspecified screen keeps its normal display policy.
screen on|off temporarily overrides that policy and restores it when the
alert ends. A selected LED pattern temporarily takes ownership from the usual
status heartbeat; the master LED switch also controls that heartbeat.
Finite repeats are 1..65535; forever loops until dismissed. Gap is
1..60000 ms after the longest output sequence. Stop modes are button,
connected, and never. Triple-press sound/vibration mute controls also
update their notification master switch where those buttons are supported.
Continuous alerts prevent MCU sleep so their timers can run.
Contact and room permission for notification strings
On the recipient, replace PUBLIC_KEY with the sender's complete public key:
set notify.remote contact:PUBLIC_KEY on
get notify.remote contact:PUBLIC_KEY
set notify.remote contact:PUBLIC_KEY off
set notify.remote room:ROOM_PUBLIC_KEY on
Permission defaults to off, is saved per contact or room key, and cannot be granted
to all, channels or connection-state variants. The identity comes from the
authenticated received DM, not a key written inside its text. The permission
alone does not replace the contact's normal message alerts. A trusted room's
forwarded !notify posts use the room server's complete key for permission,
not the post author's four-byte prefix. Trusting a room allows its posters to
send notifications; trusting a chat contact alone does not authorize their
posts forwarded by an untrusted room. Both plain DMs and signed room posts
pass through the same validation and 15-second playback cap.
The allowed sender can send:
!notify vibration=50,300,40,20,500 led=100,100,100,500 sound=order:d=8,o=5,b=180:c,e,g screen=on repeat=forever gap=2000
Allowed fields are vibration, sound, led, screen, repeat and gap.
The whole notification string is validated before any output changes.
Unknown/duplicate fields, GPIO, stop modes, permission changes and inherit
are rejected. The command cannot change saved rules. Button dismissal is
always allowed, notify.stop works, and playback stops at 15000 ms even when
the requested pattern or repeat count is longer. Unapproved or invalid
notification strings remain ordinary message text. Repeated delivery of the
same recently received post or DM does not restart its playback deadline.
Channel messages cannot execute
notification strings. Receiver master switches apply even while connected.
Examples
- Find my node: use an allowed sender to DM a short sound/LED pattern, or
use authorized remote CLI to run a saved
notify.test all@disconnectedrule. A local saved find rule can repeat until a companion client connects. A notification DM always ends within 15 seconds. - Food truck pager: use a private order channel rule that repeats until the customer presses the button, or let the customer grant the order desk's contact permission and send the notification DM when the order is ready.
- VIP chat: match the VIP's full public key and set a distinctive melody and vibration. Add a connected profile with sound/vibration off if the phone should handle notifications while attached. Permission to send notification strings is separate from a VIP's ordinary message rule.
Only channel 9 alerts; all other channels silent
This example makes message alerts silent by default, then plays one short melody for channel 9. It works both with and without a connected companion client and requires a device with a buzzer. Messages still arrive normally; this changes the node's alerts, not the phone app's notification settings. Use the Only channel 9 button above to load this setup into the builder. You can change the channel slot or alert pattern before copying or saving. Uncheck Silence other message alerts to generate only the selected rule; this does not remove a silent default already saved on the node.
channel:9 means the firmware's zero-based slot 9 (the tenth slot), not
a channel named ch9. Configure that slot before running these commands.
The rule follows its saved channel key; recreate it if you replace the channel
in that slot.
Start with no conflicting custom rules. Use get notify.rules, then
get notify.rules <rule-slot> to inspect existing selectors. Remove only
unwanted rules with notify.delete <selector>: existing state-specific and
contact/channel rules can override the silent default below.
set notify.enabled on
set notify.vibration all off
set notify.sound all off
set notify.led all off
set notify.screen all off
set notify.gpio all off
set notify.repeat all 1
set notify.gap all 500
set notify.stop all button
set notify.sound on
set notify.sound channel:9 ch9:d=8,o=5,b=180:c,e,g
Keep the sound master on: set notify.sound all off silences the default
rule, while set notify.sound off would also block the channel 9 exception.
The other outputs remain silent, including screen wake-ups for messages.
To add vibration for channel 9 on a device with a vibration motor:
set notify.vibration on
set notify.vibration channel:9 100,100,300
Test the saved exception with notify.test channel:9; stop it with
notify.stop. Send a message on another configured channel to verify that
it stays quiet.
Scope: there is no channels-only wildcard: all also silences ordinary
DM and room-message alerts unless a more specific rule enables them.
Previously authorized contact/room !notify strings can still request alerts.
If those should stay quiet too, revoke their permission with
set notify.remote contact:PUBLIC_KEY off or
set notify.remote room:ROOM_PUBLIC_KEY off, using the full sender/server key.