How Webhook Event Notifications Are Triggered for Motion Detection and Recording in AtomCam Tools

AtomCam Tools triggers webhook event notifications by piping specially-formatted log lines to a FIFO file (/var/run/atomapp), where an awk script parses motion detection, recording, and timelapse events and POSTs JSON payloads to a configured URL via curl.

The mnakada/atomcam_tools repository implements a lightweight, log-driven notification system that keeps the core camera firmware decoupled from networking logic. Instead of direct HTTP calls from C components, the system writes tagged messages to a named pipe and relies on overlay_rootfs/scripts/webhook.sh to dispatch alarmEvent, recordEvent, and timelapseEvent notifications when enabled in the configuration.

Motion Detection Webhook Notifications

Motion detection events originate from either the hardware motion sensor or the onboard AI algorithm. When triggered, these components write specific log patterns to the FIFO that webhook.sh monitors.

Log Pattern Matching

The awk script in overlay_rootfs/scripts/webhook.sh listens for three distinct regex patterns to identify motion alarms:

/\[aiAlgo\] start/ { 
    if(ENV["WEBHOOK_ALARM_EVENT"] == "on") Post("alarmEvent"); 
}
/alarm_event_handle.*timestamp/ { 
    if(ENV["WEBHOOK_ALARM_EVENT"] == "on") Post("alarmEvent"); 
}
/(alarm_event_handle).*== readly to alarm ==/ { 
    if(ENV["WEBHOOK_ALARM_EVENT"] == "on") Post("alarmEvent"); 
}

When any pattern matches and WEBHOOK_ALARM_EVENT is set to "on", the script invokes the internal Post() function.

JSON Payload Construction

The Post() function constructs a minimal JSON object and dispatches it via curl:

system("curl -X POST -m 3 -H 'Content-Type: application/json' \
       -d '{\"type\":\"alarmEvent\", \"device\":\"" HOSTNAME "\"}' \
       " INSECURE_FLAG ENV["WEBHOOK_URL"] " > /dev/null 2>&1")

The resulting payload sent to the webhook URL is:

{"type":"alarmEvent", "device":"my-atomcam"}

Recording Finish Webhook Notifications

Regular recordings generate notifications through a different path. When a one-minute recording segment completes, the atom_patch/bin/mv helper handles file movement from temporary storage to /media/mmc/record/.

Trigger Condition in the Move Helper

After successfully moving the MP4 file, the mv script checks environment variables before dispatching:

if [ "$WEBHOOK_URL" != "" ] && [ "$WEBHOOK_RECORD_EVENT" = "on" ]; then
    LD_LIBRARY_PATH=/tmp/system/lib:/tmp/system/usr/lib \
    /tmp/system/lib/ld.so.1 /tmp/system/bin/curl -X POST -m 3 \
    -H "Content-Type: application/json" \
    -d "{\"type\":\"recordEvent\", \"device\":\"${HOSTNAME}\"${STORAGE}}" \
    $INSECURE_FLAG $WEBHOOK_URL > /dev/null 2>&1
fi

The STORAGE variable appends optional file location metadata (sdcardFile or cifsFile) to the payload, allowing the receiver to locate the saved video immediately.

Timelapse Webhook Notifications

Timelapse events are generated directly from the C library libcallback/timelapse.c. The code prints specially-formatted strings to stdout that travel through the same FIFO pipeline.

Event Emission in timelapse.c

The timelapse module emits status updates using printf statements:

printf("[webhook] time_lapse_event %s %d/%d %d\n",
       ProcessingInfo.mp4File,
       ProcessingInfo.count,
       ProcessingInfo.numOfTimes,
       ScheduleNo);

printf("[webhook] time_lapse_finish %s %d/%d %d\n", ...);

awk Processing

In webhook.sh, lines 88-91 capture these tags:

/\[webhook\] time_lapse_event/ {
    if(ENV["WEBHOOK_TIMELAPSE_EVENT"] == "on") 
        Post("timelapseEvent", "\"" $0 "\"");
}

The payload includes the raw log line containing the file path and progress counters, enabling external systems to track timelapse completion status.

Configuration and Enablement

All webhook behavior is controlled via environment variables stored in /tmp/hack.ini. The Web UI (web/source/vue/Setting.vue) exposes toggles for each event type:

<SettingSwitch i18n="event.webhook.alarm" v-model="config.WEBHOOK_ALARM_EVENT" />
<SettingSwitch i18n="event.webhook.recordingSave" v-model="config.WEBHOOK_RECORD_EVENT" />

When a user enables a switch, the corresponding WEBHOOK_ALARM_EVENT, WEBHOOK_RECORD_EVENT, or WEBHOOK_TIMELAPSE_EVENT variable is set to "on". The webhook.sh script reads these variables at startup and applies them to its pattern matching logic.

Summary

  • Motion detection triggers alarmEvent webhooks when alarm_event_handle or [aiAlgo] start patterns appear in the FIFO and WEBHOOK_ALARM_EVENT is enabled.
  • Recording completion triggers recordEvent webhooks via the atom_patch/bin/mv helper when WEBHOOK_RECORD_EVENT is set to "on".
  • Timelapse progress triggers timelapseEvent webhooks from libcallback/timelapse.c when WEBHOOK_TIMELAPSE_EVENT is active.
  • All notifications are dispatched by overlay_rootfs/scripts/webhook.sh using curl to the URL defined in WEBHOOK_URL.
  • Configuration persists in hack.ini and is managed through the Vue-based Web UI settings panel.

Frequently Asked Questions

What URL format does AtomCam Tools expect for webhooks?

The system expects a standard HTTP or HTTPS URL assigned to the WEBHOOK_URL environment variable. The curl command in webhook.sh appends this URL directly to the POST request without additional path manipulation, so the endpoint should be prepared to receive POST requests at the root of the provided address.

Can I receive the actual file path in the recording webhook?

Yes. When WEBHOOK_RECORD_EVENT is enabled, the atom_patch/bin/mv helper appends a STORAGE variable to the JSON payload containing either "sdcardFile":"/path/to/file" or "cifsFile":"/path/to/file" depending on where the MP4 was saved. Parse the recordEvent payload to extract the location.

Why does the motion detection use three different regex patterns?

The three patterns—alarm_event_handle.*timestamp, alarm_event_handle.*== readly to alarm ==, and \[aiAlgo\] start—cover different firmware paths. The hardware motion detector and AI algorithm write slightly different log formats to /var/run/atomapp. The awk script in webhook.sh watches for all three to ensure reliable detection regardless of which subsystem triggered the alarm.

Is there a way to test webhooks without waiting for actual motion?

You can manually write to the FIFO pipe to simulate events. As root, execute echo "alarm_event_handle test timestamp" > /var/run/atomapp while webhook.sh is running with WEBHOOK_ALARM_EVENT=on. This forces the awk script to match the pattern and dispatch a test alarmEvent to your configured URL.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →