The Automation Engine
Mesh radios generate events: nodes come online, batteries drain, messages arrive, positions change. The automation engine lets users create rules that respond to these events without manual intervention.
Architecture
The engine follows a simple trigger-condition-action model:
Trigger (event occurs)
→ Condition (optional filter)
→ Action (response)
Triggers
| Trigger | Fires when |
|---|---|
nodeOnline | A node appears on the mesh |
nodeOffline | A node stops responding |
batteryLow | Battery drops below threshold |
messageReceived | Any message arrives on a channel |
geofence | A node enters or exits a geographic area |
silentNode | A specific node has not been heard from in N minutes |
Actions
Actions include sending messages, playing sounds, triggering notifications, and toggling device settings. Each action can include template variables that are resolved at execution time:
"Node {{node_name}} battery at {{battery_level}}%"
Variables are validated at edit time with syntax highlighting. Invalid variables show inline errors before the automation is saved.
Battery Hysteresis
The batteryLow trigger needs hysteresis to avoid notification spam. Without it, a battery hovering around 20% would trigger repeatedly as the reading fluctuates between 19% and 21%.
The solution: trigger only on threshold crossing, not threshold value.
Battery: 45% → 30% → 25% → 19% ← triggers (crossed 20%)
Battery: 19% → 21% → 19% ← does NOT trigger again
Battery: 19% → 25% → 19% ← triggers again (crossed back above, then below)
The engine tracks the last-known state per node. A batteryLow event fires only when the previous reading was above the threshold and the current reading is below it. This eliminates oscillation noise completely.
Geofence Triggers
Geofence automations define a center point (latitude, longitude) and radius in meters. The engine calculates the Haversine distance from the node’s last reported position:
Where is Earth’s radius, is latitude, and is longitude.
The trigger fires on state transition (inside → outside or outside → inside), not on every position update. This prevents rapid-fire triggers when a node moves along the fence boundary.
Variable System
Action messages support dynamic variables that are resolved from the triggering event context. Each trigger type exposes different variables:
- All triggers:
{{node_name}},{{node_id}},{{timestamp}} - batteryLow:
{{battery_level}},{{voltage}} - messageReceived:
{{message_text}},{{channel_name}},{{sender_name}} - geofence:
{{latitude}},{{longitude}},{{distance}}
Variables are inserted via chip UI — users tap to insert rather than typing the {{}} syntax manually. This prevents typos and ensures only valid variables are used.
State Persistence
Automations are stored locally with optimistic UI updates. The engine initializes at app startup and subscribes to the protocol service’s event streams. No cloud dependency — automations run entirely on-device, processing mesh events in real time.