Skip to main content

Server script API

A server script is one call of defineScript({ … }) in TypeScript or JavaScript. The editor completes these names and checks the types before it saves. For how to create and run a script, see Server scripts.

defineScript​

defineScript({
tags: ["Line1.P1", { path: "Line1.Breaker", on: "any" }],
every: "10s",
at: "0 6 * * *",
alarms: { tags: ["Boiler?.*"], minPriority: "high" },
when: { expr: "ctx.value('Line1.P1') > 80", forMs: 2000 },
timezone: "Europe/Istanbul",
onStart(ctx) {},
onChange(ctx, path, ev) {},
onTimer(ctx) {},
onSchedule(ctx, ev) {},
onAlarm(ctx, alarm) {},
onWhen(ctx, ev) {},
onStop(ctx) {},
});

A script calls defineScript once. Several triggers can be combined; the handlers run one after another, never at the same time. Every handler may be async; an error or a rejected promise counts as an error of the script.

Triggers​

OptionFormCalls
tagsList of paths; an entry may be { path, on, deadband } with on = "value" (default), "quality" or "any"onChange
everyDuration: fixed delay after the previous run ends. { rate: "10s" }: fixed rate; a tick while the previous run is busy is skipped. { delay: "10s" } is the same as the plain form. At least 50 ms.onTimer
atCron with 5 fields (minute hour day month weekday), an ISO date and time that runs once (2026-12-31T23:59:00, optionally with Z or +03:00), or a list of themonSchedule
alarms{ tags, states, minPriority }: path patterns with * and ? (empty: all alarms); states "came", "went", "acked" (empty: all three); minPriority "low", "medium", "high", "critical" or 0–3onAlarm
whenOne or a list of { expr, forMs, edge, name }: expr as a text or a function of ctx; forMs how long the new state must last; edge "rising" (default), "falling" or "both"onWhen
timezoneTime zone for at; the Time zone (cron) setting of the script takes precedence; empty: the server's local time—

Durations are written as "500ms", "10s", "1m", "1h" or a number of milliseconds.

A when condition is evaluated only when one of the tags changes (and when forMs has passed): list the signals the expression reads in tags. When the first values have arrived (at the latest after 5 seconds), the starting state is set without an edge, so a restart does not trigger a false edge.

Handlers and events​

HandlerCalledEvent
onStart(ctx)When the script starts—
onChange(ctx, path, ev)A signal in tags changesev.prev, ev.cur: { value, quality, ts } or null; ev.initial: the first value after the start; ev.qualityOnly: only the quality changed; ev.missed: changes merged while the script was busy
onTimer(ctx)every elapses—
onSchedule(ctx, ev)at is dueev.at: the entry that fired; ev.missed: a run missed while the script was stopped, made up once at the start
onAlarm(ctx, alarm)An alarm comes, goes or is acknowledgedid, defId, path, state, priority, priorityLevel, text, ts, value, user (who acknowledged), area, alarmClass, level, description
onWhen(ctx, ev)A when condition has an edgeindex, name, edge, value, ts
onStop(ctx)The script is saved again, made inactive or the service stops properly— ; it may take at most the handler time limit and 5 seconds

ev.initial is true once for each signal after onStart, with the value from the last-value store or the first live value. Compare prev and cur only after it, to avoid false edges after a restart. onChange is not called when the same value arrives again (with on: "value").

At most 50 alarm events per second (200 in a burst) are delivered to a script and at most 256 wait; more are skipped and counted in Skipped. Keep the alarm filter narrow.

ctx​

MemberReturnsMeaning
ctx.value(path)Value or undefinedLast value of a signal; reading it also subscribes to it
ctx.quality(path)Text"good", "uncertain", "bad", "not_connected", "overflow", "substituted", or "unknown" when the signal is not available
ctx.ts(path)MillisecondsTime of the last change
ctx.setTag(path, value)—Writes a number, an on/off value or a text; see Writing. Throws an error when it is refused
ctx.log(...), ctx.warn(...), ctx.error(...)—Write to the script log; console.log / warn / error do the same
ctx.now()MillisecondsThe current time
ctx.state.get(key), ctx.state.set(key, value)ValuePersistent state of the script, kept across restarts; at most 1000 keys and 64 KB per value
ctx.lib(name)ObjectA shared library
ctx.dryRunOn/offTrue during a trial run, when nothing is written

A script writes at most 200 log lines per second.

Writing​

TargetRule
Internal memory signalAlways allowed
Signal of a driver (field point)Only with Can command field points on and the path matching one of the Command target patterns; within the Command rate limit (per minute). It is a command: written to the command log as script:<name> with the trigger (onChange:<path>, every, at, alarm:<path>, when, onStop) and the version
Signal point without a driverOnly with Can publish computed values on and the path matching one of the Publish target patterns: the value is published as the value of that point. Not a command, no command log
System.*, Alarms.*, Session.*, computed internal signalsRefused

Patterns use * (any sequence) and ? (one character), for example Line1.* or Boiler?.Sp.

The patterns decide which points a script may command: keep command targets as narrow as possible. Responsibility zones do not apply to scripts, and a script cannot write to the command point of an electrical device. A write that YTCC refuses before sending (permission, pattern, rate limit, electrical device) throws an error and counts in Rejected. ctx.setTag does not wait for the driver: a command that the driver refuses or that times out does not throw; it is in the command log.

Published values:

  • are converted to the data type of the point (an on/off point takes true, a non-zero number or the text "true" / "1"; integers are rounded and must fit; lists, objects and null are refused);
  • are sent at most 10 times per second per point; faster changes are merged and the last value always arrives;
  • have the quality of the script: when the script stops, fails to load or is quarantined, the points become Bad · Not connected within 6 seconds;
  • do not trigger the script's own onChange (no echo loop);
  • are limited to the number of tags plus 10 000 points per script.

If two scripts publish the same point, the last one wins; the editor warns about overlapping patterns.

defineLibrary​

defineLibrary("common", {
average(...xs: number[]) { return xs.reduce((a, b) => a + b, 0) / Math.max(1, xs.length); },
});

The first argument must be the name the library is saved under. A library has no process, permissions or log of its own: it runs in the script that uses it, with that script's permissions. Write the name as a fixed text in ctx.lib("common") so that YTCC knows which scripts to reload when the library changes.

Status signals​

Every script has the signals System.Scripts.<name>.*, usable on screens, in alarms and in the history:

SignalMeaning
Running, QuarantinedThe script is running; it is quarantined
VersionRunning version
Runs, ErrorsNumber of handler runs and errors
LastRun, LastErrorTime of the last run; text of the last error
AvgMsAverage run time
Commands, RejectedCommands sent; writes refused
PublishedValues actually published
SkippedTicks or alarm events skipped because the script was busy or a limit was reached

Limits​

LimitDefaultRangeWhen exceeded
Memory limit (MB)648–1024The script is stopped and restarted
Handler time limit (ms)100010–60000The call is cut off and counts as an error
Command rate limit (per minute)601–6000The command is refused

A script has no access to files, the network or other programs. If its process fails five times within five minutes, the script is quarantined: it waits, and a system alarm script_<name> with priority high is raised. Saving the script again ends the quarantine.