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.
1. Add two values
Section titled “1. Add two values”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.
2. Convert a unit, both ways
Section titled “2. Convert a unit, both ways”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 valueBecause on_write is there, this tag is writable: setting the inch value really sets
the millimetres on the machine.
3. Watch a limit and raise an alarm
Section titled “3. Watch a limit and raise an alarm”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 pressureThe 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.
5. Build a path only known at run time
Section titled “5. Build a path only known at run time”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.
6. Use a library of your own
Section titled “6. Use a library of your own”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 * INCHAnd 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.
Before you arm it
Section titled “Before you arm it”- Dry run. It computes everything but performs no write — you see the result and the requested writes without anything happening on the plant.
- Look at the run log. Your
print()output is there, under the run. - Check the Problems tab. An import that points at nothing is listed there as a hint.