Resolving Ignition Perspective Timed Tag Reset from a Button

Stefan Weidner7 min read
HMI / SCADAOther ManufacturerTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Where does a Perspective button script actually run?

Follow the packet. The click happens in the browser, but the browser does not run the script. The event travels over the session connection to the Ignition gateway. The gateway executes the Jython script in gateway scope, and the resulting writes go to the tag provider and from there to the device.

Hop What happens Where failures show
Browser Mouse event captured, sent to gateway session Browser dev-tools console (system.perspective.print output)
Gateway session Script executes in gateway scope Gateway logs (script exceptions)
Tag provider [Ignition_IO_01_NE_KRASNOPOL] Write to NE_KRASNOPOL/LV_On Quality code returned by system.tag.writeBlocking
Device / driver Value lands in the controller Tag quality, driver diagnostics

The failing line is system.util.invokeLater(...). That function exists only in Vision client scope. It is not defined in gateway or Perspective scope, so the call raises an attribute error the moment the script reaches it. The first writeBlocking has already executed and LV_On is True. The exception aborts the rest of the script, and nothing is left to schedule the False write. The tag stays latched.

Check 1: Did the "Reset tag" print ever appear?

Open the browser developer console for the session, or the Designer output console if you test in the Designer, and click the button once.

Console output Meaning Next check
"Start script:", "Set path", "Set tag" only Script died at invokeLater Confirm the exception in the gateway logs, then go to Check 3
No output at all Event not bound or script not firing Verify the event is on the button's mouse/click event and the view is saved and published
All four lines including "Reset tag" Scheduling call did not throw; delayed write failed elsewhere Check 2

In the gateway web interface, open the logs under Status > Diagnostics > Logs and filter on the Perspective or script logger. The stack trace names the missing invokeLater attribute. That confirms the branch.

Check 2: Does the write itself reach the tag with good quality?

Layer one first. Before debugging the timing, prove the path from gateway to device carries writes. system.tag.writeBlocking returns a list of quality codes, and the script above discards it. Capture and print it:

results = system.tag.writeBlocking([tagPath], [True])
system.perspective.print(str(results[0]))
Returned quality Meaning Action
Good Provider accepted the write Timing is the only problem; go to Check 3
Bad / not found Tag path or provider name wrong Copy the path from the Tag Browser with right-click > Copy Path
Bad / access denied or read-only Security or tag configuration blocks writes Check tag security and the tag's read-only setting
Bad / comm error Driver or device connection down Fix the device connection before touching scripts

If LV_On goes True but never returns to False, the write path works. The defect is the timer.

Check 3: Which delay mechanism fits the gateway scope?

A Perspective event script should return fast. It runs on a gateway thread tied to the session. Anything that waits inside it either blocks that thread or depends on a thread that can die with the session, a project save, or a gateway restart.

Mechanism Available in Perspective scope Survives page close Survives project save / gateway restart Verdict
system.util.invokeLater No (Vision only) n/a n/a Throws; root cause here
time.sleep inline in the event Yes Uncertain No Blocks the session thread; avoid
system.util.invokeAsynchronous + sleep Yes Usually No; pending reset is lost Works in testing, fails in the field
Deadline memory tag + gateway timer event Yes Yes Yes; deadline stored in a tag Reliable; recommended
Timer (TON/pulse) in the controller n/a, HMI writes a trigger only Yes Yes, independent of Ignition Preferred when the output drives equipment

The reliable pattern stores the turn-off time as data, not as a pending thread. A memory tag holds the future deadline. A gateway timer event runs continuously, compares the current time to the deadline, and writes False when the deadline has passed. If the gateway restarts mid-pulse, the timer picks up the stored deadline on the next execution and still turns the output off.

If LV_On switches real equipment, put the 5 s timer in the controller and let the button write a start bit. The pulse then does not depend on the SCADA gateway staying up.

