Skip to content

cap_scheduler — Scheduling

Source: cap_scheduler.c · Header: cap_scheduler.h

cap_scheduler is the time-trigger center for ESP-Claw. It is responsible for generating events at specified points in time and pushing them to the claw_event_router. The scheduler itself does not execute specific business logic (like sending messages or calling tools); instead, it triggers subsequent automation rules by publishing events.

This “separation of scheduling and execution” design allows scheduled tasks to reuse all action capabilities of the Event Router (run_agent, call_cap, run_script, etc.).

Each schedule item defines “when” to publish “what kind of event”. Key fields include:

  • id: Unique identifier.
  • kind: Schedule type, supports once (one-time), interval (interval-based), cron (standard 5-field Cron expression).
  • enabled: Whether it is enabled.
  • event_type: The type of event to publish (corresponds to match.event_type in routing rules).
  • event_key: The event key (corresponds to match.event_key in routing rules).
  • payload_json: Accompanying JSON data.

The scheduler manages two persisted data sets:

  1. Definition file (schedules.json): Stores all schedule item configurations.
  2. State file (derived automatically as schedules_path + ".state", e.g. schedules.json.state): Stores runtime dynamic information, such as last_fire_ms (last triggered time) and run_count (number of runs). This ensures that the device can correctly resume progress after a reboot without losing or repeating tasks.

After each scheduler_reload (and when loading on startup), the scheduler fills missing fields in each entry of schedules.json using default rules.

Tool IDFunctionInput Parameters
scheduler_listList all schedule items and their running status(None)
scheduler_getGet details for one schedule itemid
scheduler_addAdd a new schedule itemschedule_json (string)
scheduler_updateUpdate an existing schedule itemschedule_json (string)
scheduler_removeRemove a schedule itemid
scheduler_enableEnable a specific schedule itemid
scheduler_disableDisable a specific schedule itemid
scheduler_pausePause a specific schedule itemid
scheduler_resumeResume a specific schedule itemid
scheduler_trigger_nowTrigger a schedule immediately (does not affect subsequent plans)id
scheduler_reloadReload configuration from disk(None)

Where:

  • schedule_json (string) means {"schedule_json":"<JSON string>"}. Here schedule_json itself is a string value (escaped), not a nested object.
  • id means {"id":"..."}.

A typical entry in schedules.json:

{
  "id": "morning_reminder",
  "kind": "cron",
  "cron_expr": "0 7 * * *",
  "enabled": true,
  "event_type": "schedule",
  "event_key": "reminder",
  "text": "Good morning! It's another vibrant day, remember to drink water meow."
}

Add a corresponding rule in router_rules.json to send this schedule event to IM:

{
  "id": "handle_morning_reminder",
  "match": {
    "event_type": "schedule",
    "event_key": "reminder"
  },
  "actions": [
    {
      "type": "send_message",
      "input": {
        "channel": "telegram",
        "chat_id": "YOUR_CHAT_ID",
        "message": "{{event.text}}"
      }
    }
  ]
}

cap_scheduler relies on the accuracy of the system time.

  • For cron and once tasks, they will only be triggered after SNTP synchronization is successful.
  • For interval tasks, if start_at or end_at are not configured, they do not rely on external time and start timing upon power-on.
  • cron matching is based on the device’s current local time (localtime_r).

After the first successful SNTP sync in basic_demo (had_valid_time == false → valid time), cap_scheduler_handle_time_sync() rebases the scheduler: if the device had already been counting from a wrong clock since boot, the first accurate system time adjusts each task’s reference points so triggers are not duplicated or skipped.

Initialize at the application layer:

ESP_RETURN_ON_ERROR(cap_scheduler_init(&(cap_scheduler_config_t) {
    .schedules_path = "/fatfs/scheduler/schedules.json",
    .tick_ms = 1000,              // Check interval (ms)
    .max_items = 32,              // Max schedule items
    .task_stack_size = 6144,      // Scheduler task stack size
    .task_priority = 5,           // Scheduler task priority
    .task_core = tskNO_AFFINITY,  // Core affinity
    .publish_event = claw_event_router_publish, // Bind publishing interface
    .persist_after_fire = true,   // Persist runtime state after a fire
}), TAG, "Failed to init scheduler");

// cap_scheduler_start() is called after claw_event_router_start()
cap_scheduler_start();