Tag Event Script In UDT with multiple tags & Dynamic Counter

I have a few tags that are part of a UDT. I’m trying to figure out where to use a tag event script and on which tag inside my UDT. The four tags are [.]Cfg_OnDly, [.]Cfg_OffDly, [.]Inp and [.]Out. My tag [.]Inp is a boolean expression tag that I turn on if outside conditions become true. The sequence would be this:

  1. When [.]Inp turns on/True then start counting up for the seconds specified by the memory tag [.]Cfg_OnDly. When the counter hits this 10 second mark, then set [.]Out to on/True.
  2. When [.]Inp turns off/False then start counting up for the seconds specified by the memory tag [.]Cfg_OffDly. When the counter hits this 10 second mark, then set [.]Out to off/False.

Would I do all of this in the ValueChanged tab of the Tag Event Script for the tag labelled [.]Inp?
If so, how do I reference the other three tags [.]Cfg_OnDly, [.]Cfg_OffDly, and [.]Out ?

The PLC’s providing the Input conditions are from a third party. We are not going in and editing their program. We also must match the customers windows and templates that use the Cfg_OnDly, Cfg_OffDly, Inp, Out.

Thank you in advance!

If you have the SQL Bridge Module, check out using a transaction group for this.

Hour and Event Meters - Transaction Group Items (inductiveuniversity.com)

1 Like

To answer this question, you can simply ref them using what youve written, e.g.

Expression:
{[.]Cfg_OnDly}

Script:
system.tag.readBlocking(['[.]Cfg_OnDly'])

Use ../ to go to parent folders
system.tag.readBlocking(['[.]../../Cfg_OnDly'])

As for the main question, I’m curious what @pturmel would suggest without using the sql bridge module.

1 Like

If the result must be robust through tag restarts or project save/restart, then a relatively permanent storage for the most recent transitions of [.]Inp is required, and the whole thing needs a state machine running in an timer event.

If transients on startup are OK, I’d just use my objectScript function to hold the event timestamps in its state dictionary, passed to a library function. Assume that looks like this:

# In gateway-scripting-project script.
# "MyScript", perhaps.
def onOffDelays(state, inp, onDly, offDly):
	now = system.date.now()
	if 'outp' not in state:
		state['outp'] = inp
		state['lastTS'] = now
	if inp != state['outp']
		threshold = system.date.addSeconds(state['lastTS'], onDly if inp else offDly)
		if now.after(threshold):
			state['outp'] = inp
			state['lastTS'] = now
	return state['outp']

Then you make an expression tag Out with the following:

objectScript("MyScript.onOffDelays(state, *args)",
    {[.]Inp}, {[.]Cfg_OnDly}, {[.]Cfg_OffDly})

The function passes Inp directly to Out on tag startup/restart. You can make that False if you prefer.

3 Likes

You may need to tweak that to handle interrupted cases better.

1 Like

So this concerned me pturmel especially since we are in a developement phase, so I decided to abandon the idea of a Tag Event Script or Gateway Event Script and investigated to see if there was a way I can simply use Expression Scripting to achieve the desired result. It worked. I left my UDT in tact but added another expression tag called [.]Out_Latch. Code:
if({[.]Inp}=1
&& secondsBetween({[.]Inp.Timestamp}, now(1000)) >= {[.]Cfg_OnDly},1,0)

Then back to my [.]Out expression tag. Code now looks like:
if({[.]Out_Latch}=1||
!{[.]Inp}&& secondsBetween({[.]Inp.Timestamp}, now(1000)) <= {[.]Cfg_OffDly},1,0)

This is useful if you want to add delays for alarming that you are not doing in a PLC. Unusual cases of course. I nest this “Gate” UDT into my Digital Input UDT. The desired result is if the Digital input does not match the Target state after the On delay setpoint then turn the output on and trigger desired alarm. Once you go into the condition and turn on an alarm, at some point the condition will clear.

In the case you were in alarm, then the digital input and the target state all of a sudden match, then reverse the process by counting up to the off delay. Then output will turn off and alarm will automatically clear.

If there seems to be concerns with this approach, by all means don’t hesitate to point them out. Thanks everyone!

Why not just use the alarm properties to delay the alarm?

Thanks @nminchin for pointing that out. Well normally yes that would be all that is needed if alarming was the only feature the customer was looking for on this condition. But they have alot of layers. They have configurable options to set the level of the alarm and whether or not to even make it an alarmable point. And in alot of cases where these input conditions do not require an alarm to be generated there is still a graphical feature they want working.

In the case that they do not want a certain mismatched state to trigger an alarm, they still want to monitor the actual input/state versus the expected state and have graphical references showing this mismatch.