# Tag change vs timed scripts

**URL:** <https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651>\
**Category:** Ignition\
**Created:** [March 27, 2023, 3:26pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651 "2023-03-27T15:26:32Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![gregory.sachs](https://avatars.discourse-cdn.com/v4/letter/g/e47774/32.png) [@gregory.sachs](https://forum.inductiveautomation.com/u/gregory.sachs)\
**Post date:** [March 27, 2023, 3:26pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/1 "2023-03-27T15:26:32Z")

</div>

General question: I'm at the point where I loathe tag change event scripts, because if the script engine is restarted events get missed. I tend to use timed scripts instead, with a single read tag/check value if on it to gate the response. In theory, a tag change script should react faster and/or give less overhead than a script being called all the time. Is that noticeable?  
Is there a good way to capture the "If tag goes high OR script engine starts and tag already High"?  
I think for proper gating using a boolean tag it needs to be something like this:  
if (newValue.getValue()) or (initialChange and (newValue.getValue())):

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 27, 2023, 3:37pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/2 "2023-03-27T15:37:44Z")

</div>

You should check the `initialChange` flag before doing anything else. If critical, use that condition to check state that survives scripting restarts to determine the real previous value. Some candidates for such state:

- A memory tag. Such would be written by the normal code whenever state changes (but not normally read). When `initialChange` is true, read it instead of `previousValue`.

- Tag history. If you are historizing the tag, read its last value from the historian before proceeding.

