Skip to content

Examples to copy

Six scripts that run as written. Each names its inputs and its trigger, so you can wire it up rather than only copy it.

Inputs: good → Press1.GoodParts, scrap → Press1.ScrapParts Trigger: tag change on both inputs

return inputs["good"] + inputs["scrap"]

That is a complete script. The return value is the tag’s value.

Inputs: length_mm → Press1.Length_mm Trigger: tag change

INCH = 25.4
def on_read():
return round(inputs["length_mm"] / INCH, 3)
def on_write(value):
system.tag.write("Press1.Length_mm", value * INCH)
return value

Because on_write is there, this tag is writable: setting the inch value really sets the millimetres on the machine.

Inputs: pressure → Press1.Setpoint_bar Trigger: tag change, with a settle time of 2 s so a value dancing around the limit does not produce a dozen alarms

LIMIT = 180.0
pressure = inputs["pressure"]
alarm = pressure > LIMIT
if alarm:
print("over limit:", pressure)
system.tag.write("Press1.Alarm_Pressure", alarm)
return pressure

The tag still reports the pressure; the alarm is a side effect in another tag. Keep that separation deliberately: a tag that sometimes holds a pressure and sometimes a boolean is a trap on every dashboard.

4. Work out the shift, on the plant’s clock

Section titled “4. Work out the shift, on the plant’s clock”

Inputs: none Trigger: cyclic, every 60 s

now = system.time.plant_now()
if 6 <= now.hour < 14:
return "A"
if 14 <= now.hour < 22:
return "B"
return "C"

system.time.plant_now() and not datetime.now(): datetime.now() gives you the time zone of the machine the script runs on — on a hosted instance, reliably UTC. The schedule, by contrast, fires on the clock the plant runs by. A script that works out the shift itself has to read the same clock as its trigger, or the shift boundary slips by the offset — and by another hour over daylight saving.

The plant’s zone is set once, on the instance. It is not in the script, which is exactly why nothing has to be tracked down when the plant moves to another time zone.

Parameters: line Trigger: manual or schedule

line = params["line"]
parts = system.tag.read("Plant." + line + ".PartCount")
target = system.tag.read("Plant." + line + ".Target")
if target == 0:
return 0.0
return round(100.0 * parts / target, 1)

Only do this when the path really is not known beforehand. When it is, bind it as an input — then TrakState knows about the dependency and warns you on a rename.

A script at the path Line1.Tools.Conversion with the library trigger:

INCH = 25.4
def mm_to_inch(mm):
return mm / INCH
def inch_to_mm(inch):
return inch * INCH

And a script that uses it:

from Line1.Tools.Conversion import mm_to_inch
return round(mm_to_inch(inputs["length_mm"]), 3)

The path is the module name. A library has no value of its own and never runs by itself; it is imported.

  1. Dry run. It computes everything but performs no write — you see the result and the requested writes without anything happening on the plant.
  2. Look at the run log. Your print() output is there, under the run.
  3. Check the Problems tab. An import that points at nothing is listed there as a hint.