Skip to main content
Version: 0.1

A daily counter reset with cron

This guide schedules a script that writes a tag once a day. It is for the engineer who wants a shift or day counter reset without a PLC change. The cron module (io.scadex.cron) runs five-field cron schedules, each in its own time zone, and keeps a record of every run.

Prerequisites​

  • The cron module installed and running; the dashboard shows Cron jobs in the Automation group while it is installed. See Cron.
  • A writable tag to reset, for example a memory tag Line1.Counter or a PLC counter the gateway may write.
  • A boolean memory tag for the failure flag, for example Alarms.CounterResetFailed, with an alarm on it if someone should be told (see Alarms).
  • The engineer role. Viewers can watch jobs and runs but not change or run them.

Steps​

1. Create the job​

  1. Open Automation, then Cron jobs, and create a new job. The form has four sections: Job, When it runs, What it does and When it goes wrong.

  2. Job: Name Reset day counter, Description as you like, Switched on left on.

  3. When it runs: choose Repeat daily with Time of day, 24-hour 00:00, or switch to a Cron expression and type 0 0 * * *. Set Time zone to the plant's zone, for example Europe/Brussels; the gateway handles daylight saving as Unix cron does. Leave Catch up off for now (see step 6).

  4. What it does: Action script, and in Script:

    const before = tag('Line1.Counter');
    writeTag('Line1.Counter', 0);
    console.log(`Counter was ${before} at reset`);
    return before;

    A cron script runs in the gateway's sandbox with tag(path) (the tag's live value, in engineering units), tags, writeTag(path, value), console.log and event (with job, trigger, jobId, runId and scheduledFor in its parameters), for up to 5 seconds of processing, one job at a time across the gateway. Its writes are applied after it finishes, in order, stopping at the first that fails. What it logs and returns is kept with the run. See Cron scripts.

  5. When it goes wrong: Failure tag Alarms.CounterResetFailed. The gateway writes true to it when a run fails and false again once one succeeds, only when that changes.

  6. Save.

The same job over the API, POST /api/v1/modules/io.scadex.cron/jobs:

curl -b cookies.txt -H "Origin: https://app.scadex.io" -H "Content-Type: application/json" \
https://app.scadex.io/api/v1/modules/io.scadex.cron/jobs -d '{
"name": "Reset day counter",
"description": "Zeroes the day counter at midnight",
"schedule": "0 0 * * *",
"timeZone": "Europe/Brussels",
"enabled": true,
"action": { "kind": "script", "script": "writeTag(\"Line1.Counter\", 0); return \"reset\";" },
"catchUp": false,
"failureTag": "Alarms.CounterResetFailed"
}'

An action is either {"kind":"script","script":"..."} or {"kind":"write","path":"Line1.Counter","value":0}, which writes one fixed value without a script. GET /api/v1/modules/io.scadex.cron/preview?schedule=0 0 * * *&timeZone=Europe/Brussels&count=5 checks a schedule and lists its next times; an unknown zone answers The gateway doesn't know the time zone "...".

2. Try it without writing​

In the form, Try it runs the script now and shows what it would write, its log and its return value. Nothing is written. For a write action it checks that the tag exists. Over the API, POST /api/v1/modules/io.scadex.cron/test takes the same body as a job and answers a run record marked as a trial, with the note "A trial: nothing was written."

3. Run it by hand​

Open the job and use its run action, or POST /api/v1/modules/io.scadex.cron/jobs/<id>/run. The gateway runs it at once, paused or not, and answers when it has finished (it waits up to 60 seconds). The run's trigger is manual and requestedBy is you; the write is audited under your account with cron-run-<id> as the correlation id. A scheduled run is audited as cron:Reset day counter.

Line1.Counter now reads 0.

4. Read the run record​

The job's panel lists its Runs; the page's header counts Running now, Failing and Runs, last 24 h, and shows the Next run. Open a run to see its Log, Returned value and Writes.

Over the API, GET /api/v1/modules/io.scadex.cron/runs?job=<id> lists runs newest first (nextBefore pages on), and GET /runs/<run id> returns one with its detail:

FieldMeaning
triggerschedule, manual or catch-up
scheduledForThe time the schedule named; null for a manual run
startedAt, finishedAt, durationMsWhen and how long
outcomerunning, succeeded, failed, skipped or missed
errorWhy it failed
detail.logs, detail.value, detail.writesThe console.log lines, the return value, each write with applied and any error

A run is failed when the script threw or hit a limit, a write was refused (no such tag, no permission, the driver refused it), or the gateway stopped mid-run. Runs are kept for 90 days, at most 2,000 per job.

5. See a failure reach the failure tag​

Edit the script so it writes a tag that does not exist, run it by hand: the outcome is failed, detail.writes[0].error says why, and Alarms.CounterResetFailed turns true. Fix the script and run again: succeeded, and the flag goes back to false.

6. What missed means​

Runs never queue. If midnight comes while the previous run is still going, that time is recorded as skipped. If midnight passes while the gateway is down, or the scheduler falls more than a turn behind, the job records a missed run when the gateway is back: one record for the whole stretch, with missedCount and missedFrom, and scheduledFor as the last time missed. Times before the job was created, resumed or rescheduled are never reported as missed, and a paused job is not blamed for the times it was paused.

With Catch up on (catchUp: true), the job also runs once after the downtime, with trigger catch-up, for the latest of the missed times. For a counter reset that is usually what you want: the counter should still be zeroed even if the gateway was restarting at midnight.

Where to go next​