- A python global dictionary, like `system.util.getGlobals()` or my `system.util.persistent()`. (The latter doesn't have any legacy conflicts and works the same in all Ignition versions.)

---

<div class="post-metadata">

**Author:** ![gregory.sachs](https://avatars.discourse-cdn.com/v4/letter/g/e47774/32.png) [@gregory.sachs](https://forum.inductiveautomation.com/u/gregory.sachs)\
**Post date:** [March 27, 2023, 4:35pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/3 "2023-03-27T16:35:18Z")

</div>

So if using a boolean tag this should work:

```auto
value=False
if initialChange:
	value=event.getCurrentValue()
if (newValue.getValue()) or value):

```

I want to 'catch' the case where the script starts with the tag already True.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 27, 2023, 5:29pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/4 "2023-03-27T17:29:32Z")

</div>

That doesn't do what you think.

---

<div class="post-metadata">

**Author:** ![gregory.sachs](https://avatars.discourse-cdn.com/v4/letter/g/e47774/32.png) [@gregory.sachs](https://forum.inductiveautomation.com/u/gregory.sachs)\
**Post date:** [March 27, 2023, 5:45pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/5 "2023-03-27T17:45:51Z")

</div>

Can you give me an example that does work?  
Thanks!

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 27, 2023, 5:51pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/6 "2023-03-27T17:51:18Z")

</div>

What do you want to happen when `initialChange` is true? Ignore currentValue? (That would be typical in a stateless situation.)

---

<div class="post-metadata">

**Author:** ![gregory.sachs](https://avatars.discourse-cdn.com/v4/letter/g/e47774/32.png) [@gregory.sachs](https://forum.inductiveautomation.com/u/gregory.sachs)\
**Post date:** [March 27, 2023, 6:22pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/7 "2023-03-27T18:22:48Z")

</div>

Failure mode I encounter is that I miss the Tag going high, which leaves the system in a bad state. So my failure mode is my trigger tag stays high.  
If my tag is low and I start the script, no issues.  
my thought was that if initialchange was true, use the current value(1 in failure mode), then execute the script.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 27, 2023, 6:26pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/8 "2023-03-27T18:26:18Z")

</div>

So, just check the current value. At worst, it'll double fire the logic, but that sounds OK for your case.

```auto
if currentValue.value:
    ... do something ...

```

---

<div class="post-metadata">

**Author:** ![gregory.sachs](https://avatars.discourse-cdn.com/v4/letter/g/e47774/32.png) [@gregory.sachs](https://forum.inductiveautomation.com/u/gregory.sachs)\
**Post date:** [March 27, 2023, 6:50pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/9 "2023-03-27T18:50:37Z")

</div>

Don't I still need initialValue check for the condition where the tag is high and scripts restart?  
I'm sorry, getting confused here.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 27, 2023, 7:00pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/10 "2023-03-27T19:00:04Z")

</div>

There are four possibilities:

- Tag is low with initialChange true

- Tag is high with initialChange true

- Tag is low with initialChange false

- Tag is high with initialChange false

When initialChange is true, you do not know the previous value (unless you use an alternate source of state, as mentioned above). Your logic can be arranged to underfire (not run at all in some cases) or overfire (run twice in the opposite cases).

You need to pick which stateless failure mode is more appropriate for your situation. If you cannot tolerate either of those two failure modes, you **must** record state elsewhere, to be recovered when initialChange is true.

---

<div class="post-metadata">

**Author:** ![jlandwerlen](https://avatars.discourse-cdn.com/v4/letter/j/bc8723/32.png) [@jlandwerlen](https://forum.inductiveautomation.com/u/jlandwerlen)\
**Post date:** [March 27, 2023, 7:09pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/11 "2023-03-27T19:09:57Z")

</div>

> [@gregory.sachs](#):
>
> Failure mode I encounter is that I miss the Tag going high, which leaves the system in a bad state.

IMO this is why using a counter is much better than using digital.

---

<div class="post-metadata">

**Author:** ![gregory.sachs](https://avatars.discourse-cdn.com/v4/letter/g/e47774/32.png) [@gregory.sachs](https://forum.inductiveautomation.com/u/gregory.sachs)\
**Post date:** [March 27, 2023, 8:10pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/12 "2023-03-27T20:10:21Z")

</div>

Yeah, no argument. The original coder liked putting a boolean on a transaction group result and using a tag change off that bool to trigger other tag writes. I'm just trying to get it reliable without redoing the whole thing.  
Original state was if (newValue.getValue());  
That can fail in the state where value is true.  
I'm tempted to just make it a timer script instead, as being much simpler...

---

<div class="post-metadata">

**Author:** ![gregory.sachs](https://avatars.discourse-cdn.com/v4/letter/g/e47774/32.png) [@gregory.sachs](https://forum.inductiveautomation.com/u/gregory.sachs)\
**Post date:** [March 27, 2023, 8:12pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/13 "2023-03-27T20:12:51Z")

</div>

This comes back to the question I was hinting around;  
What is overhead of a 1 second timer that reads a tag and exits, vs a tag change script?  
The timer script seems much easier to handle in terms of if a do b, without any potential to miss events...

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [March 27, 2023, 8:15pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/14 "2023-03-27T20:15:05Z")

</div>

> [@gregory.sachs](#):
>
> The timer script seems much easier to handle in terms of if a do b, without any potential to miss events...

What's your obsession with missing events? Are you sure this is actually happening? It's pretty uncommon, and I'm not sure what you mean about script engine restarts being the cause.

P.S. a timer script is more likely to miss something. If your tag goes 0 -\> 1 -\> 0 you can easily imagine your timer script missing the 1.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 27, 2023, 8:18pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/15 "2023-03-27T20:18:33Z")

</div>

> [@gregory.sachs](#):
>
> without any potential to miss events...

Why do you say this? How does a 1-second timer know that the true value it is looking at is a rising edge versus a continuing value? You need prior state. A tag change script gives you that prior state except when restarting. A timer script has to maintain that state itself. Both events must deal with scripting restarts.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 27, 2023, 8:28pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/16 "2023-03-27T20:28:50Z")

</div>

> [@gregory.sachs](#):
>
> The original coder liked putting a boolean on a transaction group result and using a tag change off that bool to trigger other tag writes.

Oy! Ugly and unreliable.

Handshaking for reliability generally means replacing the transaction group in its entirety with proper scripted equivalent, with one-way writes in the right places in the handshake.

---

<div class="post-metadata">

**Author:** ![gregory.sachs](https://avatars.discourse-cdn.com/v4/letter/g/e47774/32.png) [@gregory.sachs](https://forum.inductiveautomation.com/u/gregory.sachs)\
**Post date:** [March 27, 2023, 8:40pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/17 "2023-03-27T20:40:08Z")

</div>

ok, fair question;. I'm not so much concerned with missing events as 'System left in state where it needs to be debugged.'. The appearance right now is that sometimes the tag change script does not fire; leaving the equipment in an unstable state(bad design of the data transactions!)  
The event itself is a "slow" event, probably only happens on the order of every 30 seconds or so.  
Basic design is that the log transaction fires, then tag is set high by the transaction and that runs the tag change script, which does a db query and then sleeps for 0.5 seconds before writing some tags. I suspect that the real problem is the sleep leaves it vulnerable to interruption.

After the sleep, tags get written and the handshake bit gets set to zero.  
The design seems to be to write tags to confirm that values were stored in the database.

I think a more stable system would be to use a timed script that sees if the group Ok handshake is 1, then can execute with the sleep condition. If it gets interrupted before the handshake is written back to zero, it will just run again.

```auto
from time import sleep
logger = system.util.getLogger("myLogger")
if (newValue.getValue()):
	barcode = system.tag.read("Damper/Station 20 Weld/LOG/LOG_CODE")
	logger.info("Station 20:Verify Log Script Triggered, Barcode=" + barcode.value)
	query = "SELECT [BARCODE],[WELD_OK],[WELD_NG],[WELD_PROGRAM] From [DAMPERS] where [BARCODE] = '" + barcode.value + "'"
	result = system.db.runPrepQuery(query)
	rows = result.getRowCount()
	columns = result.getColumnCount()
	sleep(.5)
	if (rows != 0):
		weldOK = result.getValueAt(0,"WELD_OK")
		weldNG = result.getValueAt(0,"WELD_NG")
		weldPR = result.getValueAt(0,"WELD_PROGRAM")
		if (weldOK is None) or (weldNG is None) or (weldPR is None):
			system.tag.write("Damper/Station 20 Weld/LOG/LOG_NG",1)
		elif ((weldOK or weldNG) & (weldPR > 0)):
			system.tag.write("Damper/Station 20 Weld/LOG/LOG_OK",1)
		else:
			system.tag.write("Damper/Station 20 Weld/LOG/LOG_NG",1)
	else:
		#logger.info("Barcode Not Found")
		system.tag.write("Damper/Station 20 Weld/LOG/LOG_NG",1)
	system.tag.write("Damper/Station 20 Weld/LOG/LOG_CHECK",0)
	system.tag.write("Damper/Station 20 Weld/LOG/WELD_COMPLETE",0)

```

The LOG\_CHECK tag is the tag that triggers the script.  
If I instead do a simple

```auto
enable=system.tag.read("log_check")
if enable:
   blah blah blah
   system.tag.write(log_check,0)

```

Then I think I can never get "stuck" in the condition where the tag is 1.  
Could also do a age of timestamp instead of the sleep; but not sure that adds any value;  
I am leery of adding overhead, though, which is the only reason I don't immediately do a timed script.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 27, 2023, 8:43pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/18 "2023-03-27T20:43:34Z")

</div>

> [@gregory.sachs](#):
>
> ```auto
> result = system.db.runPrepQuery(query)
> rows = result.getRowCount()
> columns = result.getColumnCount()
> sleep(.5)
> if (rows != 0):
> weldOK = result.getValueAt(0,"WELD_OK")
> weldNG = result.getValueAt(0,"WELD_NG")
> weldPR = result.getValueAt(0,"WELD_PROGRAM")
> 
> ```

This `.sleep()` does nothing for the booleans you are retrieving, as they are already static in the result dataset.

{ Tip: If you are using any form of `.sleep()` or busy-looping, in a system like Ignition, you've already screwed up. }

---

<div class="post-metadata">

**Author:** ![gregory.sachs](https://avatars.discourse-cdn.com/v4/letter/g/e47774/32.png) [@gregory.sachs](https://forum.inductiveautomation.com/u/gregory.sachs)\
**Post date:** [March 27, 2023, 8:48pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/19 "2023-03-27T20:48:21Z")

</div>

Yeah, completely agree about the sleep being completely useless. It might have made sense before the query, but even then this event is triggered by a log to the db, which the query is checking.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 27, 2023, 8:57pm UTC](https://forum.inductiveautomation.com/t/tag-change-vs-timed-scripts/71651/20 "2023-03-27T20:57:27Z")

</div>

It seems to me that everything that needs to happen in sequence should be in a single script, relying on only the natural delays of query execution and tag operations.
