# Cyclic increment value in a script

**URL:** <https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411>\
**Category:** Ignition\
**Created:** [April 13, 2023, 2:26pm UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411 "2023-04-13T14:26:57Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [April 13, 2023, 2:26pm UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/1 "2023-04-13T14:26:57Z")

</div>

I would like to increment a value every 1s.

Here's the script running on script console.

```auto
class tagType:
	#sets all initial values for the pid library
	def __init__ (self):
		self.i = 0
from time import sleep
newTag = tagType
newTag.i = 10
while True:
	print(newTag.i)
	newTag.i = newTag.i + 1
	sleep(1)

```

I placed it in Gateway Events, as timer events & 1,000ms.  
The above "print" script is replaced to write to a memory tag.

From the above script, the instance "newTag" is created every time the script is called, I thought when the above script is running in Gateway, the print value will remain at 10 because each time the script runs, the new instance will be created, but the value does increase every one second, "10,11,12,13,14.....".

I am a bit confused about how the gateway run the script. It seems that when the instance "newTag" is generated from the class, it retains the last scanned value when the new scan starts at 1second interval.

Then I tried to use the same script in a now(1000) tag, when the tag value changes every 1 second, It will execute the above script. Under this case, the value "newTag" remain at 10, as what I expected.

Now my question is: why the script result from the gateway 1 second timer event is different from the 1 second tag event?

Any comment is appreciated.

---

<div class="post-metadata">

**Author:** ![zacht](https://avatars.discourse-cdn.com/v4/letter/z/ea5d25/32.png) [@zacht](https://forum.inductiveautomation.com/u/zacht)\
**Post date:** [April 13, 2023, 2:50pm UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/2 "2023-04-13T14:50:07Z")

</div>

You're trying to do something every one second, but you're using two different tools to accomplish the repeating.

1. A gateway timer event script at 1000ms will run whatever code exists in its script every second.
2. The while loop in your script will run forever and execute its logic every 10 seconds.

In your gateway timer script, you've essentially established one infinite loop every second. I imagine this would have performance implications eventually. If each infinite loop is trying to write to a tag at roughly the same time, I would expect that to be racey and would consider the behavior to be undefined.

As general advice for Ignition projects, I recommend not:

1. using time.sleep() in any gateway script (there may be limited exceptions in perspective)
2. using unbreakable infinite loops

I would remove all of these from your gateway, restart the gateway (to clean up the threads that are probably still running these infinite loops), and write a script that doesn't use these patterns.

---

<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:** [April 13, 2023, 2:56pm UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/3 "2023-04-13T14:56:59Z")

</div>

Never sleep or use long-running loops in tag event scripts. Event scripts must complete quickly or they block the thread pool for other tags.

{ I would say "never use sleep() in Ignition", but there are rare reasonable uses. This isn't one of them. }

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [April 13, 2023, 10:42pm UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/4 "2023-04-13T22:42:43Z")

</div>

Thank you all for the comments.

Basically I would like to use ignition to achieve some PLC functions in a cyclic manner.

For some of the functions, I used tag "now(xxxx)" to trigger the functions in the value change script, the functions are nice and short, which I hope it won't affect the overall gateway performance.

For the other functions, because it will be instances derived from a "Class", which I cannot use the cyclic now"xxxx" tag to trigger the script, otherwise, as mentioned before, the newly created instance will overwrite the existing outcome from the previous cycle. Like the example code below.

So I thought about using the gateway timer function, which I never use before.  
It seems work as I want. But for sure if I have 10 cases for each project and with 10 projects running at the same time, the gateway performance will be down.

```auto
class tagType:
	#sets all initial values for the pid library
	def __init__ (self):
		self.i = 0
from time import sleep
newTag = tagType
newTag.i = 10
while True:
	print(newTag.i)
	newTag.i = newTag.i + 1
	sleep(1)

```

What's the better way to achieve the cyclic running function?

1. The script in "now(xxxx)" seems be working for short and nice calculation. I hasn't seen any gateway performance impact, for now.
2. For the above mentioned instance from class script, the gateway timer script is the only one I found it able to achieve my requirements.

Please advise your comments.

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [April 13, 2023, 11:02pm UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/5 "2023-04-13T23:02:46Z")

</div>

PID control is one function I would like to achieve in Ignition.

"simple-pid" is a python script I used.

In ignition exchange, there's a project utilizing the "simple-pid" to achieve the pid function, but it's using SFC to cyclic run the script.

I never use ignition SFC before.  
Is the SFC a better tool to manage the cyclic running script?

Or is ignition a platform to handle cyclic functions?  
What's the limit of cyclic script it can handle?  
How's the ignition gateway handling the timer script?

Ideally, there are maybe 200 instance of valves&pumps&instruments&switches in one project. I would like to cyclically run them in the script, same as the PLC FB. Then on top of it, there are timer&pid&totalizer blocks I would like to cyclically run in igniton as well, but it has more complicated logic involving instance from class and the values from the outcome of last cycle to be the input to the current cycle.

I would like to have a try, but maybe with all of the effort spent, at the end, ignition won't be able to handle it.

Any comment is appreciated.

---

<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:** [April 14, 2023, 1:10am UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/6 "2023-04-14T01:10:43Z")

</div>

**Don't use** `.sleep()` **!!!**  
**Don't use** `while True:` **!!!**

Just set a gateway project timer event to run at your desired pace, as if it were a PLC task. Have that single script call all of your cyclic functions. Use a project script module for the functions. Make sure the entire event runs straight through--the gateway timer takes care of running it repeatedly.

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [April 14, 2023, 2:15am UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/7 "2023-04-14T02:15:01Z")

</div>

wonderful.

Thank you for the advice.

I will have a try.

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [April 14, 2023, 2:48am UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/8 "2023-04-14T02:48:57Z")

</div>

Still a bit confused about my experiment mentioned before:

From the gateway script,  
the instance of the class is created every xx Second, but the outcome value is not overwritten every time the script is called.  
But from the tag timer script, it works as I expected.

1. Why the gateway timer script is different from the tag timer script?
2. Where is the gateway tag instance stored? in the gateway memory cache?

---

<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:** [April 14, 2023, 2:54am UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/9 "2023-04-14T02:54:49Z")

</div>

Your script doesn't make instances of `tagType` as `newTag`, it simply makes it a synonym for the class.

1. No clue. I haven't looked beyond the glaring problems.

2. Gateway memory tags are held in the java heap under the tag provider's hierarchy, with value backups in the gateway's internal database. But these are mere details that you should not be concerned with.

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [April 14, 2023, 3:51am UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/10 "2023-04-14T03:51:22Z")

</div>

I kind of find the issue.

When running it from the gateway, it looks like the gateway run this script only once, even though it is a 1second timer script.  
So the instance was created only once.

This is the gateway timer script, 1second.

```auto
class tagType:
	#sets all initial values for the pid library
	def __init__ (self):
		self.i = 0
from simple_pid import PID
pid = PID(15, 1, 0, setpoint=1.5)
pv = 1
logger = system.util.getLogger("myLogger")
logger.info(str(pv))
from time import sleep
while True:
	control = pid(pv)
	sleep(1)
	system.tag.writeAsync("[default]ctrlPID/outCV", control)

```

I got the following log:

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/2/d/2d1bc92409b08d3b33757b11c7ac75d23bc138d2.png)  
And I have the PID loop CV value updating every one second.

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [April 14, 2023, 3:58am UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/11 "2023-04-14T03:58:24Z")

</div>

Looking through this post,

Actually my main problem is not able the cyclic loop, but more about the instance of the defined class.

In this PID controller issue, I want to create an instance of the PID class, then I want to execute its PID calculation every couple of seconds.

I don't see a way to create a tag as the instance of defined class. But this instance has to be stored in the running project/gateway in some certain form so I can retrieve the values everything I want to run its function.

Maybe my question should be:  
How do I create an instance of a defined class and store the data somewhere in the project? So I can run its function whenever I want, either in a cyclic loop or by some event trigger.

Or is there any way I can store the object of the defined class as a ignition global variable, so it can be used at any time?

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [April 14, 2023, 7:32am UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/12 "2023-04-14T07:32:31Z")

</div>

Remove. The. Loop.

What do you think is going to happen when the loop is reached ?  
Here's a rundown:

- second 0: Script starts. Loop is entered. sleep for 1 second, repeat forever.
- second 1: New script starts. Loop is entered. sleep for 1 second, repeat forever.
- second 2: New script starts. Loop is entered. sleep for 1 second, repeat forever.
- second 3: New script starts. Loop is entered. sleep for 1 second, repeat forever.
- second 4: New script starts. Loop is entered. sleep for 1 second, repeat forever.
- second 5: New script starts. Loop is entered. sleep for 1 second, repeat forever.

6 seconds in, you already have 6 infinite loops running. And it's not going to stop.

Let's try and make it clear:  
The gateway timer event IS the loop. If you set a timer event to run every 1 second, it WILL RUN every 1 second. You don't need to add your own loop inside.

That's a script that runs ONCE and loops FOREVER, calling a function every second:

```python
while True:
    do_something()
    sleep(1)

```

Here's a TIMER script that will be run every x second (set up in the GUI) and call a function every time:

```auto
do_something()

```

That's it.  
Do not use `sleep`. Do not use `While True` without a break condition.  
And ESPECIALLY do not do these things in a timer script.

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [April 14, 2023, 10:03am UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/13 "2023-04-14T10:03:20Z")

</div>

Thanks for the comments. You made the point.

The previously posted script was drafted in a script console to test the class object function and then pasted in the gateway timer script to try out the simple-pid library. It was poorly structured.

I thought the same when I started the gateway script, as per the code, there should be a new script starting every one second, because the previous script will never complete.

But when I checked the gateway "Current running script" status page, there's only one script running, I thought maybe the gateway list only one instance of the duplicated script. But because I write a flag log in the script, if there's duplicated scripts running, there should be one new log every one second. But from the gateway log, there's only one log only.

So I was kind of confused, maybe Ignition is doing something smart to run only one script to prevent the memory from overflowing?

```auto
logger = system.util.getLogger("myLogger")
logger.info(str(pv))

```

I used the gateway script only a handful of times over the years and I had poor experience when using it. For example, in the gateway script, I will always write log to keep track of the running script status. But for quite a few times I found the script was not listed in the current running script page, but the log keep on updating with new status log, which means there's a script running at the backend but not captured by the gateway, the only way to stop it is to restart the gateway.

Anyway, the gateway cyclic script is not the show stopper to my current case.  
My real problem is how to create object from class, store the object in gateway or running project, then run the object function.  
I have started a new post about it, but since this post attracted more attention, maybe we can continue the discussion in this post. 😀

> [@Creation of Instance Object](https://forum.inductiveautomation.com/t/creation-of-instance-object/72444):
>
> Hi, This is the script I tried to make use of the "simple-pid" python library to build a PID controller in Ignition. There are two sections: import the library and create a object. from simple\_pid import PID pid = PID(15, 1, 0, setpoint=1.5) inPV = 1 cyclically run the object, and assign the outcome to a tag. outCV = pid(inPV) system.tag.writeAsync("[default]ctrlPID/outCV", outCV) How do I set it up in Ignition to get it working? The object should be created only once, but the function…

---

<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:** [April 14, 2023, 11:27am UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/14 "2023-04-14T11:27:40Z")

</div>

> [@chaoliang](#):
>
> maybe Ignition is doing something smart to run only one script to prevent the memory from overflowing?

Yes. Contrary to @pascal.fragnoud's suggestion, an event that doesn't **return** will be prevented from running again. Event scripts are effectively "critical sections" that will not run in parallel with themselves. (They **can** run in parallel with other scripts and events.)

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [April 14, 2023, 12:30pm UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/15 "2023-04-14T12:30:42Z")

</div>

Eh, I didn't know that. Makes sense though.

Let's take a script on a 1 second timer:  
Will the next execution run 1 second after the previous one completes ?  
Imagine it takes 1.5 seconds to complete, will the next one be 1 seconds afterward, or 0.5 seconds ?

I guess I'm asking if it's a 'fixed' timer, checking every second if it should run, or if the end of an execution triggers a scheduling of the next.

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [April 14, 2023, 12:36pm UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/16 "2023-04-14T12:36:10Z")

</div>

From what I tested, the first script will continue, as I saw the PID CV kept on changing until it reaches 100% or 0%.

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [April 14, 2023, 12:43pm UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/17 "2023-04-14T12:43:49Z")

</div>

Just tested again a new gateway script, same issue happened again.  
The timer script is running, because the log kept on updating, but there's no running script listed in the log page.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/c/b/cbcd685c0a14c206fed8bda93d223ae4923b0abe.png)  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/6/a/6a40980b4b751273fcc87d75e762e9e35c5d2ee0.png)  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/e/b/eb20979c4b0230fd60d6dc304ed3a290a50520c3.png)  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/d/8/d8c9dc965718dc6faa849a921171605599079250.png)

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [April 14, 2023, 12:58pm UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/18 "2023-04-14T12:58:13Z")

</div>

> [@chaoliang](#):
>
> The timer script is running, because the log kept on updating, but there's no running script listed in the log page.

Yes, because it executes very fast. You'll get one script that executes almost instantly every second.  
It's not just a script that keeps on running.

Why do you call that an issue ?

---

<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:** [April 14, 2023, 2:43pm UTC](https://forum.inductiveautomation.com/t/cyclic-increment-value-in-a-script/72411/19 "2023-04-14T14:43:50Z")

</div>

> [@chaoliang](#):
>
> no running script listed in the log page

That is a good thing. The point of the "running scripts" page is to find the scripts that are _ **misbehaving** _ by not finishing quickly.
