mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-20 12:41:58 +00:00
243 lines
14 KiB
Markdown
243 lines
14 KiB
Markdown
# 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.
|
|
|
|
<div class="notification-builder" data-notification-builder>
|
|
<div class="notification-examples">
|
|
<button type="button" data-example="find">Find my node</button>
|
|
<button type="button" data-example="food">Food order ready</button>
|
|
<button type="button" data-example="vip">VIP chat</button>
|
|
</div>
|
|
<form data-role="form" onsubmit="return false">
|
|
<section class="notification-card">
|
|
<h2>Who should trigger the alert?</h2>
|
|
<div class="notification-grid">
|
|
<label>Messages from<select name="kind"><option value="all">All contacts and channels</option><option value="contact">One contact</option><option value="room">One room server</option><option value="channel">One channel</option></select></label>
|
|
<label>Contact/room key or channel slot<input name="id" autocomplete="off" placeholder="Full contact/room public key, or channel slot such as 3"></label>
|
|
<label>Companion client status<select name="when"><option value="any">Connected or disconnected</option><option value="connected">Connected</option><option value="disconnected">Disconnected</option></select></label>
|
|
</div>
|
|
<p>Connected means an active phone/app, USB, WiFi, Ethernet or serial
|
|
companion client. It selects a message rule; connecting or disconnecting
|
|
alone does not create an alert. Contact matching uses the full public key.
|
|
Channel slots resolve to the channel's key when the rule is saved.</p>
|
|
</section>
|
|
<section class="notification-card">
|
|
<h2>What should the device do?</h2>
|
|
<div class="notification-grid">
|
|
<label>Vibration pattern<input name="vibration" value="50,300,40,20,500" spellcheck="false"><small>Millisecond on/off durations, or off / inherit</small></label>
|
|
<label>LED pattern<input name="led" value="100,100,100,500" spellcheck="false"><small>Starts on, alternates off/on, finishes off</small></label>
|
|
<label class="notification-wide">Sound melody<input name="sound" value="order:d=8,o=5,b=180:c,e,g,4c6" spellcheck="false"><small>RTTTL: note letters a-g, # for sharp, p for rest; off / inherit also work</small></label>
|
|
<label>Screen<select name="screen"><option value="inherit">Use normal screen policy</option><option value="on">On during alert</option><option value="off">Off during alert</option></select></label>
|
|
<label>GPIO output<input name="gpio" value="off" spellcheck="false"><small>off / inherit, or an approved pin and pattern: 22:50,300,50</small></label>
|
|
</div>
|
|
<p><code>50,300,40,20,500</code> means on for 50 ms, off for 300 ms,
|
|
on for 40 ms, off for 20 ms, then on for 500 ms. A rule controls only
|
|
outputs physically supported by its firmware. The USB connection reports
|
|
the supported outputs and approved GPIO pins before applying anything.</p>
|
|
</section>
|
|
<section class="notification-card">
|
|
<h2>Repeating and stopping</h2>
|
|
<div class="notification-grid">
|
|
<label>Repeat count<input name="repeat" value="1"><small>A number, or forever</small></label>
|
|
<label>Gap between cycles (ms)<input name="gap" value="500" inputmode="numeric"></label>
|
|
<label>Stop alert<select name="stop"><option value="button">Button</option><option value="connected">Node connected</option><option value="never">Never automatically dismiss</option></select></label>
|
|
</div>
|
|
<p>Node connected stops an active alert when a companion client connects.
|
|
Never disables button/connection dismissal; a finite repeat count still
|
|
finishes. <code>notify.stop</code> always stops playback. A new matching
|
|
message replaces the current alert.</p>
|
|
</section>
|
|
<section class="notification-card">
|
|
<h2>Allow notification strings from this contact or room</h2>
|
|
<label>Permission<select name="remote"><option value="inherit">Leave permission unchanged</option><option value="on">Allow this contact or room</option><option value="off">Revoke this contact or room</option></select></label>
|
|
<p>Only applies to a contact or room server's full public key, without a connection
|
|
condition. An allowed contact can DM the notification string below, or
|
|
it can be posted in an allowed room. Trusting a room allows its posters
|
|
to send alerts through that server.
|
|
GPIO, stop-policy and permission changes are forbidden in DMs or room posts. The device
|
|
stops playback after at most 15 seconds, including infinite repeats.
|
|
Incoming strings do not save settings and obey the recipient's master switches.</p>
|
|
</section>
|
|
</form>
|
|
<p data-role="error" class="notification-error" role="alert" aria-live="polite"></p>
|
|
<section class="notification-card">
|
|
<h2>Preview one cycle</h2>
|
|
<div class="notification-indicators"><span data-indicator="vibration" data-on="false">Vibration</span><span data-indicator="led" data-on="false">LED</span><span data-indicator="gpio" data-on="false">GPIO</span><span data-indicator="screen" data-on="false">Screen</span></div>
|
|
<p data-role="preview-time" aria-live="off">Ready</p>
|
|
<p data-role="preview-sound" aria-live="polite">Ready to play the melody</p>
|
|
<audio data-role="preview-audio" preload="none"></audio>
|
|
<button type="button" data-action="preview">Preview with sound</button>
|
|
<button type="button" data-action="preview-stop">Stop preview</button>
|
|
<p>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.</p>
|
|
<p>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.</p>
|
|
</section>
|
|
<section class="notification-card">
|
|
<h2>Device commands</h2>
|
|
<pre><code data-role="commands"></code></pre>
|
|
<button type="button" data-action="copy">Copy commands</button><span data-role="copy-status" aria-live="polite"></span>
|
|
<h3>Notification DM or room post</h3>
|
|
<pre><code data-role="dm"></code></pre>
|
|
<p>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.</p>
|
|
</section>
|
|
<section class="notification-card">
|
|
<h2>Try it on your device</h2>
|
|
<p data-role="device-status" aria-live="polite">No device connected</p>
|
|
<div class="notification-buttons">
|
|
<button type="button" data-action="connect">Connect USB</button>
|
|
<button type="button" data-action="disconnect">Disconnect USB</button>
|
|
<button type="button" data-action="apply">Save rule</button>
|
|
<button type="button" data-action="apply-test">Save and test</button>
|
|
<button type="button" data-action="test">Test saved rule</button>
|
|
<button type="button" data-action="stop">Stop device alert</button>
|
|
<button type="button" data-action="delete">Delete selected rule</button>
|
|
</div>
|
|
<p>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. USB testing requires Chrome or Edge.</p>
|
|
<pre data-role="device-log" class="notification-log" aria-live="polite"></pre>
|
|
</section>
|
|
</div>
|
|
|
|
## 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
|
|
|
|
```text
|
|
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.
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
!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@disconnected` rule.
|
|
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.
|