Gateway Timer Events vs. Threading?

Hi all,

So having been a little let down by the behavior of Gateway Events in V8.0:

And lacking a solution for a few weeks I reverted to the following solution to get the 'trigger' property on a Sound Player to toggle on and off: I basically spawn a thread with an enclosed sleep timer, which on initiation sets a property on the SoundPlayer and on conclusion resets it. I have a propertyChanged script which tracks changes in numbers of alarms, as well as the current state of the thread which times out the alarm.

It works as well as the old gateway timer did, and given the divergences (in my opinion) between how Gateway Events work now and how the 8.0 manual says they ought, I'd prefer to leave my solution in place, since I 100% understand how it works and I control how or if its behavior changes. I'm really only looking for serious concerns about possible mismanagement of memory or other resources. This is the first time I've mucked around with threads in Python, and I haven't much experience with them in other languages either. So I can very easily see myself setting up another issue down the road.

Apologies for the unPythonic Grammar and the probably needlessly long code:

import time
from threading import Thread

def sleepFunc(secs,triggerState):
        #This function waits, then sets two Sound Player properties
	time.sleep(secs)
	event.source.trigger = triggerState
	event.source.ThreadClear = True

if event.propertyName == 'AlarmTotal':
       #if there are Alarms, turn on RingToggle and set the Sound Player on.
       #if there aren't, turn off RingToggle and trigger on the Sound Player
	if event.newValue != 0:
		event.source.RingToggle = True
	else:
		event.source.RingToggle = False
    event.source.trigger = bool(event.source.AlarmTotal)

elif (event.propertyName == 'trigger') or (event.propertyName == 'ThreadClear'):
        #Once 'Ring Toggle' is on the player will cycle 'trigger' on and off till it is removed
        #Each cycle will be spawned as a thread, and a new one will not start till the old one
        #concludes.
	if event.source.ThreadClear:
		event.source.ThreadClear = False
		if ( (event.source.AlarmTotal != 0) and (event.source.trigger) ):
			alarmThread = Thread(target = sleepfunc, args = (0.25,False) )
			alarmThread.start()
		elif ( (event.source.AlarmTotal != 0) and (not event.source.trigger) ):
			alarmThread = Thread(target = sleepfunc, args = (1.75,True) )
			alarmThread.start()
        if event.source.AlarmTotal = 0:
            event.source.trigger = False

There’s nothing wrong with using java threads from jython in Ignition, as long as you take care to destroy and recreate them upon script module edits, and take care to only create the number of threads desired.

If the thread will run indefinitely, you need some form of object tracking in the persistent dictionary from system.util.getGlobals(). But:

Since gateway event script behavior hasn’t changed in v8 other than the addition of inheritance, and you had working scripts in v7.9, you probably don’t need to do any this. (Go back and look at Kevin’s comment about how you messed up your global project.)

Thanks Phil,

Again, there’s nothing I did to the global project; I neither created it, nor assigned it inheritors, nor gave my gateway events to it. to be run simultaneously by all inheritors. The behavior may be standard, but it was a shift from the behavior in the previous version, one that if it was flagged I didn’t notice it. It also doesn’t seem to be documented in the current 8.0 manual discussion of how gateway events function.

While I’m aware of how to detangle my gateway events from my client events now, under the new 8.0 rubric, I’m leery of such changes to how things work coming through on future updates, and I’d prefer in that case to keep any unexpected behavior due to bugs in my own, self-maintained code. This was a minor issue, but it was a minor issue in our plant’s alarming project, and that’s a larger cause for concern.

I believe my current code, which only permits a thread to be created if the prior thread has terminated successfully (swapping the ThreadComplete flag on the component as last command) should limit myself to one thread at a time. Again I was concerned about committing some obvious ‘newb’ error that would eventually crash my gateway, but it sounds like we should be fine. There’s no indication that memory useage on the gateway has been anything but pancake flat for the last several days. More granular analysis, for windows 10 at least, seems to require installation of a program called ‘process explorer’. I’d like to keep the gateway as bare of extraneous software as possible however.

I don't know if you're aware, but this app is only a few kB :grin: it's also designed as a portable app, so no need to install