How do you build the deadline tag and timer event?

  1. Create a memory tag of type DateTime to hold the turn-off time. The example path below uses a placeholder, [yourProvider]NE_KRASNOPOL/LV_On_OffTime; substitute your own provider and name.
  2. Replace the button's mouse event script. Write the deadline first, then the output. That ordering prevents the timer from seeing True next to a stale past deadline and dropping the output immediately.
    lvPath      = "[Ignition_IO_01_NE_KRASNOPOL]NE_KRASNOPOL/LV_On"
    offTimePath = "[yourProvider]NE_KRASNOPOL/LV_On_OffTime"   # placeholder
    
    deadline = system.date.addMillis(system.date.now(), 5000)
    q1 = system.tag.writeBlocking([offTimePath], [deadline])
    q2 = system.tag.writeBlocking([lvPath], [True])
    system.perspective.print("deadline=%s q=%s/%s" % (deadline, q1[0], q2[0]))
  3. In the Designer, open the project's Gateway Events, add a Timer script, and set its delay. The delay is your precision: the output drops between 5 s and 5 s plus one timer period after the click.
  4. Paste the check logic into the timer script:
    lvPath      = "[Ignition_IO_01_NE_KRASNOPOL]NE_KRASNOPOL/LV_On"
    offTimePath = "[yourProvider]NE_KRASNOPOL/LV_On_OffTime"   # placeholder
    
    lv, offT = system.tag.readBlocking([lvPath, offTimePath])
    if lv.quality.isGood() and offT.quality.isGood():
        if lv.value and offT.value is not None:
            if system.date.now() >= offT.value:
                system.tag.writeBlocking([lvPath], [False])
  5. Save and publish the project. Gateway event scripts run only while the project is enabled on the gateway.

Recurring pitfalls with this pattern:

  • Double execution: if the same timer script exists in more than one running project, each copy runs. That is harmless for an idempotent False write, but it wastes cycles. Keep it in one project.
  • Retrigger behavior: a second click inside the window pushes the deadline out another 5 s. If you need a fixed pulse that ignores re-clicks, have the button skip the write while LV_On is already True.
  • Manual override: an operator who sets LV_On to True from elsewhere, while an old deadline is in the past, gets turned off on the next timer execution. Clear or refresh the deadline wherever else the tag is written.
  • Clock skew: the deadline and the comparison both use gateway time through system.date.now() in gateway scope, so browser clock drift does not matter. Do not compute the deadline client-side.

How do you verify the reset end to end?

  1. Open the Tag Browser with LV_On and the deadline tag visible, then click the button in a live session.
  2. Confirm the browser console shows the deadline and two good write qualities.
  3. Watch LV_On go True and the deadline tag show a timestamp 5 s ahead of the gateway time.
  4. Confirm LV_On returns to False within 5 s plus one timer period. Check the gateway logs for timer-script exceptions if it does not.
  5. Click the button, close the browser tab immediately, and confirm the tag still drops on schedule. This proves the reset does not depend on the session.
  6. Read the value at the device through the driver diagnostics or the controller's online view. Confirm the controller saw both the rising and the falling edge. A pulse visible only in Ignition has not been proven at the output.

FAQ

Why does system.util.invokeLater not work in Ignition Perspective?

invokeLater is a Vision-only function tied to the Vision client's UI thread. Perspective scripts execute in gateway scope, where that function does not exist, so the call throws and the script aborts.

Why does my Perspective button set the tag true but never reset it?

The first writeBlocking completes, then the next line raises an exception, so no reset is ever scheduled. Check the gateway logs for the stack trace, and see whether the prints after the failing line ever reach the browser console.

Why does the tag turn off immediately instead of after 5 seconds?

The timer event read True alongside an old deadline that was already in the past. Write the new deadline before writing the output, and refresh the deadline anywhere else the output tag gets set.

Why does a sleep in invokeAsynchronous lose the reset sometimes?

The pending reset lives only in a gateway thread. A project save or gateway restart kills that thread before it wakes up. Storing the deadline in a memory tag and checking it from a gateway timer event survives both, and the reset error is bounded by one timer period.

Back to blog